//WBGT(OLED使用) // // WBGT指標とは // WBGT(湿球黒球温度)とは,人体の熱収支に影響の大きい湿度,輻射熱,気温の3つを取り入れた指標で, // 乾球温度,湿球温度,黒球温度の値を使って計算する // ※WBGT(湿球黒球温度)の算出方法 // 屋外:WBGT = 0.7×湿球温度+0.2×黒球温度+0.1×乾球温度 // 屋内:WBGT = 0.7×湿球温度+0.3×黒球温度 // // 本プログラムではWBGT値を,気温・湿度から推定値で求める // #include <Arduino.h> #include <Wire.h> #include <avr/pgmspace.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include <avr/wdt.h> #include <U8glib.h> #include <Adafruit_SHT31.h> //#define DEBUG true char version[] = "2020.07.23 Ver.1.00"; #define CTRL_BTN PD2 //Control button #define BTRY_PIN PC0 //battery voltage pin #define SHT31_ADDRESS 0x44 //Set to 0x45 for alternate i2c addr U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE);//Just for 0.91 h(128*32) //0x3c Adafruit_SHT31 sht31 = Adafruit_SHT31(); // NP / no problem //20以下:1.ほぼ安全 safety //21~25:2.注意 attention //25~28:3.警戒 warning //28~31:4.厳重警戒 danger / dangerous //31以上:5.危険 critical // : deadly const byte wbgt_t[20][17] = { /* 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 */ /*21*/ { 15, 15, 16, 16, 17, 17, 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24 }, /*22*/ { 15, 16, 17, 17, 18, 18, 19, 19, 20, 21, 21, 22, 22, 23, 24, 24, 25 }, /*23*/ { 16, 17, 17, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26 }, /*24*/ { 17, 18, 18, 19, 19, 20, 21, 21, 22, 22, 23, 24, 24, 25, 26, 26, 27 }, /*25*/ { 18, 18, 19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28 }, /*26*/ { 18, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25, 26, 26, 27, 28, 28, 29 }, /*27*/ { 19, 20, 21, 21, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28, 29, 29, 30 }, /*28*/ { 20, 21, 21, 22, 23, 23, 24, 25, 25, 26, 27, 28, 28, 29, 30, 30, 31 }, /*29*/ { 21, 21, 22, 23, 24, 24, 25, 26, 26, 27, 28, 29, 29, 30, 31, 31, 32 }, /*30*/ { 21, 22, 23, 24, 24, 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33 }, /*31*/ { 22, 23, 24, 24, 25, 26, 27, 27, 28, 29, 30, 30, 31, 32, 33, 33, 34 }, /*32*/ { 23, 24, 25, 25, 26, 27, 28, 28, 29, 30, 31, 31, 32, 33, 34, 34, 35 }, /*33*/ { 24, 25, 25, 26, 27, 28, 28, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36 }, /*34*/ { 25, 25, 26, 27, 28, 29, 29, 30, 31, 32, 33, 33, 34, 35, 36, 37, 37 }, /*35*/ { 25, 26, 27, 28, 29, 29, 30, 31, 32, 33, 33, 34, 35, 36, 37, 38, 38 }, /*36*/ { 26, 27, 28, 29, 29, 30, 31, 32, 33, 34, 34, 35, 36, 37, 38, 39, 39 }, /*37*/ { 27, 28, 29, 29, 30, 31, 32, 33, 34, 35, 35, 36, 37, 38, 39, 40, 41 }, /*38*/ { 28, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 37, 38, 39, 40, 41, 42 }, /*39*/ { 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 37, 38, 39, 40, 41, 42, 43 }, /*40*/ { 29, 30, 31, 32, 33, 34, 35, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44 } }; struct history { short temp; //気温*10 short humi; //湿度*10 }; #define SECPMS 1000 //秒/ms #define T100MS (SECPMS/10) //100ms #define T10MS (SECPMS/100) //10ms #define T60S 60000 //60秒 #define BTN_INT_ON (EIMSK = (1<0); } void loop() { bool info_mdf = false; #ifdef DEBUG Serial.println("loop start"); #endif u8g.sleepOn(); sleep_enable(); BTN_INT_ON; for(;;) { WDT_start(); sleep_mode(); //ここでスリープに入る WDT_stop(); if(btn_intr) { btn_intr = false; sleep_disable(); u8g.sleepOff(); drawOLED(0); long ms = SECPMS * 5; //モード変更時間をセット while(!BTN_RELEASE) { delay(T10MS); if((ms -= T10MS) <= 0) { //情報表示モード infoOLED(); //次にボタンを押下するまでモードは終了しない //前のボタンリリースまで待ち while(!BTN_RELEASE) delay(T10MS); BTN_INT_ON; do { infoOLED(); localDelay(SECPMS); } while(!btn_intr); btn_intr = false; //ボタンリリースまで待ち while(!BTN_RELEASE) delay(T10MS); info_mdf = true; break; } } BTN_INT_ON; if(!info_mdf) { //5秒間表示(1秒単位で更新) int log = 0; for(int tt = 0; tt < 5; tt++) { if(btn_intr) { btn_intr = false; #ifdef DEBUG Serial.print("press within 5 seconds. log := "); Serial.println(log); #endif while(!BTN_RELEASE) delay(T10MS); BTN_INT_ON; if((log += 6) > LOG_COUNT) log -= 6; tt = 0; //5秒をリセット } else { collection(false); } drawOLED(log); localDelay(SECPMS); } } else { info_mdf = false; } clearOLED(); u8g.sleepOn(); sleep_enable(); } if(wdt_count >= 15*5) { //8秒 * 15 * 5 = 10分 //10分間隔でロギング #ifdef DEBUG Serial.println("collect data every 10 minutes"); #endif collection(true); wdt_count = 0; } } } // log := * 10 分前 void drawOLED(int log) { int t, h, wbgt, lv; char ls[12], ss[8], ts[8], hs[8], ws[8]; #ifdef DEBUG Serial.println("OLED draw"); // Serial.print(reg_temp); // Serial.print("(*10)'C, "); // Serial.print(reg_humi); // Serial.println("(*10)%"); #endif //表示データ取得(現在値か,ログか) // t10 := temp * 10, h10 := humd * 10 int t10 = log? hist_log[log - 1].temp: reg_temp; int h10 = log? hist_log[log - 1].humi: reg_humi; //表示データチェック if(h10 != 0) { //四捨五入してWBGTにする t = (t10 + 5) / 10; t = (t > 40)? 40: t; //MAX40(40℃以上の場合は未対応) h = (h10 + 5) / 10; h = (h > 100)? 100: h; //MAX100 wbgt = wbgt_t[t - 21][(h - 20) / 5]; sprintf(ws, "%d", wbgt); //WBGT レベル算出 if(wbgt <= 20) lv = 0; //1 else if(wbgt <= 25) lv = 1; //2 else if(wbgt <= 28) lv = 2; //3 else if(wbgt <= 31) lv = 3; //4 else lv = 4; //5 if(lv == 0) { sprintf(ss, "LOW"); } else if(lv == 4) { sprintf(ss, "MAX"); } else { sprintf(ss, "Lv.%d", lv); } //WBGT タイトル表示 if(log == 0) { sprintf(ls, "WBGT"); } else { //ログ表示 sprintf(ls, "%d hour ago", log/6); } } else { //湿度がの場合はログの記録なしとして現在表示 t10 = reg_temp; h10 = reg_humi; lv = 0; sprintf(ws, "--"); sprintf(ss, ""); sprintf(ls, "NO DATA"); } sprintf(ts, "%d.%d'C", t10/10, t10%10); sprintf(hs, "%d.%d%%", h10/10, h10%10); // picture loop u8g.firstPage(); do { //LEVEL Graph Display for(int n = 1; n <= lv; n++) { u8g.drawBox(58, 32 - (n * 5 + (n - 1)), 12, 5); } //TITLE u8g.setFont(u8g_font_timB08); u8g.drawStr(0, 7, ls); u8g.drawStr(54, 7, ss); //WBGT u8g.setFont(u8g_font_ncenB24n); u8g.drawStr(8, 32, ws); //u8g.setFont(u8g_font_freedoomr25n); //u8g.drawStr(8, 34, ws); //u8g.setPrintPos(16, 30); u8g.print(ws); //Temperature, Humidity u8g.setFont(u8g_font_helvB14r); u8g.drawStr(76, 14, ts); //u8g.setPrintPos(64, 15); u8g.print(ts); u8g.drawStr(76, 32, hs); //u8g.setPrintPos(64, 32); u8g.print(hs); } while(u8g.nextPage()); } void clearOLED() { #ifdef DEBUG Serial.println("OLED clear"); #endif u8g.firstPage(); while(u8g.nextPage()); } //debug用内部情報表示 //128x32なので8x8で16列x4行表示(8, 16, 24, 32) void infoOLED() { char lstr[4][32]; //logging count int logcnt = 0; for(int n = 0; n < LOG_COUNT; n++) { if(hist_log[n].humi != 0) logcnt++; } //battery voltage long val = analogRead(BTRY_PIN); long v10 = val * 11 * 57 / 1024 / 10; //val * 11 / 1024 * 57 / 10 sprintf(lstr[0], "%s", version); sprintf(lstr[1], "log count := %d", logcnt); sprintf(lstr[2], "battery := %d.%dV(%d)", (int)v10/10, (int)v10%10, (int)val); sprintf(lstr[3], ""); u8g.setFont(u8g_font_timB08); u8g.firstPage(); do { for(int n = 0; n < 4; n++) { u8g.drawStr(0, n * 8 + 8, lstr[n]); } } while(u8g.nextPage()); }