時間の表示が出来るようになったので、更に、温度・湿度を測定し表示させることにした。温湿度センサは当初はBME280を利用する予定でしたが、BME280は動作電圧が3.3Vで、測定値の補正計算も面倒そうなので、5Vで動作し、データもリニアでそのまま使えるHDC1050を使うことにした。
HDC1050のデータは全て16ビットで、最初に動作設定をConfiguration(0x02)に書き込み、温度(0x00)または湿度(0x01)にアドレス指定すると温湿度の測定が開始され、測定終了後に温度や湿度の16ビットデータ(有効データは上位14ビット)読み込み、測定範囲で浮動小数点データに変換するだけである(温度は-40℃オフセットが必要)。HDC1050では温度と湿度を同時に測定し、温度と湿度を続けて読み込むこともできるが、ここでは温度と湿度を個別に測定し、読み込む方法を用いた。
左ボタンは「温湿度/時刻表示」切替えボタン、右ボタンは「秒/曜日・温度表示桁」切替ボタンとした。LCD表示時の注意として、UNOではsprintfでformat文に"%f"が使えないので、dtostrf()を利用した(指数表示できるdtostre()もある)。なお、標準で温度表示は4桁で、5桁以上になると右端の”C"が表示されない。この場合、右ボタンを押すと”C"を含めて正しく表示される
なお、RTCの内部データはBCDデータとなっているので、整数データをBCDに変換して書き込み、読み出し時には2進数に変換した。また、プッシュボタンを押すと、「秒表示」と「曜日表示」を変更できる。
1秒毎の測定にはRTCの一定周期割り込みも使えるが、RTCのCLOCKOUTに1Hzが出力されるように設定し、これをUNOの2番ピンに接続し、UNOの外部割り込み(立ち上がり)を利用した。割込ルーチンではrtc_int_flgをセットし、メインルーチンで常にrtc_int_flgをチェックし、フラグが立っていたら各データを取り込んで、LCDに表示している。これにより1秒毎に時計と温湿度データを取込み、表示している。RTCのINT出力はRTC基板のLED表示に利用した(1秒毎にON/OFF)。
char *dtostrf( double val, signed char width, unsigned char prec, char *s ) 【変数】val :変換する値 width :小数点や符号を含んだ変換後の総文字数(負の数を指定すると左詰めとなる) prec :小数点以下の桁数 s :変換後の文字列を格納する変数を指定 戻り値 :戻り値は、変換後の文字列を格納する変数(sと同じ)
//********** interrupt routin ***** void rtc_intr(){ // 割込処理ルーチン rtc_int_flg = true; // 割込フラグをセット } ・・・ attachInterrupt( 0, rtc_intr, FALLING ); // 割込設定(H->L)) ・・・
温湿度測定表示回路図 | ブレッドボード配線 (左:温度/時刻、右:秒/曜) |
温湿度データ読み込み・表示中 |
// 温度・湿度測定+RTC+LCD( HDC1050 + rtc-8564nb + LCD ) #include |
//***** 液晶表示 ********(使用電源によりどちらか選択) //#define BOOST 0x04 // 3.3V用 AQM0802 #define BOOST 0x00 // 5.0V用 AQM0802 int contrast = 0x20; // コントラスト初期値 void lcd_cmd(byte cmd){ Wire.beginTransmission(LCD_Adr); Wire.write(0x00); // コマンド指定 Wire.write(cmd); // コマンド出力 Wire.endTransmission(); // ストップ if((cmd == 0x01)||(cmd == 0x02)) // ClearかHomeか delay(2); // 2msec待ち else delayMicroseconds(30); // 30μsec待ち } void lcd_data(byte data){ Wire.beginTransmission(LCD_Adr); // スタート Wire.write(0x40); // 表示データ指定 Wire.write(data); // 表示データ出力 Wire.endTransmission(); // ストップ delayMicroseconds(30); // 遅延 } void lcd_setCursor(byte clm,byte row){ if(row==0) lcd_cmd(0x80+clm); // カーソル位置 if(row==1) lcd_cmd(0xc0+clm); } void lcd_begin(void){ // LCDの初期化 Serial.println("LCD_begin"); delay(10); lcd_cmd(0x38); // 8ビット2行 標準モード lcd_cmd(0x39); // 8ビット2行 拡張モード lcd_cmd(0x14); // OSC 183Hz BIAS 1/5 lcd_cmd((byte)(0x70 + (contrast & 0x0F))); lcd_cmd((byte)(0x58 + BOOST + (contrast >> 4))); lcd_cmd((byte)0x6B); // Follwer for 3.3V delay(1); lcd_cmd((byte)0x38); // 標準モードへ lcd_cmd((byte)0x0C); // 表示開始 lcd_cmd((byte)0x01); // 画面消去 delay(1); } void lcd_clear(void){ lcd_cmd(0x01); // 全消去コマンド出力 delay(2); } void lcd_print(char* ptr){ // 文字列表示関数 while(*ptr != 0) // 文字取り出し lcd_data(*ptr++); // 文字表示 } void lcd_print(int num){ // 整数表示関数 sprintf(s_buf,"%d",num); lcd_print(s_buf); } //***** HDC1050 ******** #define HDC_TEMP 0 #define HDC_HUME 1 #define HDC_CONFIG 2 void hdc_write(byte adr, word data){ Wire.beginTransmission(HDC_Adr); Wire.write(adr); // アドレス指定 Wire.write((byte)(data >> 8)); // データ書込み(MSD8) Wire.write((byte)(data % 0xff)); // データ書込み(LSD8) Wire.endTransmission(); delay(1); } unsigned int hdc_read(byte adr){ word rd_dat; Wire.beginTransmission(HDC_Adr); Wire.write(adr); // アドレス指定 Wire.endTransmission(); Wire.requestFrom(HDC_Adr,2); // データ1バイト送信要求 while ( Wire.available()== 0 ); rd_dat = Wire.read() << 8 ; // データ取得(MSD8) rd_dat = rd_dat | Wire.read(); // データ取得(LSD8) return rd_dat; } void hdc_trigger(byte adr){ Wire.beginTransmission(HDC_Adr); Wire.write(adr); // アドレス指定 Wire.endTransmission(); delay(1); } unsigned int hdc_read_data(){ word rd_dat; Wire.requestFrom(HDC_Adr,2); // データ1バイト送信要求 rd_dat = Wire.read() << 8 ; // データ取得(MSD8) rd_dat = rd_dat | Wire.read(); // データ取得(LSD8) return rd_dat; } |
void hdc_begin(){ //****** 条件により選択 Serial.println("HDC_begin"); //hdc_write(HDC_CONFIG, 0x0000); // TH単独、14bit、ヒートoff //hdc_write(HDC_CONFIG, 0x1000); // TH同時、14bit、ヒートoff hdc_write(HDC_CONFIG, 0x2000); // TH単独、14bit、ヒートon //hdc_write(HDC_CONFIG, 0x3000); // TH同時、14bit、ヒートon delay(1); sprintf(s_buf,"HDC device: %x", hdc_read(0xff) ); Serial.println(s_buf); } //********** interrupt routin ***** void rtc_intr(){ // 割込処理ルーチン rtc_int_flg = true; // 割込フラグをセット Serial.println("interrupt!"); // 周期割込確認用 } //********* setup *********** void setup(){ Serial.begin(9600); // シリアルモニタON pinMode(MdBtn_Pin, INPUT_PULLUP); // モード選択ボタン pinMode(THBtn_Pin, INPUT_PULLUP); // 時間・温度選択ボタン Wire.begin(); // I2C通信開始 delay(1); rtc_begin(); // RTCの初期化 lcd_begin(); // LCDの初期化 hdc_begin(); attachInterrupt( 0, rtc_intr, FALLING ); //割込設定 Serial.println("-- setup end"); } //********* main loop *********** unsigned int temp; unsigned int hum; float f_buf; char buf[10] = ""; void loop(){ if ( digitalRead(MdBtn_Pin) == LOW ){; dsp_md = dsp_md ^ 0x01; // ビット0を反転 while( digitalRead(MdBtn_Pin) == LOW ); // highまで待つ } if ( digitalRead(THBtn_Pin) == LOW ){; dsp_md = dsp_md ^ 0x02; // ビット1を反転 while( digitalRead(THBtn_Pin) == LOW ); // highまで待つ } hdc_trigger( HDC_TEMP ); delay(10); temp = hdc_read_data(); //temp = 0xffff; // 表示テスト用 hdc_trigger( HDC_HUME ); delay(10); hum = hdc_read_data(); if ( rtc_int_flg == true ){ // 割込フラグが立っているか? rtc_read_data(); // RTCからデータを読む switch ( dsp_md ){ case 0: case 1: sprintf( s_buf,"%02d/%02d/%02d",years,months,days ); break; case 2: f_buf = (float)temp / 65536.0 * 165.0 - 40.0; dtostrf( (double)f_buf,4,1,buf); // "%f"の代わり sprintf( s_buf,"T:%4s\337C",buf ); break; case 3: f_buf = (float)temp / 65536.0 * 165.0 - 40.0; dtostrf( (double)f_buf,5,1,buf); // "%f"の代わり sprintf( s_buf,"T%5s\337C",buf ); break; } lcd_setCursor(0,0); // カーソルを0行目の先頭に lcd_print(s_buf); // LCDに年月日を表示 Serial.println( s_buf ); // 表示テスト・確認用 switch ( dsp_md ){ case 0: sprintf( s_buf,"%02d:%02d:%02d",hours,minutes,seconds ); break; case 1: sprintf( s_buf,"%02d:%02d%3s",hours,minutes,wk_dt[weeks] ); break; case 2: case 3: f_buf = (float)hum / 65536.0 * 100.0; dtostrf( (double)f_buf,4,1,buf); // "%f"の代わり sprintf( s_buf,"H:%4s %%",buf ); break; } lcd_setCursor(0,1); // カーソルを1行目の先頭に lcd_print(s_buf); // LCDに時分秒を表示 Serial.println( s_buf ); // 表示テスト・確認用 rtc_int_flg = false; // 割込フラグ消去 } delay(10); } |
温度・湿度−LCD表示スケッチ (hdc1050_rtc.ino), (hdc1050_rtc.zip)
郵便物などの宛名が残ったままゴミ箱に捨てた場合、個人情報が読み取られる場合があります。
このような場合、シュレッダーを使ったり、宛名部分を黒く塗りつぶす方法が行われています。郵便物など消す部分が小さい場合は、「コココロケシコロ」「ケシポン」などのローラースタンプが便利です。特にMAXの「コロコロケシコロwithレターオープナー」は宛名消しと切り屑を出さずに封筒カットと両方出来るので、机の上に一つ置いておくと便利です
コロコロ消しコロwithレターオープナー |
毎年、砺波市で開催されているチューリップフェアに久しぶりに行きました。朝早かったので近くの駐車場に車を駐車できましたが、平日にも関わらず県外ナンバー車が多く止まっていました。
全体を俯瞰するためチューリップタワーに登り、大花壇を見ると、100回記念の花絵が綺麗に見えました。さらに、花の大谷、水上花壇、五輪揚水水車とまわり、ふるさと広場の屋台で昼食をとりました。次に訪れたチューリップ四季彩館では、チューリップが咲き揃うワンダーガーデン、特別展示のロイヤルコレクション(皇室に献上した品種)が展示されていました。カフェーかくれ庵でチューリップソフトをいただきました。チューリップの原産地はトルコで、宮殿やモスクのタイルに使われていたことや、球根では富山県、切り花では新潟県、どちらも県花、と勉強にもなりました。
チュ-リップタワー | 大花壇 | 花の大谷 | 水上花壇 |
五輪揚水水車 | 水車の説明 | ふるさと広場 | チューリップ色彩館 |
ちゅーりっぷソフト | ワンダーガーデン | ロイヤルコレクション | トルコのチューリップ |