気象センサー&タイマーシールドの実装
自作工程のメモとして
27.Jun.2017
(更新:2018/09/06)
Edit by bluegriffon2.3.1
1.回路 |
2.シールドの実装 |
CW Keyer のケースの中にそのまま取り付けるだけです。
ただし、気象センサーは密閉状態ではおかしいので、後面のパネルに3.5Φの穴を開けています。
■ シールドを実装した状態の後面■ 後面パネルに開けた穴
気象センサー(AE-BME280)は、ブレッドボード上でテストしていたものを直付けしています。
もし、このように実装するならL型のピンコネクタを後面から刺せば、後面パネルにギリギリの位置まで近づけられたかもしれません。
■ CW Keyer に気象センサーと時刻を表示させた状態
試しに、失敗作の後面パネルに穴を開け、センサーの穴(塞いではいけない穴)が見えるようにしました。
ケース内の温度上昇が影響するか心配しましたが、温度等は後面パネルを外した状態と変わらなかったため良しとしました。
スピードのボリュームを左に回し切った時に、気象センサーと時刻を表示するようにしています。
右に少し回すと、k3ng CW Keyer に切り替わります。(キーヤーの画面も復活)
3.スケッチの工夫(k3ng CW Keyer と 気象センサー&タイマーの同居) |
// k3ng_keyer.ino ファイルの 1684 行に挿入 (Ver 2018/08/13) // 1684 #include "jlb_Insert_top.h" // // 時間調整はM1 M2 ボタンを使う(プラス1秒=M1・マイナス1秒=M2) // 注意:桁上がり桁下がりを考慮していないため、30秒前後の時に実行 // DS3231 を使用。ライブラリーは、DS1307 // k3ng CW Keyer と連携するときは、Keyerのloopエンドは、1538行目付近にある。 // // #include <Wire.h> // #include <TimeLib.h> #include <DS1307RTC.h> const char *monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; // スイッチサイエンス社のBME280サンプスケッチ #define BME280_ADDRESS 0x76 unsigned long int hum_raw, temp_raw, pres_raw; signed long int t_fine; uint16_t dig_T1; int16_t dig_T2; int16_t dig_T3; uint16_t dig_P1; int16_t dig_P2; int16_t dig_P3; int16_t dig_P4; int16_t dig_P5; int16_t dig_P6; int16_t dig_P7; int16_t dig_P8; int16_t dig_P9; int8_t dig_H1; int16_t dig_H2; int8_t dig_H3; int16_t dig_H4; int16_t dig_H5; int8_t dig_H6; tmElements_t tm; #define SerialOutFlag false // シリアル出力する場合は true 、出力しない false int b4sec; // 前回表示した秒値を格納。 int valarm = 0; // アラームセットに使用 int valdatetime = 0; // 時刻セットに使用 int cal_Minute; // アラームセットに使用 int w_sw, SSt, MM, UU; // 時刻セットに使用 int ST; // 時刻セットに使用 int MaxVal, MinVal; // 時刻セットに使用 // ------------------------------------------- |
// k3ng_keyer.ino ファイルの 1717 行に挿入 (Ver 2018/08/13) // 1717 #include "jlb_Insert_setup.h" // ------------------------------------------- pinMode(6, INPUT_PULLUP); pinMode(7, OUTPUT); pinMode(15, OUTPUT); //BME280初期設定 uint8_t osrs_t = 1; //Temperature oversampling x 1 uint8_t osrs_p = 1; //Pressure oversampling x 1 uint8_t osrs_h = 1; //Humidity oversampling x 1 uint8_t mode = 3; //Normal mode uint8_t t_sb = 5; //Tstandby 1000ms uint8_t filter = 0; //Filter off uint8_t spi3w_en = 0; //3-wire SPI Disable uint8_t ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode; uint8_t config_reg = (t_sb << 5) | (filter << 2) | spi3w_en; uint8_t ctrl_hum_reg = osrs_h; // I2CのSETUP Wire.begin(); writeReg(0xF2, ctrl_hum_reg); writeReg(0xF4, ctrl_meas_reg); writeReg(0xF5, config_reg); readTrim(); // ------------------------------------------- |
// k3ng_keyer.ino ファイルの 1724 行に挿入 (Ver 2018/08/13) // 1724 #include "jlb_Insert_loop.h" // ------------------------------------------- digitalWrite(15, digitalRead(6)); if (analogRead(0) < 5 ) // ■■スピードボリュームが最小ならタイマー温度表示の処理 { if (RTC.read(tm)) { // RTCから時間が読み出せれば◆ // COMボタンが2秒以上押されたら時刻調整に入る。 (2018/09/06) // 2月のうるう年も考慮済。 // // 通常状態で時間調整 プラス・マイナス1秒を M1+ M2- ボタンで調節する。 // アナログ入力の実測値:COM=0 ,M1=89 ,M2=166 ,M3=231 ( 0 --- 1023 ) // 注意:秒が30秒前後の時に実行すること // (簡易設定のため、桁上がり桁下がりを考慮せず) // // M3ボタンをアラームに使う (2017/10/31) // LCD 0行、10桁目に'"'文字を表示するとアラームのセットが有り SSt = analogRead(1); if (SSt < 40 ) { // COMボタン押された ST = 0; while (SSt < 40) { // COMボタンを放すまで待つ delay(100); ST++; SSt = analogRead(1); } if (ST > 20) { // 100mS X 20 = 2秒以上なら beep(); delay(50); // COMボタンなら 時間設定 (2018/09/06) lcd.clear(); lcd.setCursor(0, 0); lcd.print("M1:+ M2:- M3:Set"); lcd.setCursor(0, 1); lcd.print("Set YYYY "); // ----■■年の設定■■------- valdatetime = tm.Year + 1970; MaxVal = 2040; MinVal = 2018; YMDHMSset(); // ボタン操作による加減算処理へ tm.Year = CalendarYrToTm(valdatetime); RTC.write(tm); // 時間をDS3231 へセットする beep(); // うるう年を判定 if (((tm.Year + 2 ) % 4) == 0) { UU = 1; // うるう年 } else { UU = 0; // 通常年 } // --------------------------------------■■月の設定■■------- lcd.setCursor(0, 1); lcd.print("Set MM "); valdatetime = tm.Month; MaxVal = 12; MinVal = 1; YMDHMSset(); // ボタン操作による加減算処理へ tm.Month = valdatetime; RTC.write(tm); // 時間をDS3231 へセットする MM = valdatetime; // セットした月を記憶 beep(); // 大小の月を判定 switch (MM) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: MaxVal = 31; break; case 2: if (UU == 0) { MaxVal = 28; } else { MaxVal = 29; // うるう年 } break; case 4: case 6: case 9: case 11: MaxVal = 30; break; } // ---------------------------------------■■日の設定■■------- lcd.setCursor(0, 1); lcd.print("Set DD "); valdatetime = tm.Day; // MaxVal は月の設定部分で決定済み MinVal = 1; YMDHMSset(); // ボタン操作による加減算処理へ tm.Day = valdatetime; RTC.write(tm); // 時間をDS3231 へセットする beep(); // ---------------------------------------■■時の設定■■------- lcd.setCursor(0, 1); lcd.print("Set Hour "); valdatetime = tm.Hour; MaxVal = 23; MinVal = 0; YMDHMSset(); // ボタン操作による加減算処理へ tm.Hour = valdatetime; RTC.write(tm); // 時間をDS3231 へセットする beep(); // --------------------------------------■■分の設定■■------- lcd.setCursor(0, 1); lcd.print("Set Min. "); valdatetime = tm.Minute; MaxVal = 59; MinVal = 0; YMDHMSset(); // ボタン操作による加減算処理へ tm.Minute = valdatetime; RTC.write(tm); // 時間をDS3231 へセットする beep(); // ----------------------------------------■■秒の設定■■------- lcd.setCursor(0, 1); lcd.print("Set Sec. "); valdatetime = tm.Second; MaxVal = 59; MinVal = 0; YMDHMSset(); // ボタン操作による加減算処理へ tm.Second = valdatetime; RTC.write(tm); // 時間をDS3231 へセットする // ----------------------------------------■■設定終わり■■------- beep(); delay(300); beep(); lcd.clear(); } } if ((SSt > 70) && (SSt < 120)) { // M1ボタンなら +1秒 if (tm.Second > 57) { // 57秒より上なら3秒待ち(2018/09/26) beep(); delay(3000); beep(); } else { tm.Second++; // and configure the RTC with this info RTC.write(tm); // 時間をDS3231 へセットする beep(); } delay(200); } if ((SSt > 130) && (SSt < 195)) { // M2ボタンなら -1秒 if (tm.Second < 3) { // 3秒より下なら3秒待ち(2018/09/26) beep(); delay(3000); beep(); } else { tm.Second--; // and configure the RTC with this info RTC.write(tm); // 時間をDS3231 へセットする beep(); } delay(200); } if ((SSt > 200) && (SSt < 300)) { // M3ボタンなら アラーム選択 (2017/10/31) ST = 0; while ((SSt > 200) && (SSt < 300)) { // M3ボタンを放すまで待つ delay(100); ST++; SSt = analogRead(1); } if (ST > 20) { // 100mS X 20 = 2秒以上なら beep(); delay(50); lcd.clear(); lcd.setCursor(0, 1); lcd.print("Next=M1,Exit=M2 "); int w_sw = 1; while (w_sw) { SSt = analogRead(1); if ((SSt >70) && (SSt < 120)) { // M1ボタンなら while ((SSt > 70) && (SSt < 120)) { // M1ボタンを放すまで待つ delay(50); SSt = analogRead(1); } valarm++; if (valarm == 4) valarm = 0; } switch (valarm) { case 0: lcd.setCursor(0, 0); lcd.print("NON ALARM "); break; case 1: lcd.setCursor(0, 0); lcd.print("ALARM 1 Minute "); break; case 2: lcd.setCursor(0, 0); lcd.print("ALARM 10 Minute "); break; case 3: lcd.setCursor(0, 0); lcd.print("ALARM 15 Minute "); break; default: break; } // switch (valarm) end //delay(50); if ((SSt > 130) && (SSt < 195)) { // M2ボタンなら Exit while ((SSt > 130) && (SSt < 195)) { // M2ボタンを放すまで待つ delay(50); SSt = analogRead(1); } w_sw = 0; } } // while (w_sw) lcd.clear(); } } // アラーム処理 1分・10分・15分 毎にアラーム if (tm.Second == 0) { switch (valarm) { case 1: beep(); delay(300); break; case 2: cal_Minute = (tm.Minute + 1) % 10; if (cal_Minute == 1) { beep(); delay(300); } break; case 3: cal_Minute = (tm.Minute + 1) % 15; if (cal_Minute == 1) { beep(); delay(300); } break; default: break; } // switch } } else { // RTCから時間が読み出せ無ければ◆ if (RTC.chipPresent()) { lcd.setCursor(0, 0); lcd.print("run the SetTime"); } else { lcd.setCursor(0, 0); lcd.print("DS1307 read error!"); } delay(9000); } if (b4sec != tm.Second ) { // 取得した秒値が違えば、表示する b4sec = tm.Second; TempClockDisp(); } // delay(1000); } else { // ------------------------------------------- |
// k3ng_keyer.ino ファイルの 1867 行に挿入 (Ver 2018/08/13) // 1867 #include "jlb_Insert_loopend.h" } // loop end |
// k3ng_keyer.ino ファイルの 20806 行(最下行の下)にこのファイル全体を貼り付ける。 (Ver 2018/08/13) // 編集は jlb_paste_end.h ファイルにて行い、その都度貼り付けること。 void TempClockDisp() { // 温度・湿度・気圧・時間を表示 // アラームマークを表示する(2017/10/31) lcd.setCursor(10, 0); if (valarm > 0) lcd.write('"'); else lcd.write(' '); // LCD へ出力する。 // 時分秒 lcd.setCursor(11, 0); if (tm.Month < 10 ) lcd.write(' '); lcd.print(tm.Month); lcd.write('/'); lcd2digits(tm.Day); lcd.setCursor(8, 1); lcd2digits(tm.Hour); lcd.print(":"); lcd2digits(tm.Minute); lcd.print(":"); lcd2digits(tm.Second); /* // 年月日 表示エリヤの関係で使わない lcd.setCursor(0, 1); lcd.print(tmYearToCalendar(tm.Year)); lcd.print("/"); lcd2digits(tm.Month); lcd.print("/"); lcd2digits(tm.Day); lcd.print(" "); */ // 温度・湿度・気圧を表示 double temp_act = 0.0, press_act = 0.0, hum_act = 0.0; signed long int temp_cal; unsigned long int press_cal, hum_cal; int aa; readData(); temp_cal = calibration_T(temp_raw); press_cal = calibration_P(pres_raw); hum_cal = calibration_H(hum_raw); temp_act = (double)temp_cal / 100.0; press_act = (double)press_cal / 100.0; hum_act = (double)hum_cal / 1024.0; //初期値が小数点以下2桁のため Serial.print(XXXXX,1); ,1 で //小数点以下2桁目を四捨五入し、小数点以下1桁出力とする。 switch (tm.Second) { // ■■■ 10秒毎に表示 case 0: case 10: case 20: case 30: case 40: case 50: // I2C LCD に表示する //初期値が小数点以下2桁のため lcd.print(XXXXX,1); ,1 で //小数点以下2桁目を四捨五入し、小数点以下1桁出力とする。 lcd.setCursor(0, 0); temp_act = temp_act - 2.4; // ■温度センサーの出力が高すぎるため 2.4度引く。 lcd.print(temp_act, 1); lcd.print("c "); lcd.setCursor(0, 1); if (press_act < 999.95) lcd.print(" "); lcd.print(press_act, 1); lcd.print("h "); lcd.setCursor(7, 0); lcd.print(hum_act, 0); lcd.print("%"); } } // ■◆■■これ以降、タイマーDS3231関係の記述 // LCDへの出力を2桁にする print2digits を参照して追加。 void lcd2digits(int number) { if (number >= 0 && number < 10) { lcd.print('0'); } lcd.print(number); } void YMDHMSset() // 時間調整用のM1,M2,M3ボタン操作部分(2018/09/07) { while (1) { SSt = analogRead(1); if ((SSt > 70) && (SSt < 120)) { // M1ボタンなら while ((SSt > 70) && (SSt < 120)) { // M1ボタンを放すまで待つ delay(50); SSt = analogRead(1); } valdatetime++; if (valdatetime > MaxVal) valdatetime = MinVal; } SSt = analogRead(1); if ((SSt > 130) && (SSt < 195)) { // M2ボタンなら while ((SSt > 130) && (SSt < 195)) { // M2ボタンを放すまで待つ delay(50); SSt = analogRead(1); } valdatetime--; if (valdatetime < MinVal) valdatetime = MaxVal; } lcd.setCursor(10, 1); if (valdatetime < 10) { lcd.write('0'); } // *if の終了位置修正(2019/02/09) lcd.print(valdatetime); //delay(50); if ((SSt > 200) && (SSt < 300)) { // M3ボタンなら Exit while ((SSt > 200) && (SSt < 300)) { // M3ボタンを放すまで待つ delay(50); SSt = analogRead(1); } return; } } // while END } // ■◆■■ここまで、タイマーDS3231関係の記述 //////////////////////////////////////////////////////////////// // ■■■これ以降、BME280 温度・湿度・気圧関係の記述 void readTrim() // BME280の処理 { uint8_t data[32], i = 0; // Fix 2014/04/06 Wire.beginTransmission(BME280_ADDRESS); Wire.write(0x88); Wire.endTransmission(); Wire.requestFrom(BME280_ADDRESS, 24); // Fix 2014/04/06 while (Wire.available()) { data[i] = Wire.read(); i++; } Wire.beginTransmission(BME280_ADDRESS); // Add 2014/04/06 Wire.write(0xA1); // Add 2014/04/06 Wire.endTransmission(); // Add 2014/04/06 Wire.requestFrom(BME280_ADDRESS, 1); // Add 2014/04/06 data[i] = Wire.read(); // Add 2014/04/06 i++; // Add 2014/04/06 Wire.beginTransmission(BME280_ADDRESS); Wire.write(0xE1); Wire.endTransmission(); Wire.requestFrom(BME280_ADDRESS, 7); // Fix 2014/04/06 while (Wire.available()) { data[i] = Wire.read(); i++; } dig_T1 = (data[1] << 8) | data[0]; dig_T2 = (data[3] << 8) | data[2]; dig_T3 = (data[5] << 8) | data[4]; dig_P1 = (data[7] << 8) | data[6]; dig_P2 = (data[9] << 8) | data[8]; dig_P3 = (data[11] << 8) | data[10]; dig_P4 = (data[13] << 8) | data[12]; dig_P5 = (data[15] << 8) | data[14]; dig_P6 = (data[17] << 8) | data[16]; dig_P7 = (data[19] << 8) | data[18]; dig_P8 = (data[21] << 8) | data[20]; dig_P9 = (data[23] << 8) | data[22]; dig_H1 = data[24]; dig_H2 = (data[26] << 8) | data[25]; dig_H3 = data[27]; dig_H4 = (data[28] << 4) | (0x0F & data[29]); dig_H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F); // Fix 2014/04/06 dig_H6 = data[31]; // Fix 2014/04/06 } void writeReg(uint8_t reg_address, uint8_t data) { Wire.beginTransmission(BME280_ADDRESS); Wire.write(reg_address); Wire.write(data); Wire.endTransmission(); } void readData() { int i = 0; uint32_t data[8]; Wire.beginTransmission(BME280_ADDRESS); Wire.write(0xF7); Wire.endTransmission(); Wire.requestFrom(BME280_ADDRESS, 8); while (Wire.available()) { data[i] = Wire.read(); i++; } pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4); temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4); hum_raw = (data[6] << 8) | data[7]; } signed long int calibration_T(signed long int adc_T) { signed long int var1, var2, T; var1 = ((((adc_T >> 3) - ((signed long int)dig_T1 << 1))) * ((signed long int)dig_T2)) >> 11; var2 = (((((adc_T >> 4) - ((signed long int)dig_T1)) * ((adc_T >> 4) - ((signed long int)dig_T1))) >> 12) * ((signed long int)dig_T3)) >> 14; t_fine = var1 + var2; T = (t_fine * 5 + 128) >> 8; return T; } unsigned long int calibration_P(signed long int adc_P) { signed long int var1, var2; unsigned long int P; var1 = (((signed long int)t_fine) >> 1) - (signed long int)64000; var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((signed long int)dig_P6); var2 = var2 + ((var1 * ((signed long int)dig_P5)) << 1); var2 = (var2 >> 2) + (((signed long int)dig_P4) << 16); var1 = (((dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + ((((signed long int)dig_P2) * var1) >> 1)) >> 18; var1 = ((((32768 + var1)) * ((signed long int)dig_P1)) >> 15); if (var1 == 0) { return 0; } P = (((unsigned long int)(((signed long int)1048576) - adc_P) - (var2 >> 12))) * 3125; if (P < 0x80000000) { P = (P << 1) / ((unsigned long int) var1); } else { P = (P / (unsigned long int)var1) * 2; } var1 = (((signed long int)dig_P9) * ((signed long int)(((P >> 3) * (P >> 3)) >> 13))) >> 12; var2 = (((signed long int)(P >> 2)) * ((signed long int)dig_P8)) >> 13; P = (unsigned long int)((signed long int)P + ((var1 + var2 + dig_P7) >> 4)); return P; } unsigned long int calibration_H(signed long int adc_H) { signed long int v_x1; v_x1 = (t_fine - ((signed long int)76800)); v_x1 = (((((adc_H << 14) - (((signed long int)dig_H4) << 20) - (((signed long int)dig_H5) * v_x1)) + ((signed long int)16384)) >> 15) * (((((((v_x1 * ((signed long int)dig_H6)) >> 10) * (((v_x1 * ((signed long int)dig_H3)) >> 11) + ((signed long int) 32768))) >> 10) + (( signed long int)2097152)) * ((signed long int) dig_H2) + 8192) >> 14)); v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((signed long int)dig_H1)) >> 4)); v_x1 = (v_x1 < 0 ? 0 : v_x1); v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1); return (unsigned long int)(v_x1 >> 12); // ■■■ここまで、温度・湿度・気圧関係の記述 ///////////////////////////////////////////////////////////////// } |
9.その他気づいたこと |
99.タイマーモジュールのソケット処理と非充電対応(2018/09/06) |