/**************************************/ /* DHT11を使った湿度計 */ /* "humidity3.ino" */ /**************************************/ // 設定湿度と温度で結露防止のヒーター制御 // Arduino-UNO // 2016-01-21 開始 // 01-25 現 // 2019-12-01 HD1000→SHT31-DISに変更 // 2021-12-08 SHT31→DHT11に変更 // ピン割り当て // PD0 TXD out // PD1 RXD in // PD2 IO2 out (!!!) test pulse // PD3 IO3 out (!!!) // PD4 IO4 out (!!!) // PD5 IO5 out PWM OC0B 温度出力 0~50℃を0~5Vで // PD6 IO6 out PWM OC0A 湿度出力 0~100%を0~5Vで // PD7 IO7 in SSR駆動状態 // PB0 IO8 i/o ICP1 DHT11 通信 // PB1 IO9 out LCD E // PB2 IO10 out LCD D4 // PB3 IO11 out LCD D5 // PB4 IO12 out LCD D6 // PB5 IO13 out LCD D7 // PC0 AD0 in A/D VR1 // PC1 AD1 in A/D VR2 // PC2 AD2 in SW入力 // PC3 AD3 out ヒータ制御 on/off // PC4 AD4 out LCD RS // PC5 AD5 in データ出力1分/1秒切り替えジャンパ /***** ライブラリ ****/ #include // 16文字×2行液晶を4bitモードで使用 // http://www.arduino.cc/en/Tutorial/LiquidCrystal /***** タイトル *****/ const char pgm_ttl1[] PROGMEM = "Humidity"; const char pgm_ttl2[] PROGMEM = "21-12-10" ; // 01234567 /***** 液晶ピン指定 *****/ #define LCD_RS A4 // デジタルピン指定 #define LCD_E 9 // 4bitモードで使用 #define LCD_D4 10 #define LCD_D5 11 #define LCD_D6 12 #define LCD_D7 13 // initialize the library with the numbers of the interface pins LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7); /***** 配列のデータ数を返すマクロ *****/ #define DIMSIZ(a) (sizeof(a)/sizeof(*a)) /***** ピン指定 *****/ // PWM出力 #define PWM_TEMP 5 // 温度 0~50℃ #define PWM_HUMI 6 // 湿度 0~100% // SW入力 #define INP_SW ((~PINC) & (1 << PC2)) // SW入力 on,offチェック Lでon #define INP_SSR ((~PIND) & (1 << PD7)) // SSR駆動状態 Lでon #define JP_TX1S ((~PINC) & (1 << PC5)) // データ送信タイミングジャンパ // onで1秒,offなら1分 // ヒータ出力 #define HEAT_ON (PORTC |= (1 << PC3)) // ヒータ制御出力 on #define HEAT_OFF (PORTC &= ~(1 << PC3)) // ヒータ制御出力 off #define HEAT_CK (PORTC & (1 << PC3)) // ヒータ出力on,offチェック // PB0 ICP1 (14pin) ポート出力 H/L,out/inp 入力 #define DHT_H (PORTB |= (1 << PB0)) // 14pin #define DHT_L (PORTB &= ~(1 << PB0)) #define DHT_OUT (DDRB |= (1 << DDB0)) // 出力に #define DHT_INP (DDRB &= ~(1 << DDB0)) // 入力に #define INP_DHT (PINB & (1 << PB0)) // 入力H/Lチェック // タイマー1 ICP #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)) // オーバーフロークリア // テストポイント #define PD2_H (PORTD |= (1 << PD2)) // 4pin #define PD2_L (PORTD &= ~(1 << PD2)) // 計算タイミング #define PD3_H (PORTD |= (1 << PD3)) // 5pin #define PD3_L (PORTD &= ~(1 << PD3)) // 1mSタイマー,A/D割り込み #define PD4_H (PORTD |= (1 << PD4)) // 6pin #define PD4_L (PORTD &= ~(1 << PD4)) // HDT11タイミング /***** 温度、湿度データ *****/ word temp_w; // 温度生データ(16bit) word humi_w; // 湿度生データ(16bit) float temp_f; // 温度計算データ(℃) float humi_f; // 湿度計算データ(%) // ヒータon/off制御データ float humi_vr; // ヒータ制御VR1 湿度設定値 40~99% // 設定以上の湿度でヒーターon float temp_vr; // ヒータ制御VR2 温度設定値 5~30℃ // 設定温度以下で設定湿度以上の時にヒーターをon // 設定温度以上の時は湿度が大きくてもヒーターはonしない #define HIST_HUMI 2.0 // 湿度ヒステリシス設定値 % #define HIST_TEMP 0.5 // 温度ヒステリシス設定値 ℃ // オン条件 設定湿度(VR1)以上で // 設定温度(VR2)-ヒステリシス 未満の温度の時 // オフ条件 設定湿度(VR1)-ヒステリシス 未満で // 設定温度(VR2)以上の時 /***** フラグ *****/ byte f_vrok; // VRデータ確定フラグ // 1でVR値確定 byte f_dhtok; // DHT11 データ確定フラグ // 0:まだ 1:OK // 2:タイムアウトエラー // 3:sumエラー // 4:数値範囲エラー H:0~99,T:-20~50 volatile byte f_dhtrun; // DHT11読み出し開始フラグ // 1で開始 // タイマー割込で250ms周期 /******************************/ /* スイッチ入力 */ /******************************/ // SWコード #define SW_DISP 1 // SW1 温度湿度/VR,VR1表示切り替え #define SW_TEST 2 // SW1 長押しでテスト表示 volatile byte f_swon; // SW入力オン確定フラグ volatile byte sw_code; // SW on コード /***** スイッチ入力チェック *****/ // 1msで処理 // 結果をf_swonとsw_codeに残す void swscan(void) { static byte chk = 0; // 実行区分 static word tm1 = 0; // 1msタイマー チャタリング除去 if(tm1) tm1--; // 1ms計時 switch(chk){ case 0: // オフチェックタイマーをセット tm1 = 10; // 10ms chk++; break; case 1: // 離されるのを待つ if(INP_SW == 0){ // SWオフ確認 if(tm1 == 0) chk++; // タイムアップで次stepへ } else{ // どれか押されている chk--; // タイマー再セット } break; case 2: // on待ち if(INP_SW){ // on? tm1 = 10; // 10ms チャタリング除去 chk++; // 安定チェックへ } break; case 3: // on確定待ち if(INP_SW == 0){ // オフならもういちど chk--; } else{ // オン継続 if(tm1 == 0){ // チャタリングOK tm1 = 1500; // 1.5秒経過で長押し判定 chk++; } } break; case 4: // 短押し、長押しの判断 if(INP_SW){ // on継続 if(tm1 == 0){ // タイムアップ sw_code = SW_TEST; // 長押しコード確定 f_swon = 1; // onフラグ chk = 0; // オフ確認に } } else{ // 離された sw_code = SW_DISP; // 短押しコード確定 f_swon = 1; // onフラグ chk = 0; // オフ確認に } break; } } /***** SW オンチェック *****/ // onしたらコードを持ってリターン // offなら0 byte swonchk(void) { if(f_swon == 0){ return 0; // SW off =0 } else{ f_swon = 0; // フラグをオフして return sw_code; // SW on =SWコード } } /******************************/ /* 1ms タイマー割り込み */ /******************************/ /***** タイマーデータ *****/ volatile byte tm_10ms; // 計時用ダウンカウント volatile byte f_htctrl; // ヒーター制御タイミング 1秒周期 volatile byte f_txrq = 1; // データ送信タイミング 1分周期 /***** タイマー2 コンペアマッチA割込み *****/ // 1kHz周期で割り込み ISR(TIMER2_COMPA_vect) { static byte cnt10 = 0; // 10msカウント static byte cnt25 = 0; // 250msカウント static byte cnt100 = 0; // 1秒カウント (10ms x 100) static byte cnt60 = 0; // 1分カウント (1sec x 60) PD3_H; // (!!!) 5pin // 1ms処理 swscan(); // スイッチ入力チェック // 10msタイマー cnt10++; if(cnt10 >= 10){ // 10ms cnt10 = 0; if(tm_10ms) tm_10ms--; // 10mS ダウンカウント cnt25++; if(cnt25 >= 25){ // 250ms経過 cnt25 = 0; f_dhtrun = 1; // DHT11読み出し開始フラグon } // 1secタイマー cnt100++; if(cnt100 >= 100){ // 1秒経過 cnt100 = 0; f_htctrl = 1; // ヒーター制御タイミングon if(JP_TX1S) f_txrq = 1; // データ送信タイミングJP(1秒) cnt60++; if(cnt60 >= 60){ // 1分経過 cnt60 = 0; if(JP_TX1S == 0) f_txrq = 1; // データ送信タイミングJP(1分) } } } // 内蔵A/D開始 ADCSRA |= (1 << ADSC); // A/D変換開始 PD3_L; // (!!!) 5pin } /******************************/ /* 内蔵A/D処理 */ /******************************/ /**** A/D データ *****/ // A/D変換チャンネル (ADMUX) const byte ad_mpx[] PROGMEM ={ 0b01000000, // ch 0 VR1 0b01000001, // ch 1 VR2 }; // ||| ++++---- MPX 0,1 // ||+--------- ADLAR 右そろえ // ++---------- REFS1,0 AVCC接続 // AD ch0,1 : VRデータ volatile word ad_avr[2]; // A/D変換データ 0~1023 // 平均処理された結果 volatile uint32_t ad_add[2]; // A/D平均処理用加算データ volatile byte f_adok; // A/D変換完了フラグ // 256msごと /***** A/D割り込み処理 *****/ // タイマー割り込みでA/D変換開始 // 1msに1回, 2msで2ch, 128回で平均値算出 ISR(ADC_vect) { word d; static byte ch = 0; // A/D変換チャンネル static word cnt = 0; // A/D変換平均回数 PD3_H; // (!!!) 5pin d = (word)ADCL; // d |= (ADCH & 0x03) << 8; // 符号なしで 0~3FF // 測定値 ad_add[ch] += (uint32_t)d; // 平均用に加算 // 次変換チャンネル ch++; // ch0,1 if(ch >= 2) ch = 0; ADMUX = pgm_read_byte(&ad_mpx[ch]); // MPX切り替え // 平均加算回数 if(ch == 0){ cnt++; if(cnt >= 128){ // 128回? cnt = 0; ad_avr[0] = word(ad_add[0] / 128L); // 平均 ad_avr[1] = word(ad_add[1] / 128L); ad_add[0] = 0; // 次加算データクリア ad_add[1] = 0; f_adok = 1; // 変換完了 } } PD3_L; // (!!!) 5pin } /************************************/ /* DHT11温湿度センサー処理 */ /************************************/ // タイマー1を2MHz(0.5us)クロックで使用 /***** DHT11 データ *****/ word dht_data[5]; // 検出データ // 湿度H,湿度L,温度H,温度L,sum byte dht_exc; // DHT11読み出し実行区分 /***** スタンバイ *****/ // f_dhtrunを待ってDHT11へ開始パルスを出力 void dhtstby(void) { if(f_dhtrun){ // 定期的読み出し指令あり(250ms) f_dhtrun = 0; cli(); // いったん割り込み禁止で DHT_H; // DHT H出力 DHT_OUT; TCNT1 = 0; // カウンタ ゼロから DHT_L; // DHT L出力 sei(); // 割込有効 dht_exc = 1; // DHT処理実行開始 } } /***** トリガー *****/ // L出力トリガー時間(20ms)待ち void dhttriger(void) { if(TCNT1 >= 40000){ // 20ms=0.5us*40000 dht_exc++; // DHT次処理へ } } /***** レスポンス確認 *****/ // ここから高速応答のためこの関数内に留まる // 5バイトのデータ取得に4~5msくらい // パルスが来ないときは20msでタイムアウト // 割込は有効のままで // PD3,PD4とLED(PB5)はタイミングチェック用 // 毎回TCNT1をクリアするのではなく前回のICP1値 // との差でパルス幅をチェックする void dhtrespons(void) { byte ptr; // dht_data書き込みポインタ byte cnt; // 8bitカウンタ byte d; // 8bitシフト用データ word icp; // ICP1 ICR1データ word p; // 前回のICPからの差でクロック数を計算 byte exc = 0; // 関数内の実行区分 TCNT1 = 0; // カウンタ ゼロから while(1){ // loop if(TCNT1 >= 40000){ // 20ms=0.5us*40000 タイムアウト dht_exc = 0; // タイムアウトで最初から f_dhtok = 2; // エラーを残す return; // おわり } switch(exc){ // 実行区分 case 0: // Hにしてpullup入力に cli(); // いったん割り込み禁止で DHT_H; // DHT H出力 DHT_INP; // 入力プルアップに CLR_ICF1; // ICF1クリア ICP1_UP; // ICP1↑エッジに sei(); // 割込有効 exc++; // 次処理へ break; case 1: // ACK応答 L→H 確認 if(CHK_ICF1){ // ↑エッジ待ち CLR_ICF1; // ICF1クリア ICP1_DN; // ICP1↓エッジに exc++; // 次処理へ } break; case 2: // 最初の↓確認 if(CHK_ICF1){ // ↓エッジ待ち CLR_ICF1; // ICF1クリア icp = ICR1; // キャプチャ値を保存 ptr = 0; // dht_dataポインタ cnt = 0; // 8bit カウンタ d = 0; // シフトデータ exc++; // 次処理へ } break; case 3: // ↓を待って時間チェック if(CHK_ICF1){ // ↓エッジ待ち PD4_H; // (!!!) 6pin CLR_ICF1; // ICF1クリア p = ICR1 - icp; // クロック差 icp = ICR1; // キャプチャ値を保存 d <<= 1; // データ左シフト if(p >= 200){ // 100us=(0.5u*200)で1/0判断 d |= 0x01; // 越えればdata=1 } cnt++; // ビット数カウンタ +1 if(cnt >= 8){ // 8bit? dht_data[ptr] = d; // データセーブ cnt = 0; // 0に戻す d = 0; ptr++; // ポインタ+1 if(ptr >= 5){ // 5バイト(40パルス)おわり? exc++; // 次へ } } PD4_L; // (!!!) } break; case 4: // おしまい dht_exc++; // 次処理 データチェックへ return; // おわり } } } /***** 受取データチェック *****/ // dht_data[]から湿度,温度を分離 void dhtdatack(void) { byte sum; // 5つのsum確認 short d; // 湿度 0.1%、温度 0.1℃で(マイナスにもなる) byte er = 0; PD2_H; // (!!!) sum = dht_data[0] // sum確認 + dht_data[1] // 先頭の4つ + dht_data[2] + dht_data[3]; if(sum != dht_data[4]){ // 5つ目と比較 f_dhtok = 3; // sumエラー dht_exc = 0; // 次回の開始を待つ PD2_L; // (!!!) return; // おわり } // 湿度変換 0.1%単位で PD2_L; // (!!!) d = dht_data[0] * 10; // 湿度 1 d += dht_data[1] & 0x0F; // 湿度 0.1 // 0.0%~100.0%の範囲をチェック if(d > 1000){ d = 1000; // 100.0%に er = 1; } humi_w = d; //湿度確定(wordで) humi_f = (float)d / 10.0; // 0.1%で // 温度変換 0.1℃単位で PD2_H; // (!!!) d = dht_data[2] * 10; // 温度 1 d += dht_data[3] & 0x0F; // 温度 0.1 if(dht_data[3] & 0x80){ // 氷点下なら d = -d; // マイナスに } // 温度 -20.0℃~99.9℃ 範囲をチェック if(d < -200){ // -20.0℃未満? d = -200; // -20.0℃に er = 1; } else if(d > 999){ // 99.9℃越えた? d = 999; // 99.9℃に er = 1; } temp_w = d; // 温度確定(wordで) temp_f = (float)d / 10.0; // 0.1℃で // エラー判断 if(er) f_dhtok = 4; // 数値範囲エラー else f_dhtok = 1; // エラー無しでok // 次サイクル待ちへ PD2_L; // (!!!) dht_exc = 0; // 次回の開始を待つ } /***** DHT11 制御実行 *****/ void (*dhtexc[])(void)={ dhtstby, // * 0: スタンバイ dhttriger, // 1: トリガー出力 dhtrespons, // 2: ACK応答待ち~データ入力 dhtdatack, // 3: データチェック }; /**************************/ /* 液晶表示 */ /**************************/ /***** 書式付液晶表示 *****/ void lcdprintf(const char *s, ...) { va_list vp; char bff[40]; // バッファを確保 va_start(vp,s); vsprintf(bff,s,vp); lcd.print(bff); va_end(vp); } /***** 1行消去 *****/ // n : 0,1 行 void lcdclrline(byte n) { byte i; lcd.setCursor(0, n); for(i = 0; i < 16; i++){ lcd.write(' '); } } /***** メッセージ出力 *****/ void lcdputs_P(PGM_P s) { char c; while(1){ c = pgm_read_byte(s); if(c == '\x0') break; lcd.write(c); s++; } } /**************************/ /* シリアル出力 */ /**************************/ /***** 書式付シリアル出力 *****/ void txprintf(const char *s, ...) { va_list vp; char bff[40]; // バッファを確保 va_start(vp,s); vsprintf(bff,s,vp); Serial.print(bff); va_end(vp); } /***** メッセージ出力 *****/ void txputs_P(PGM_P s) { char c; while(1){ c = pgm_read_byte(s); if(c == '\x0') break; Serial.write(c); s++; } } /********************************/ /* 温度,湿度出力処理 */ /********************************/ // 制御時間 uint32_t tx_cnt; // 1出力ごとにカウントアップ byte f_txrdy; // データ送信準備完了フラグ // DHT11 データok回数が2で /***** 測定データシリアル出力 *****/ // 1分ごとに6桁分値 温度,湿度を出力 // ヒーター制御情報 // 0:オフ // 1:制御出力はオンしているが感熱センサーでSSRはオフ // 3:制御出力オン,SSRもオンで通電中 void txdata(void) { char s[10]; byte d; byte i; if((f_txrdy) && // DHT11温湿度データ確定 (f_txrq)){ // 送信タイミング f_txrq = 0; // カウント txprintf("%6lu", tx_cnt); tx_cnt++; if(tx_cnt > 999999L) tx_cnt = 0L; // 温度 dtostrf(temp_f, 6, 1, s); // xxxx.x Serial.print(s); // 湿度 dtostrf(humi_f, 6, 1, s); // xxxx.x Serial.print(s); // ヒータ,SSR on,off d = 0; if(HEAT_CK) d += 1; // ヒーター on if(INP_SSR) d += 2; // SSR on txprintf(" %u", d); // 3:SSRon 1:ヒータ出力 // DHT11生データ #if 0 Serial.print(" ["); // 16進で5データ for(i = 0; i < 5; i++){ txprintf("%02X", dht_data[i]); if(i != 4) Serial.print(" "); } Serial.print("]"); #endif Serial.println(); // 改行 } } /***** VR設定データ出力 *****/ // 温度,湿度制御設定データ void txvrset(void) { char s[10]; dtostrf(temp_vr, 5, 1, s); // 5.0~30.0℃ txprintf("#VR T-off:%s%cC\r\n", s, 0xDF); dtostrf(humi_vr, 5, 1, s); // 40.0~99.0% txprintf("#VR H-on :%s%%\r\n", s); } /********************************/ /* ヒーター制御 */ /********************************/ /***** ヒータ制御処理 *****/ // 1秒ごとに制御 // オン条件 設定湿度(VR1)以上で // 設定温度(VR2)-ヒステリシス 未満の温度の時 // オフ条件 設定湿度(VR1)-ヒステリシス 未満で // 設定温度(VR2)以上の時 void heaterctrl(void) { float f; word d; if(f_htctrl){ // 1秒経過? f_htctrl = 0; // on ? if((humi_f >= humi_vr) && // 湿度が上昇 (temp_f < (temp_vr - HIST_TEMP))){ // なおかつ温度が低い時 HEAT_ON; // ヒーターon } // off else if((humi_f < (humi_vr - HIST_HUMI)) || // 湿度が下降 (temp_f >= temp_vr)){ // あるいは温度上昇 HEAT_OFF; // ヒーターoff } // 温度PWM出力 f = constrain(temp_f , 0.0, 50.0); // 温度 0~50℃ d = (word)((f / 50.0) * 256.0); analogWrite(PWM_TEMP, min(d, 255)); // 0~255 // 湿度PWM出力 f = constrain(humi_f , 0.0, 100.0); // 湿度 0~100% d = (word)((f / 100.0) * 256.0); analogWrite(PWM_HUMI, min(d, 255)); // 0~255 } } /*****************************************/ /* 制御実行処理 */ /*****************************************/ /***** 制御実行区分 *****/ byte r_exc; // 実行区分 #define R_HTCTRL 2 // ヒーター制御 #define R_TESTVR 4 // 液晶表示実行 /***** 制御用データ ******/ word ad_vr[2]; // VR1,VR2 A/D値 0~1023 /***** タイトル表示 *****/ // 装置名,バージョン表示 void rttl1(void) { // タイトル lcd.setCursor(0, 0); // タイトル lcdputs_P(pgm_ttl1); lcd.setCursor(0, 1); lcdputs_P(pgm_ttl2); tm_10ms = 200; // 2.0秒 r_exc++; // 次exc } /***** タイトル表示 #2 *****/ // タイムアップを待ってヒーター制御へ void rttl2(void) { static byte ok = 0; // OKカウンタ if(f_dhtok == 1){ // DHT11正常変換 f_dhtok = 0; if(ok < 2) ok++; // 2回検出 } if((tm_10ms == 0) && // タイムアップ (ok >= 2)){ // DHT11変換2回 f_txrdy = 1; // データ送信できる txvrset(); // 温度,湿度VR設定出力 lcd.clear(); // 液晶消してから r_exc++; // 次exc } } /***** 温度,湿度表示 *****/ // ヒーター制御出力 // 温度がVR設定より低くて湿度がVR設定より大きい時 // 温度0~50℃を0~5VでPWM出力 // 湿度0~100%を0~5VでPWM出力 void rhtctrl(void) { char s[10]; if(f_dhtok){ // DHT11変換完了(okでなくてもかまわない) f_dhtok = 0; lcd.setCursor(0, 0); // 1行目 温度 dtostrf(temp_f, 5, 1, s); // xxx.x℃ lcdprintf("T%s%cC", s, 0xDF); lcd.setCursor(0, 1); // 2行目 湿度 dtostrf(humi_f, 5, 1, s); // xxx.x% lcdprintf("H%s%%", s); } // ヒータ制御 heaterctrl(); // 湿度でヒータをon/off // スイッチチェック switch(swonchk()){ case SW_DISP: // 表示切り替え lcd.clear(); r_exc++; break; case SW_TEST: // 長押し:VRテストへ lcd.clear(); HEAT_OFF; // ヒーターoff r_exc = R_TESTVR; break; } } /***** ヒータ制御湿度値確認 *****/ // VR1(ヒータon湿度)とVR2(規制温度)の設定を表示 void rvrdisp(void) { char s[10]; if(f_vrok){ // VRデータ確定 f_vrok = 0; lcd.setCursor(0, 0); // 1行目 温度設定VR dtostrf(temp_vr, 2, 0, s); // 5~30℃ lcdprintf("Toff%s%cC", s, 0xDF); // 「゚C」 lcd.setCursor(0, 1); // 2行目 湿度設定VR dtostrf(humi_vr, 3, 0, s); // 40~99% lcdprintf("Hon%s%%", s, 0xDF); // 「゚C」 } // ヒータ制御 heaterctrl(); // ヒータ制御 // スイッチチェック switch(swonchk()){ case SW_DISP: // 表示切り替え txvrset(); // 温度,湿度VR設定出力 lcd.clear(); r_exc--; break; case SW_TEST: // 長押し:VRテストへ lcd.clear(); HEAT_OFF; // ヒーターoff r_exc = R_TESTVR; break; } } /***** テストVR値表示 *****/ // VR1,2のA/D値(10bit)を表示 // その値をPWM出力 void rtestvr(void) { byte i; if(f_vrok){ // VRデータ確定 f_vrok = 0; lcd.setCursor(0, 0); // 1行目 lcdprintf("T:%4d", ad_vr[1]); lcd.setCursor(0, 1); // 2行目 lcdprintf("H:%4d", ad_vr[0]); analogWrite(PWM_TEMP, ad_vr[1] / 4); // PWM出力 analogWrite(PWM_HUMI, ad_vr[0] / 4); } // スイッチチェック switch(swonchk()){ case SW_DISP: // 表示切り替え lcd.clear(); r_exc++; break; case SW_TEST: // 長押し:ヒーター制御へ lcd.clear(); txvrset(); // 温度,湿度VR設定出力 r_exc = R_HTCTRL; break; } } /***** テストDHT11値表示 *****/ // 温度,湿度の生データを表示 void rtestdht(void) { if(f_dhtok){ // DHT11変換完了 f_dhtok = 0; lcd.setCursor(0, 0); // 1行目 lcdprintf("T:%6d", temp_w); lcd.setCursor(0, 1); // 2行目 lcdprintf("H:%6d", humi_w); } // スイッチチェック switch(swonchk()){ case SW_DISP: // 表示切り替え lcd.clear(); r_exc--; break; case SW_TEST: // 長押し:ヒーター制御へ lcd.clear(); txvrset(); // 温度,湿度VR設定出力 r_exc = R_HTCTRL; break; } } /********************************/ /* 制御実行テーブル */ /********************************/ /***** 制御実行 *****/ void (*rexc[])(void)={ rttl1, // 0:タイトル表示 rttl2, // 1:タイトル表示完了待ち rhtctrl, // 2:ヒーター制御 rvrdisp, // 3:ヒータ制御湿度値確認 rtestvr, // 4:VR値テスト rtestdht, // 5:DHT11センサーテスト }; /******************************/ /* セットアップ */ /******************************/ /***** セットアップ *****/ // ATmega328Pのレジスタを直接制御 void setup() { // I/Oイニシャル cli(); // いったん割り込み禁止 PORTB = 0b00000001; // out data, pull up DDRB = 0b00111110; // portI/O // |||||+---- PB0 IO8 i/o ICP1 DHT11 通信 // ||||+----- PB1 IO9 out LCD E // |||+------ PB2 IO10 out LCD D4 // ||+------- PB3 IO11 out LCD D5 // |+-------- PB4 IO12 out LCD D6 // +--------- PB5 IO13 out LCD D7 PORTC = 0b00100100; // out data, pull up DDRC = 0b00011000; // portI/O // |||||+---- PC0 AD0 in VR1入力 // ||||+----- PC1 AD1 in VR2入力 // |||+------ PC2 AD2 in SW入力 // ||+------- PC3 AD3 out ヒーター駆動出力 // |+-------- PC4 AD4 out LCD RS // +--------- PC5 AD5 in データ出力1分/1秒切り替えジャンパ PORTD = 0b10000011; // out data, pull up DDRD = 0b01111110; // portI/O // |||||||+---- PD0 RXD in // ||||||+----- PD1 TXD out // |||||+------ PD2 IO2 out (!!!) // ||||+------- PD3 IO3 out (!!!) // |||+-------- PD4 IO4 out (!!!) // ||+--------- PD5 IO5 out PWM OC0B // |+---------- PD6 IO6 out PWM OC0A // +----------- PD7 IO7 in SSR駆動状態入力 Lでon // A/D割り込み ADMUX = 0b01000000; // 内蔵A/D // ||| ++++---- ch0 VR1 // ||+--------- ADLAR // ++---------- AVCC接続 ADCSRA = 0b10001111; // |||||+++--- ADPS 16MHz/128=125kHz // ||||+------ ADIE A/D割込有効 // |||+------- ADIF 変換完了フラグ // ||+-------- ADATE A/D自動起動 // |+--------- ADSC 変換開始 // +---------- ADEN A/D有効 DIDR0 = 0b00000011; // デジタル入力禁止 // ||||++--- A/D ch1,0 A/Dに // ++++----- A/D ch5~2 I/Oポートに // タイマー1 : ICP1でインプットキャプチャ TCCR1A = 0b00000000; TCCR1B = 0b00000010; // clk 2MHz 0.5usでスタート // タイマー2 : 1kHz割込 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割り込み有効 sei(); // 割込有効に // シリアル Serial.begin(9600); // シリアル通信 // LCD lcd.begin(8, 2); // 16文字×2行 } /******************************/ /* ループ */ /******************************/ /***** LOOP *****/ void loop() { while(1){ // 湿度,温度データ取得 dhtexc[dht_exc](); // DHT11制御処理実行 // VR1,VR2データ if(f_adok){ // A/D変換完了 f_adok = 0; cli(); // 割込禁止 ad_vr[0] = ad_avr[0]; // 内蔵A/D ch0 0~1023 ad_vr[1] = ad_avr[1]; // 内蔵A/D ch1 sei(); // 割込許可 // VR1 湿度ヒータ制御データに 0~1023→40~99% humi_vr = 40.0 + (float)((ad_vr[0] * 59) / 1023); // VR2 温度ヒータ制御データに 0~1023→5~30℃ temp_vr = 5.0 + (float)((ad_vr[1] * 25) / 1023); f_vrok = 1; } // 制御実行 rexc[r_exc](); // 制御実行区分 // 温度,湿度をシリアル出力 txdata(); // 制御情報出力 } } /*==== end of "humidity3.ino" ====*/