// HDT11湿度センサーのテスト // タイマー1のICP1(PB0)を使って // PB0 ICP1 (14pin) // ポート出力 H/L,out/inp 入力 #define HDT_H (PORTB |= (1 << PB0)) // 14pin #define HDT_L (PORTB &= ~(1 << PB0)) #define HDT_OUT (DDRB |= (1 << DDB0)) // 出力に #define HDT_INP (DDRB &= ~(1 << DDB0)) // 入力に #define INP_HDT (PINB & (1 << PB0)) // 入力H/Lチェック // タイマー1 #define CHK_ICF1 (TIFR1 & (1 << ICF1)) // ICP1有無チェック #define CLR_ICF1 (TIFR1 = (1 << ICF1)) // ICF1クリア #define ICP1_UP (TCCR1B |= (1 << ICES1)) // ICP1↑エッジに #define ICP1_DN (TCCR1B &= ~(1 << ICES1)) // ICP1↓エッジに #define CHK_TOV1 (TIFR1 & (1 << TOV1)) // オーバーフロー有無チェック #define CLR_TOV1 (TIFR1 = (1 << TOV1)) // オーバーフロークリア // Port出力 #define PB1_H (PORTB |= (1 << PB1)) // 15pin #define PB1_L (PORTB &= ~(1 << PB1)) #define PD3_H (PORTD |= (1 << PD3)) // 5pin #define PD3_L (PORTD &= ~(1 << PD3)) #define LED_ON (PORTB |= (1 << PB5)) // LED #define LED_OFF (PORTB &= ~(1 << PB5)) /*****************************/ /* タイマー処理 */ /*****************************/ /***** タイマーデータ *****/ volatile byte f_1ms; // 1msフラグ volatile byte tm_1ms; // 1msダウンカウントタイマー volatile byte f_10ms; // 10msフラグ volatile byte tm_10ms; // 10msダウンカウントタイマー volatile byte f_1sec; // 1秒フラグ /***** タイマー2 コンペアマッチA割込み *****/ // 1kHz周期で割り込み ISR(TIMER2_COMPA_vect) { static byte cnt10 = 0; static byte cnt1sec = 0; PB1_H; // (!!!) f_1ms = 1; // 1msフラグ if(tm_1ms) tm_1ms--; // 1msダウンカウント // 10msタイマー cnt10++; if(cnt10 >= 10){ // 10ms経過 cnt10 = 0; f_10ms = 1; // 10msフラグ if(tm_10ms) tm_10ms--; // 10mS ダウンカウント // 1秒タイマー cnt1sec++; if(cnt1sec >= 100){ // (!!!) cnt1sec = 0; f_1sec = 1; // 1秒フラグ } } PB1_L; // (!!!) } /******************************/ /* 書式付シリアル出力 */ /******************************/ // クラスPrintへのポインタ Print *Cp; // クラスPrintへの関数ポインタ // Cp = &Serial; や &LCDなど /***** Printクラスへの書式付シリアル出力 *****/ // PSTR("")で書式を指定 void CpPrintf_P(const char *s, ...) { va_list vp; char bff[64]; // バッファを確保 va_start(vp, s); vsnprintf_P(bff, sizeof(bff), s, vp); // PSTRで書式を指定 Cp->print(bff); // cpへ出力 va_end(vp); } /***** 文字出力 *****/ void CpPuts_P(const char *s) { char c; while(1){ c = pgm_read_byte(s); if(c == '\x0') break; Cp->write(c); s++; } } /******************************/ /* HDT11処理 */ /******************************/ /***** HDT11 データ *****/ volatile word hdt_data[5]; // 検出データ byte hdt_exc; // HDT11読み出し実行区分 byte f_hdt_ok; // HDT11読み出し完了フラグ // 0:まだ 1:OK, 2:エラー byte f_hdt_run; // HDT読み出し実行フラグ // 1なら周期的に実行 /***** スタンバイ *****/ void hdtstby(void) { if((f_1sec != 0) && // 1秒ごとに (f_hdt_run != 0)){ // 定期的読み出し f_1sec = 0; cli(); // いったん割り込み禁止で HDT_H; // HDT H出力 HDT_OUT; PD3_H; // (!!!) PD3 H出力 HDT_L; // HDT L出力 TCNT1 = 0; // カウンタ ゼロから sei(); // 割込有効 f_hdt_ok = 0; // これから hdt_exc = 1; // HDT処理実行開始 } } /***** トリガー *****/ // L出力トリガー時間(20ms)待ち void hdttriger(void) { if(TCNT1 >= 40000){ // 20ms=0.5us*40000 TCNT1 = 0; // カウンタ ゼロから hdt_exc++; // HDT次処理へ } } /***** レスポンス確認 *****/ // ここから高速応答のためこの関数内に留まる // 5バイトのデータ取得に4~5msくらい // パルスが来ないときは20msでタイムアウト // 割込は有効のままで // PD3とLED(PB5)はタイミングチェック用 void hdtrespons(void) { byte ptr; // hdt_data書き込みポインタ byte cnt; // 8bitカウンタ byte d; // 8bitデータ word icp; // ICP1 ICR1データ while(f_hdt_ok == 0){ if(TCNT1 >= 40000){ // 20ms=0.5us*40000 PD3_L; // (!!!) PD3 L出力 LED_OFF; // (!!!) hdt_exc = 0; // タイムアウトで最初から f_hdt_ok = 2; // エラーを残す } switch(hdt_exc){ // 実行区分 2~5 case 2: // Hに cli(); // いったん割り込み禁止で PD3_L; // (!!!) PD3 L出力 HDT_H; // HDT H出力 HDT_INP; // 入力プルアップに CLR_ICF1; // ICF1クリア ICP1_UP; // ICP1↑エッジに TCNT1 = 0; // カウンタ ゼロから sei(); // 割込有効 hdt_exc++; // HDT次処理へ break; case 3: // ACK応答 L→H 確認 if(CHK_ICF1){ // ↑エッジ待ち cli(); // 割り込み禁止で CLR_ICF1; // ICF1クリア ICP1_DN; // ICP1↓エッジに TCNT1 = 0; // カウンタ ゼロから sei(); // 割込有効 hdt_exc++; // HDT次処理へ } break; case 4: // 最初の↓確認 if(CHK_ICF1){ // ↓エッジ待ち cli(); // 割り込み禁止で LED_ON; // (!!!) CLR_ICF1; // ICF1クリア TCNT1 = 0; // カウンタ ゼロから sei(); // 割込有効 ptr = 0; // hdt_dataポインタ cnt = 0; // 8bit カウンタ d = 0; hdt_exc++; // HDT次処理へ } break; case 5: // ↓を待って時間チェック if(CHK_ICF1){ // ↓エッジ待ち cli(); // 割り込み禁止で CLR_ICF1; // ICF1クリア icp = ICR1; // キャプチャ TCNT1 = 0; // カウンタ ゼロから sei(); // 割込有効 d <<= 1; // データ左シフト if(icp >= 200){ // 100us=(0.5u*200)で1/0判断 d |= 0x01; // 越えればdata=1 } cnt++; // ビット数カウンタ +1 if(cnt >= 8){ // 8bit? hdt_data[ptr] = d; // データセーブ cnt = 0; d = 0; ptr++; if(ptr >= 5){ // 5バイト(40パルス) hdt_exc = 0; // 次サイクルに LED_OFF; // (!!!) f_hdt_ok = 1; // OK } } } break; } } } /***** HDT11 制御実行 *****/ void (*hdtexc[])(void)={ hdtstby, // * 0:スタンバイ hdttriger, // 1: hdtrespons, // 2~5: }; /***** SET UP *****/ void setup() { PORTB = 0b00000001; // data/pull up DDRB = 0b00111110; // port指定 // |||||+---- PB0 IO8 in ICP1 // ||||+----- PB1 IO9 out // |||+------ PB2 IO10 out // ||+------- PB3 IO11 out // |+-------- PB4 IO12 out // +--------- PB5 IO13 out LED表示 PORTC = 0b00000000; // data/pull up DDRC = 0b00000000; // port指定 // |||||+---- PC0 AD0 out // ||||+----- PC1 AD1 out // |||+------ PC2 AD2 out // ||+------- PC3 AD3 out // |+-------- PC4 AD4 out // +--------- PC5 AD5 out PORTD = 0b00000011; // data/pull up DDRD = 0b11111110; // port指定 // |||||||+---- PD0 IO0 in RXD // ||||||+----- PD1 IO1 out TXD // |||||+------ PD2 IO2 out // ||||+------- PD3 IO3 out // |||+-------- PD4 IO4 out // ||+--------- PD5 IO5 out // |+---------- PD6 IO6 out // +----------- PD7 IO7 out Serial.begin(9600); // 9600BPSで Cp = &Serial; // シリアル出力に // タイマー1 TCCR1A = 0b00000000; TCCR1B = 0b00000010; // clk 2MHz 0.5usでスタート // タイマー2 TCCR2A = 0b00000010; // |||| ++---- WGM CTC モード // ||++-------- COM2B // ++---------- COM2A TCCR2B = 0b00000100; // || |+++---- CS 16MHz / 64 : 250kHz // || +------- WGM CTC モード // |+---------- ICES2 // +----------- ICNC2 OCR2A = 250 - 1; // 250MHz/250 = 1kHz TIMSK2 = 0b00000010; // +----- OCIE2A コンペアマッチA割り込み有効 } /***** LOOP *****/ void loop() { byte i; Cp->println(F("Test INT0")); delay(100); // 100ms // 繰り返し f_hdt_run = 1; // HDT読み出し実行開始 while(1){ hdtexc[hdt_exc](); // HDT11制御処理実行 if(f_hdt_ok){ f_hdt_ok = 0; for(i = 0; i < 5; i++){ CpPrintf_P(PSTR("%3d "), hdt_data[i]); } Cp->print(" "); for(i = 0; i < 5; i++){ CpPrintf_P(PSTR("%02X "), hdt_data[i]); } Cp->println(); } } }