温湿度測定するぞ(2)

前回に続き今回は温湿度測定器の製作と測定です。

使用するモジュール

  • ESP32(本体)
    • 36ピンですが、USBケーブルを繋ぐだけでArduinoで開発出来ます。
    • 以前使用したログを ここ にまとめています。参照下さい。
  • AM2320(温湿度素子)
    • I2C接続の温湿度測定素子です。
    • 以前使用したログを ここ にまとめています。参照下さい。
  • AQM1248A(LCD表示器)
    • I2C接続のLCD表示器です。解像度 48×128ドット。
    • 以前使用したログを ここ にまとめています。参照下さい。
  • SDカード(データ保存用)
    • 測定データを保存します。
    • 以前使用したログを ここ にまとめています。参照下さい。
  • RTC DS3231(測定時間カウント用)
    • 測定時間カウント用に使用します。
    • ESP32で時間のカウントも出来ますがRTCを使用した方が設定が簡単
    • 以前使用したログを ここ にまとめています。参照下さい。
  • その他
    • 基板
    • 配線コード
    • ヘッダーピン
    • など

回路と実装

これらの素子を組み合わせて下記の様な回路を作製し実装しました。

  • AM2320(温湿度素子)は基板上にある2個のI2C用コネクター(1個は予備)に接続して使用。
  • ESP32上のUSBコネクタにケーブルを繋げばプログラムを即開発出来ます。
  • この基板上の素子の全ての電源はUSBコネクターから供給されています。

プログラムの概要

今回は下記の様なプログラムを目指します。

  • ESP32でWebサーバーを立ち上げる。
  • ローカルネットを通してブラウザを使用しサーバーのHPにアクセス。
  • HPを操作して温湿度を測定し、データを得る。
  1. ESP32のWebサーバーにホストネームでアクセスします。ホストメームは、esp32monitor.local です。
  2. この欄に現在の時間が表示されます。
    • 最初はDS3231が設定されていないのでそれなりの表示になります。
    • 下記5の”Set Time”ボタンで時刻を設定出来ます。
    • ボタン電池でバックアップされてれば時間は保存されます。
    • バックアップされていなければ、時間を毎回設定する必要が有り。
  3. この欄に、AM2320からの温度と湿度の測定値が表示されます。
  4. 測定開始後、行われた測定回数が表示されます。
  5. 現在の時間を設定します。
    • ボタンを押すと時間設定用の画面が表示されます。
  6. データの更新ボタン
    • このアプリはWebのHPなのでこのボタンを押して最新のデータを取得します。
  7. 測定間隔設定
    • 温湿度の測定間隔をこの欄で設定します。
    • 時間、分、秒 単位で設定出来ます。
  8. 測定開始ボタン
    • 設定された間隔で温湿度を測定しSDカードに保存します。
  9. 測定停止ボタン
    • 測定を停止します。
  10. データのダウンロードボタン
    • データはSDカードに保存されたデータをダウンロード出来ます。
    • データの形式は 測定回数、時間、温度、湿度の順(上図参照)

ソース一覧

ソースは、下記の構成になっています。

  • ESP32関係ソフト → ESP32に焼く
    • Monitor_00.ino   
    • AQM1248A.cpp /.h
    • AM2320.cpp /.h
  • Web画面用ソフト → SDカードに保存
    • menu.html
    • menu.css
    • Set_Time.html

メインプログラム Monitor_00.ino

これがメインのプログラムです。プログラムの41,2行にルーターのSSIとPasswordを入力する箇所が有ります。自分の環境に有った値を指定下さい。

測定動作を簡単に説明すると、

  1. HP画面で測定間隔を設定後、Startボタンを押す。
  2. サーバはHPから送られた設定時間を保存し測定動作を開始する。
  3. AM2320を使って温湿度のデータを測定する。
  4. 測定されたデータをSDカードに保存し、値をLCDに表示する。
  5. DS3231に次の測定時間を設定する。
  6. DS2321が割り込み信号を発生するまでESP32は空ループを行う。
  7. 割り込み信号が発生すると、上記、”3”に移動して測定を行う。
  8. Stopボタンを押すと測定を終了する。

測定が始まるとLCDに温度、湿度、測定回数が表示されます。

Monitor_00.ino

#include "Arduino.h"
#include "SD.h"                          
#include <Wire.h>
#include <WebServer.h>
#include <ESPmDNS.h>

#include "AM2320.h"
#include "AQM1248A.h"

#include <DS3231.h>

// SD Card select PIN
#define sd_ss             5
/*
#define sd_sck            18
#define sd_mosi           23
#define sd_miso           19
*/

// External Interrupt
// Only use GPIO:0,2,4,12-15,25-27,32-39
#define RTC_INT           GPIO_NUM_4

// DS3231 Flg 
#define every_s         0x0f    //Alarm once per second
#define match_s         0x0e    //Alarm when seconds match
#define match_ms        0x0c    //Alarm when min, sec match
#define match_hms       0x08    //Alarm when hour, min, sec match
#define match_dhms      0x00    //Alarm when date, h, m, s match
#define match_whms      0x00    //Alarm when DoW, h, m, s match
#define alarm1          1
#define alarm2          2

int bootCount = 0;
int st_h = 0;
int st_m = 0;
int st_s = 0;

WebServer server(80);

const char *SSID = "your_SSID";
const char *PASSWORD = "your_Password";

DS3231 Clock;
byte tm_data[10];           //Year,Month,Date,DoW,Hour,Minute,Secon
bool Century,h12,PM;
int int_flg = 0;

void Handle_int()
{
    int_flg = 1;
}

void setup() 
{
  File dataFile;

    Wire.begin();
    SPI.begin();
    SD.begin(sd_ss);

    Serial.begin(115200);

    init_DS3231();

    pinMode(RTC_INT, INPUT_PULLUP);

    Serial.println("Connecting to WiFi");
    WiFi.disconnect(true);
    WiFi.softAPdisconnect(true);
    delay(500);

    WiFi.mode(WIFI_STA);
    WiFi.begin(SSID, PASSWORD);
    delay(1000);

    // Try forever
    while (WiFi.status() != WL_CONNECTED) {
      Serial.println("...Connecting to WiFi");
      delay(1000);
    }
    Serial.println("Connected");
    Serial.println(SSID);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());

    if (MDNS.begin("esp32monitor")) {
        Serial.println("MDNS responder started");
    }

    server.on("/", handleRoot);
    server.onNotFound(handleWebRequests); 
    server.begin();
    Serial.println("HTTP server started");

    Init_LCD();
    LCD_CLS(0);
    LCD_Print_Str(0,0,"LCD OK",1,2);

}

void loop() 
{
  server.handleClient();

  if(int_flg) measure_data();

}

void handleRoot() {
  String buf,cmd;
  int a,b,fl,fl_sleep;
  File dataFile;
  float h_data[2];
  uint8_t para[7];

    fl=1; fl_sleep=0;
    cmd=server.argName(0);
    switch(cmd.toInt())
    {
      case 1:   // Update Data
                break;
                
      case 99:  // Back or Cansel
                break;      
      
      case 2:   //Set TIME (send url data)
                buf=server.arg("2");
                get_h_m_s(buf);
                
                dataFile = SD.open("/Set_Time.html", FILE_READ);
                server.streamFile(dataFile,"text/html");
                dataFile.close();
                fl=0;
                break;

      case 3:   // Stop Logger
                detachInterrupt(RTC_INT);
                Clock.turnOffAlarm(alarm1);
                bootCount = 0;
                int_flg = 0;
                Serial.println("Stop Monitoring");

                break;
                
      case 4:   // Start Logger
                buf=server.arg("4");
                get_h_m_s(buf);
                Serial.println("Start Monitoring");
                Serial.println("buf:" + buf);
                dataFile = SD.open("/data0.txt", FILE_WRITE);
                dataFile.close();
                dataFile = SD.open("/data1.txt", FILE_WRITE);
                dataFile.close();
                
                bootCount = 0;
                measure_data();
                attachInterrupt(RTC_INT, Handle_int, FALLING);
                
                break;
                
      case 80:  // Send parameter
                buf=get_current_time() + ",";
                AM2320(h_data);
                buf += ("Temp:" + String(h_data[1]) + "'c / Humi:" + String(h_data[0]) +"%,");
                buf += (String(bootCount) + ",");
                disp_temp(h_data);
                buf += (String(st_h) + "," + String(st_m) + "," + String(st_s) + ",");
                server.send(200, "text/plain", buf);
                fl=0;

                Serial.println("buf:" + buf);

                break;
              
      case 81:  // Send RTC parameter
                get_DS3231(tm_data);
                buf = "";
                for(a = 0; a < 7; a ++) buf += (String(tm_data[a]) + ",");
                server.send(200, "text/plain", buf);
                fl=0;
                break;
              
      case 100: // Set TIME
                buf=server.arg("100");
                b=0;
                for(a=0; a<7; a++)
                {
                    cmd="";
                    while( buf[b] != ',') 
                    {
                        cmd += buf[b];
                        b ++;
                    }
                    tm_data[a]=cmd.toInt(); b ++; 
                }

                set_DS3231(tm_data);
                break;
    }
    
    if(fl)
    {
      dataFile = SD.open("/menu.html", FILE_READ);
      server.streamFile(dataFile,"text/html");
      dataFile.close();
    }
}

void disp_temp(float * th_data)
{
    char c_buf[50];
    String buf; 
    
    LCD_CLS(0);
    buf = "T:" + String(th_data[1]) + "'c ";
    buf.toCharArray(c_buf, 50);
    LCD_Print_Str(0,0,c_buf,1,2);
    
    buf = "t:" + String(th_data[0]) + "'c ";
    buf.toCharArray(c_buf, 50);
    LCD_Print_Str(0,16,c_buf,1,2);

    buf = "N:" + String(bootCount) ;
    buf.toCharArray(c_buf, 50);
    LCD_Print_Str(0,32,c_buf,1,2);

}

void set_next(byte cntl)
{
  int a,b,c;
  
    get_DS3231(tm_data);
    a = tm_data[6] + st_s;
    b = c = 0;
    if(a > 59) 
    {
        a -= 60;
        b ++;
    }
    b += (tm_data[5] + st_m);
    c = tm_data[4] + st_h;
    if(b > 59) 
    {
        b -= 60;
        c ++;
    }
    if(c > 23) c -= 24;
    
    Clock.setA1Time(0, c, b, a, cntl, 0, 0, 0);
}

void init_DS3231()
{
    Clock.turnOffAlarm(alarm1);               // Disables alarm 1 or 2 (default is 2 if Alarm != 1);
    Clock.turnOffAlarm(alarm2);               // Disables alarm 1 or 2 (default is 2 if Alarm != 1);
    Clock.setClockMode(0);
}

void get_h_m_s(String str)
{
  int a;
  String cmd;
              
    st_h = str.toInt();
    
    a = 0; 
    while(str[a] != ',') a ++;
    a ++;
    cmd = str.substring(a);
    st_m = cmd.toInt();
    
    while(str[a] != ',') a ++;
    a ++;
    cmd = str.substring(a);
    st_s = cmd.toInt();
}

//#define CLOCK_ADDRESS 0x68
void set_DS3231(byte* tm_data)
{
    Clock.setYear(tm_data[0]);          //Set the year (Last two digits of the year)
    Clock.setMonth(tm_data[1]);                
    Clock.setDate(tm_data[2]);         
    Clock.setDoW(tm_data[3]);           //Set the day of the week  SUN=0 / SAT=6
    Clock.setHour(tm_data[4]);          
    Clock.setMinute(tm_data[5]);        
    Clock.setSecond(tm_data[6]);       
}

void get_DS3231(byte* tm_data)
{
  bool Century=false;
  bool h12;
  bool PM;
    
    tm_data[0] = Clock.getYear();
    tm_data[1] = Clock.getMonth(Century);
    tm_data[2] = Clock.getDate();
    tm_data[3] = Clock.getDoW();
    tm_data[4] = Clock.getHour(h12,PM);
    tm_data[5] = Clock.getMinute();
    tm_data[6] = Clock.getSecond();
}

void measure_data()
{
  String buf;
  File dataFile;
  float h_data[2],t_temp;
  
    buf= String(bootCount) + ",";
    buf += get_current_time() + ",";
    AM2320(h_data);
    buf += ("T/H," + String(h_data[1]) + "," + String(h_data[0]) +",");
    Serial.println("N:" + String(bootCount) + "/T:" + String(h_data[1]) + "/H:" + String(h_data[0]) );

    disp_temp(h_data);
                
    dataFile = SD.open("/data0.txt", FILE_APPEND);
    dataFile.println(buf);
    dataFile.close();

    bootCount ++;

    set_next(match_hms);
    Clock.checkIfAlarm(alarm1);
    Clock.turnOnAlarm(alarm1);

    int_flg = 0;
}

String digit_2(byte num)
{
  String str;

    if(num < 10) str = ("0" + String(num));
    else str = String(num);

    return (str);
}

String get_current_time()
{
  uint8_t a;
  String buf;
  String w_data[8]={"Sun","Mon","Tue","Wen","Thu","Fri","Sat"};

    get_DS3231(tm_data);
    buf=String(tm_data[0] + 2000);
    buf += ("/" + digit_2(tm_data[1]));
    buf += ("/" + digit_2(tm_data[2]));
    buf += ("/" + w_data[tm_data[3]] + "/");

    for(a = 4; a < 7; a ++)
    {
        buf += digit_2(tm_data[a]);
        if(a != 6) buf += ":";
    }

    return(buf);    
}

void handleWebRequests()
{
  String dataType = "text/plain";
  String path;
  File dataFile;
   
    path = server.uri();
    if(path.endsWith(".txt")) dataType = "text/plain";
    else if(path.endsWith(".css")) dataType = "text/css";
    else if(path.endsWith(".html")) dataType = "text/html";
    delay(5);

    dataFile = SD.open(path.c_str(), "r");
    server.streamFile(dataFile, dataType);
    dataFile.close();
    delay(5);
}

以降、各素子用のプログラムです。

am2320.cpp

#include "AM2320.h"

void AM2320(float * h_t_data) 
{
 uint8_t data[8];
 int flg;

  Wire.beginTransmission(AM2320_ADR);
  Wire.endTransmission();
  delay(10);

  Wire.beginTransmission(AM2320_ADR);
  Wire.write(0x03);         
  Wire.write(0x00);         
  Wire.write(0x04);            
  Wire.endTransmission();
  delay(10);

  Wire.requestFrom(AM2320_ADR,8); 
  if (Wire.available() >= 8) 
  {
    for (uint8_t i=0; i<8; i++) data[i] = Wire.read();

    h_t_data[0] = ((float)((data[2] << 8) | data[3]))/10;
     
    flg = 1;
    if(data[4] & 0x80) flg = -1;
    data[4] &= 0x7f;
    h_t_data[1] = ((float)((data[4] <<8 ) | data[5]))/10 * flg; 
  }
}
am2320.h

#include <Wire.h>

// AM2320 I2C Address
#define AM2320_ADR    0x5c        // FIX

//------------------------------------------------
// Get Humidity & Temperature 
// float * h_t_data:  Pointer to array of floating point variables
//                    1st: Humidity  2nd:Temperature
//------------------------------------------------
void AM2320(float * h_t_data) ;
aqm1248a.cpp

#include "Arduino.h"
#include "AQM1248A.h"

char v_buf[128][6];

void Init_LCD()
{
    pinMode(LCD_CS, OUTPUT);     
    digitalWrite(LCD_CS,HIGH);
    
    pinMode(LCD_RS, OUTPUT);     
    digitalWrite(LCD_RS,HIGH);

    digitalWrite(LCD_CS,LOW);
    digitalWrite(LCD_RS,LOW);
    
    SPI.transfer(0xAE);
    SPI.transfer(0xA0);
    SPI.transfer(0xC8);
    SPI.transfer(0xA3);
    
    SPI.transfer(0x2C);
    delay(50);
    SPI.transfer(0x2E);
    delay(50);
   
    SPI.transfer(0x2F);
    
    SPI.transfer(0x23);
    SPI.transfer(0x81);
    SPI.transfer(0x1C);

    SPI.transfer(0xA4);
    SPI.transfer(0x40);
    SPI.transfer(0xA6);
    SPI.transfer(0xAF);
     
    digitalWrite(LCD_CS,HIGH);
}

void LCD_CLS(char data)
{
    int a,b;
    
    digitalWrite(LCD_CS,LOW);
    for(b=0; b<6; b ++)
    {
        digitalWrite(LCD_RS,LOW);
        SPI.transfer(0xB0+b);
        SPI.transfer(0x10);
        SPI.transfer(0x00);
    
        digitalWrite(LCD_RS,HIGH);   
        for(a=0; a<128; a++)
        {
            SPI.transfer(data);
            v_buf[a][b]=data;
        }
    }
    digitalWrite(LCD_CS,HIGH);
}

//----------------------------------------------------
//  点の描画 
//  int x_data  X positon   0 -> 128    
//  int x_data  Y positon   0 -> 48 
//  int cl      color 0: white  1:black 
//----------------------------------------------------
void LCD_PSET(int x_data, int y_data, int cl)
{

    int a,b;
    char c;
 
//  y_data
    a=y_data >> 3; b= y_data & 0x07;
    c=0x1; 
    while(b)
    {
        c <<= 1; b --; 
    }
    
    if(cl) v_buf[x_data][a] |= c;
    else 
    {
        c = ~c; v_buf[x_data][a] &= c;
    }

    digitalWrite(LCD_CS,LOW);
    digitalWrite(LCD_RS,LOW);    
    SPI.transfer(0xB0+a);
    c=x_data >> 4; c |= 0x10;
    SPI.transfer(c);
    c=x_data & 0xf;
    SPI.transfer(c);
    digitalWrite(LCD_RS,HIGH);
    SPI.transfer(v_buf[x_data][a]);
    digitalWrite(LCD_CS,HIGH);
}

//----------------------------------------------------
//  Fontの描画 
//  int x_data  X positon   0 -> 128    
//  int y_data  Y positon   0 -> 48
//  char c_data Data
//  int cl      color 0: white  1:black
//----------------------------------------------------
void LCD_Print_C(int x_data, int y_data, char c_data, int cl, int m_fl)
{
    int a,b,c,d,e,f;
    char s;

    a = c_data - 0x20; 
    for(b=0; b<5; b ++)
    {
        s=0x1;
        for(c=0; c<8; c ++)
        {
            d=0;
            if(Font[a][b] & s) d=1;
            if(cl == 0)
            {
                if(d) d=0;
                else d=1;
            }
            for(e = 0; e < m_fl; e ++)
                for(f = 0; f < m_fl; f ++)
                    LCD_PSET(x_data + f,y_data + c * m_fl + e,d);
            s <<= 1; 
        }
        x_data += m_fl;
    }
    for(c=0; c<8; c ++)
    {
        d=0;
        if(cl == 0) d=1; 
        LCD_PSET(x_data,y_data + c,d);        
    }
}

//----------------------------------------------------
//  Strtの描画 
//  int x_data  X positon   0 -> 128    
//  int y_data  Y positon   0 -> 48
//  char *c_data Data
//  int cl      color 0: white  1:black
//----------------------------------------------------
void LCD_Print_Str(int x_data, int y_data, char *c_data, int cl, int m_fl)
{
    int a;
    a = strlen(c_data);
    while(a)
    {
        if(*c_data == 0xef)
        {
            c_data += 2;
            a -= 2;
        }
        LCD_Print_C(x_data,y_data,*c_data,cl,m_fl);
//        Serial.println(*c_data,HEX);
        a --; x_data += (6 *m_fl); c_data ++;
    }
}

//----------------------------------------------------
//   直線描画関数
//
//  int x0      start x
//  int y0      start y
//  int x1      end x
//  int y1      end y
//  int cl      color 0: white  1:black
//----------------------------------------------------
#define abs(a)  (((a)>0) ? (a) : -(a))
void LCD_LINE(int x0, int y0, int x1, int y1, int cl)
{
    int steep, t;
    int deltax, deltay, error;
    int x, y;
    int ystep;
    
    /// 差分の大きいほうを求める
    steep = (abs(y1 - y0) > abs(x1 - x0));
    /// x、yの入れ替え
    if(steep)
    {
        t = x0; x0 = y0; y0 = t;
        t = x1; x1 = y1; y1 = t;
    }
    if(x0 > x1) 
    {
        t = x0; x0 = x1; x1 = t;
        t = y0; y0 = y1; y1 = t;
    }
    deltax = x1 - x0;                       // 傾き計算 
    deltay = abs(y1 - y0);
    error = 0;
    y = y0;
    /// 傾きでステップの正負を切り替え
    if(y0 < y1) ystep = 1; else ystep = -1;
    /// 直線を点で描画
    for(x=x0; x<x1+1; x++) 
    {
        if(steep) LCD_PSET(y,x,cl); else LCD_PSET(x,y,cl);
        error += deltay;
        if((error << 1) >= deltax) 
        {
            y += ystep;
            error -= deltax;
        }
    }
}
aqm1248a.h

//----------------------------------------------------------------
//        AQM1248A LCD
//----------------------------------------------------------------
#include <SPI.h>

void Init_LCD();
void LCD_CLS(char data);
void LCD_PSET(int x_data, int y_data, int cl);
void LCD_Print_C(int x_data, int y_data, char c_data, int cl, int m_fl);
void LCD_Print_Str(int x_data, int y_data, char *c_data, int cl, int m_fl);
void LCD_LINE(int x0, int y0, int x1, int y1, int cl);

#define LCD_CS          16    
#define LCD_RS          15
#define LCD_RSET        -1
#define SPI_CLK         30


//    Font Data 
const char Font[192][5] =
{
    { 0x00, 0x00, 0x00, 0x00, 0x00 }, // " " 0x20
    { 0x00, 0x00, 0x4f, 0x00, 0x00 }, // !   0x21
    { 0x00, 0x07, 0x00, 0x07, 0x00 }, // "   0x22
    { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // #   0x23
    { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $   0x24
    { 0x23, 0x13, 0x08, 0x64, 0x62 }, // %   0x25
    { 0x36, 0x49, 0x55, 0x22, 0x50 }, // &   0x26
    { 0x00, 0x05, 0x03, 0x00, 0x00 }, // '   0x27
    { 0x00, 0x1c, 0x22, 0x41, 0x00 }, // (   0x28
    { 0x00, 0x41, 0x22, 0x1c, 0x00 }, // )   0x29
    { 0x14, 0x08, 0x3e, 0x08, 0x14 }, // *   0x2A
    { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // +   0x2B
    { 0x00, 0x50, 0x30, 0x00, 0x00 }, // ,   0x2C
    { 0x08, 0x08, 0x08, 0x08, 0x08 }, // -   0x2D
    { 0x00, 0x60, 0x60, 0x00, 0x00 }, // .   0x2E
    { 0x20, 0x10, 0x08, 0x04, 0x02 }, // /   0x2F
    { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 0   0x30
    { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 1   0x31
    { 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2   0x32
    { 0x21, 0x41, 0x45, 0x4b, 0x31 }, // 3   0x33
    { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 4   0x34
    { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5   0x35
    { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 6   0x36
    { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7   0x37
    { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8   0x38
    { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 9   0x39
    { 0x00, 0x36, 0x36, 0x00, 0x00 }, // :   0x3A
    { 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;   0x3B
    { 0x08, 0x14, 0x22, 0x41, 0x00 }, // <   0x3C
    { 0x14, 0x14, 0x14, 0x14, 0x14 }, // =   0x3D
    { 0x00, 0x41, 0x22, 0x14, 0x08 }, // >   0x3E
    { 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?   0x3F
    { 0x32, 0x49, 0x79, 0x41, 0x3e }, // @   0x40
    { 0x7e, 0x11, 0x11, 0x11, 0x7e }, // A   0x41
    { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // B   0x42
    { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // C   0x43
    { 0x7f, 0x41, 0x41, 0x22, 0x1c }, // D   0x44
    { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // E   0x45
    { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // F   0x46
    { 0x3e, 0x41, 0x49, 0x49, 0x7a }, // G   0x47
    { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // H   0x48
    { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // I   0x49
    { 0x20, 0x40, 0x41, 0x3f, 0x01 }, // J   0x4A
    { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // K   0x4B
    { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // L   0x4C
    { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // M   0x4D
    { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // N   0x4E
    { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // O   0x4F
    { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // P   0X50
    { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // Q   0X51
    { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // R   0X52
    { 0x46, 0x49, 0x49, 0x49, 0x31 }, // S   0X53
    { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // T   0X54
    { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // U   0X55
    { 0x1f, 0x20, 0x40, 0x20, 0x1f }, // V   0X56
    { 0x3f, 0x40, 0x38, 0x40, 0x3f }, // W   0X57
    { 0x63, 0x14, 0x08, 0x14, 0x63 }, // X   0X58
    { 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y   0X59
    { 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z   0X5A
    { 0x00, 0x7f, 0x41, 0x41, 0x00 }, // [   0X5B
    { 0x02, 0x04, 0x08, 0x10, 0x20 }, // "\" 0X5C
    { 0x00, 0x41, 0x41, 0x7f, 0x00 }, // ]   0X5D
    { 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^   0X5E
    { 0x40, 0x40, 0x40, 0x40, 0x40 }, // _   0X5F
    { 0x00, 0x01, 0x02, 0x04, 0x00 }, // `   0X60
    { 0x20, 0x54, 0x54, 0x54, 0x78 }, // a   0X61
    { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // b   0X62
    { 0x38, 0x44, 0x44, 0x44, 0x20 }, // c   0X63
    { 0x38, 0x44, 0x44, 0x48, 0x7f }, // d   0X64
    { 0x38, 0x54, 0x54, 0x54, 0x18 }, // e   0X65
    { 0x08, 0x7e, 0x09, 0x01, 0x02 }, // f   0X66
    { 0x0c, 0x52, 0x52, 0x52, 0x3e }, // g   0X67
    { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // h   0X68
    { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // i   0X69
    { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // j   0X6A
    { 0x7f, 0x10, 0x28, 0x44, 0x00 }, // k   0X6B
    { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // l   0X6C
    { 0x7c, 0x04, 0x18, 0x04, 0x78 }, // m   0X6D
    { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // n   0X6E
    { 0x38, 0x44, 0x44, 0x44, 0x38 }, // o   0X6F
    { 0x7c, 0x14, 0x14, 0x14, 0x08 }, // p   0X70
    { 0x08, 0x14, 0x14, 0x18, 0x7c }, // q   0X71
    { 0x7c, 0x08, 0x04, 0x04, 0x08 }, // r   0X72
    { 0x48, 0x54, 0x54, 0x54, 0x20 }, // s   0X73
    { 0x04, 0x3f, 0x44, 0x40, 0x20 }, // t   0X74
    { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // u   0X75
    { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // v   0X76
    { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // w   0X77
    { 0x44, 0x28, 0x10, 0x28, 0x44 }, // x   0X78
    { 0x0c, 0x50, 0x50, 0x50, 0x3c }, // y   0X79
    { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // z   0X7A
    { 0x00, 0x08, 0x36, 0x41, 0x00 }, // {   0X7B
    { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // |   0X7C
    { 0x00, 0x41, 0x36, 0x08, 0x00 }, // }   0X7D
    { 0x08, 0x08, 0x2a, 0x1c, 0x08 }, // ->  0X7E
    { 0x08, 0x1c, 0x2a, 0x08, 0x08 }, // <-  0X7F
    { 0x08, 0x46, 0x4a, 0x32, 0x1e }, // ta  0x80
    { 0x0a, 0x4a, 0x3e, 0x09, 0x08 }, // ti  0x81        
    { 0x0e, 0x00, 0x4e, 0x20, 0x1e }, // tu  0x82
    { 0x04, 0x45, 0x3d, 0x05, 0x04 }, // te  0x83       
    { 0x00, 0x7f, 0x08, 0x10, 0x00 }, // to  0x84
    { 0x44, 0x24, 0x1f, 0x04, 0x04 }, // na  0x85        
    { 0x40, 0x42, 0x42, 0x42, 0x40 }, // ni  0x86
    { 0x42, 0x2a, 0x12, 0x2a, 0x06 }, // nu  0x87       
    { 0x22, 0x12, 0x7b, 0x16, 0x22 }, // ne  0x88
    { 0x00, 0x40, 0x20, 0x1f, 0x00 }, // no  0x89        
    { 0x78, 0x00, 0x02, 0x04, 0x78 }, // ha  0x8A
    { 0x3f, 0x44, 0x44, 0x44, 0x44 }, // hi  0x8B       
    { 0x02, 0x42, 0x42, 0x22, 0x1e }, // hu  0x8C
    { 0x04, 0x02, 0x04, 0x08, 0x30 }, // he  0x8D        
    { 0x32, 0x02, 0x7f, 0x02, 0x32 }, // ho  0x8E
    { 0x02, 0x12, 0x22, 0x52, 0x0e }, // ma  0x8F       
    { 0x00, 0x2a, 0x2a, 0x2a, 0x40 }, // mi  0x90
    { 0x38, 0x24, 0x22, 0x20, 0x70 }, // mu  0x91        
    { 0x40, 0x28, 0x10, 0x28, 0x06 }, // me  0x92
    { 0x0a, 0x3e, 0x4a, 0x4a, 0x4a }, // mo  0x93       
    { 0x04, 0x7f, 0x04, 0x14, 0x0c }, // ya  0x94
    { 0x40, 0x42, 0x42, 0x7e, 0x40 }, // yu  0x95        
    { 0x4a, 0x4a, 0x4a, 0x4a, 0x7e }, // yo  0x96
    { 0x04, 0x05, 0x45, 0x25, 0x1c }, // ra  0x97       
    { 0x0f, 0x40, 0x20, 0x1f, 0x00 }, // ri  0x98
    { 0x7c, 0x00, 0x7e, 0x80, 0x30 }, // ru  0x99        
    { 0x7e, 0x40, 0x20, 0x10, 0x08 }, // re  0x9A
    { 0x7e, 0x42, 0x42, 0x42, 0x7e }, // ro  0x9B       
    { 0x0e, 0x02, 0x42, 0x22, 0x1e }, // wa  0x9C
    { 0x42, 0x42, 0x40, 0x20, 0x18 }, // n   0x9D        
    { 0x02, 0x04, 0x01, 0x02, 0x00 }, // "   0x9E
    { 0x07, 0x05, 0x07, 0x00, 0x00 }, // .   0x9F
    { 0x00, 0x00, 0x00, 0x00, 0x00 }, //     0xA0
    { 0x70, 0x50, 0x70, 0x00, 0x00 }, //  .  0xA1        
    { 0x00, 0x00, 0x0f, 0x01, 0x01 }, //  [  0xA2
    { 0x40, 0x40, 0x78, 0x00, 0x00 }, //  ]  0xA3       
    { 0x10, 0x20, 0x40, 0x00, 0x00 }, //  ,  0xA4
    { 0x00, 0x18, 0x18, 0x00, 0x00 }, //  .  0xA5        
    { 0x0a, 0x0a, 0x4a, 0x2a, 0x1e }, // wo  0xA6
    { 0x04, 0x24, 0x34, 0x14, 0x0c }, // a   0xA7       
    { 0x20, 0x10, 0x78, 0x04, 0x00 }, // i   0xA8
    { 0x18, 0x08, 0x4c, 0x48, 0x38 }, // u   0xA9        
    { 0x48, 0x48, 0x78, 0x48, 0x48 }, // e   0xAA
    { 0x48, 0x28, 0x18, 0x7c, 0x08 }, // o   0xAB       
    { 0x08, 0x7c, 0x08, 0x28, 0x18 }, // ya  0xAC
    { 0x40, 0x48, 0x48, 0x78, 0x40 }, // yu  0xAD        
    { 0x54, 0x54, 0x54, 0x7c, 0x00 }, // yo  0xAE
    { 0x18, 0x00, 0x58, 0x40, 0x38 }, // tu  0xAF       
    { 0x08, 0x08, 0x08, 0x08, 0x08 }, //  -  0xB0
    { 0x01, 0x41, 0x3d, 0x09, 0x07 }, //  a  0xB1        
    { 0x20, 0x10, 0x7c, 0x02, 0x01 }, //  i  0xB2
    { 0x0e, 0x02, 0x43, 0x22, 0x1e }, //  u  0xB3       
    { 0x42, 0x42, 0x7e, 0x42, 0x42 }, //  e  0xB4
    { 0x22, 0x12, 0x0a, 0x7f, 0x02 }, //  o  0xB5        
    { 0x42, 0x3f, 0x02, 0x42, 0x3e }, // ka  0xB6
    { 0x0a, 0x0a, 0x7f, 0x0a, 0x0a }, // ki  0xB7       
    { 0x08, 0x46, 0x42, 0x22, 0x1e }, // ku  0xB8
    { 0x04, 0x03, 0x42, 0x3e, 0x04 }, // ke  0xB9        
    { 0x42, 0x42, 0x42, 0x42, 0x7e }, // ko  0xBA
    { 0x02, 0x4f, 0x22, 0x1f, 0x02 }, // sa  0xBB       
    { 0x4a, 0x4a, 0x40, 0x20, 0x1c }, // si  0xBC
    { 0x42, 0x22, 0x12, 0x2a, 0x46 }, // su  0xBD        
    { 0x02, 0x3f, 0x42, 0x4a, 0x46 }, // se  0xBE
    { 0x06, 0x48, 0x40, 0x20, 0x1e }, // so  0xBF
    { 0x08, 0x46, 0x4a, 0x32, 0x1e }, // ta  0xC0
    { 0x0a, 0x4a, 0x3e, 0x09, 0x08 }, // ti  0xC1        
    { 0x0e, 0x00, 0x4e, 0x20, 0x1e }, // tu  0xC2
    { 0x04, 0x45, 0x3d, 0x05, 0x04 }, // te  0xC3       
    { 0x00, 0x7f, 0x08, 0x10, 0x00 }, // to  0xC4
    { 0x44, 0x24, 0x1f, 0x04, 0x04 }, // na  0xC5        
    { 0x40, 0x42, 0x42, 0x42, 0x40 }, // ni  0xC6
    { 0x42, 0x2a, 0x12, 0x2a, 0x06 }, // nu  0xC7       
    { 0x22, 0x12, 0x7b, 0x16, 0x22 }, // ne  0xC8
    { 0x00, 0x40, 0x20, 0x1f, 0x00 }, // no  0xC9        
    { 0x78, 0x00, 0x02, 0x04, 0x78 }, // ha  0xCA
    { 0x3f, 0x44, 0x44, 0x44, 0x44 }, // hi  0xCB       
    { 0x02, 0x42, 0x42, 0x22, 0x1e }, // hu  0xCC
    { 0x04, 0x02, 0x04, 0x08, 0x30 }, // he  0xCD        
    { 0x32, 0x02, 0x7f, 0x02, 0x32 }, // ho  0xCE
    { 0x02, 0x12, 0x22, 0x52, 0x0e }, // ma  0xCF       
    { 0x00, 0x2a, 0x2a, 0x2a, 0x40 }, // mi  0xD0
    { 0x38, 0x24, 0x22, 0x20, 0x70 }, // mu  0xD1        
    { 0x40, 0x28, 0x10, 0x28, 0x06 }, // me  0xD2
    { 0x0a, 0x3e, 0x4a, 0x4a, 0x4a }, // mo  0xD3       
    { 0x04, 0x7f, 0x04, 0x14, 0x0c }, // ya  0xD4
    { 0x40, 0x42, 0x42, 0x7e, 0x40 }, // yu  0xD5        
    { 0x4a, 0x4a, 0x4a, 0x4a, 0x7e }, // yo  0xD6
    { 0x04, 0x05, 0x45, 0x25, 0x1c }, // ra  0xD7       
    { 0x0f, 0x40, 0x20, 0x1f, 0x00 }, // ri  0xD8
    { 0x7c, 0x00, 0x7e, 0x80, 0x30 }, // ru  0xD9        
    { 0x7e, 0x40, 0x20, 0x10, 0x08 }, // re  0xDA
    { 0x7e, 0x42, 0x42, 0x42, 0x7e }, // ro  0xDB       
    { 0x0e, 0x02, 0x42, 0x22, 0x1e }, // wa  0xDC
    { 0x42, 0x42, 0x40, 0x20, 0x18 }, // n   0xDD        
    { 0x02, 0x04, 0x01, 0x02, 0x00 }, // "   0xDE
    { 0x07, 0x05, 0x07, 0x00, 0x00 } // .   0xDF
                    
};

HP用HTMLコード

以下はHP表示用のHTMLコードです。保存先は基板上のSDカードです。

menu.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <link rel='stylesheet' type='text/css' href='./menu.css' >
        <title>ESP32 Monitor</title>
    </head>
    <body>
	<center>
       	<div style='font-size:35px'><b><i><u>ESP32 Monitor</u></i></b><br><br></div>
       	<div class="menu">
       	    <div class="input-group"> 
            	<label>Time:</label>
        	    <div id="0" ></div>
            </div>
            <div class="input-group"> 
                <label>Temp & Humi:</label>
        	    <div id="1" ></div>
            </div> 
            <div class="input-group"> 
                <label>Count:</label>
        	    <div id="2" ></div>
            </div> 
            <form method='get'>
                <button type='submit' name='2' onclick='onBtn_back(2)'>Set Time</button><br>
                <button type='submit' name='1' onclick='onBtn_back(1)'>Update</button>
                <div>
            		<input type='number' max='23' min='0' id='3' class='inp_box' />(H)
            		<input type='number' max='59' min='0' id='4' class='inp_box' />(M)
            		<input type='number' max='59' min='0' id='5' class='inp_box' />(S)
        	    </div>
                <button type='submit' name='4' onclick='onBtn_back(4)'>Start</button>
                <button type='submit' name='3' onclick='onBtn_back(3)'>Stop</button><br>
    	    	<a style="color:#00ffff;cursor: pointer;" href='./data0.txt' download='data00.txt'>Download00</a>  	    	
            </form>
       	</div>
	</center>
    <script>

	    var para=['0','0','0','0','0','0','0'];
	    var url = "http://esp32monitor.local/?80=";
	    var xhr = new XMLHttpRequest();	
	    var a,b,str;
      
	    xhr.open('GET', url);
	    xhr.send();
     
	    xhr.onreadystatechange = function() 
	    {
	      if(xhr.readyState === 4 && xhr.status === 200) 
	      {
	        console.log( xhr.responseText );

	        b=0;
	        for(a = 0; a < 6; a ++)
       	    {
	            para[a]='';
       	        while( xhr.responseText[b] != ',') 
	            {
	                para[a] += xhr.responseText[b];
       	            b ++;
	            }
	            b ++; 
	        }

		    for(a = 0; a < 3; a ++) document.getElementById(String(a)).innerHTML = para[a];
		    for(a = 3; a < 6; a ++) document.getElementById(String(a)).value=para[a];	        
   	      }
	    }

        function onBtn_back(btno){
            var a;
            var str = "";
		    for(a = 3; a < 6; a ++) str += (document.getElementById(String(a)).value + ",");
		    document.getElementsByName(btno)[0].value=str;
	    }
	    
        history.pushState(null,null,'/');        
    </script>
    </body>
</html>


Set_Time.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <link rel='stylesheet' type='text/css' href='./menu.css' >
        <title>ESP32 Monitor</title>
    </head>
    <body>
		<center>
            <div style='font-size:35px'><b><i><u>Set Time</u></i></b><br><br></div>
            <div class="menu">
				<div class="input-group"> 
					<label>Year:</label>
					<div >
						20<input type='number' max='99' min='0' id='100' class='inp_box' onchange='onChg_Set_Year()' />
					</div>
				</div>
				<div class="input-group"> 
					<label>Month/Day/Weekday:</label>
					<div>
						<input type='number' max='12' min='1' id='101' class='inp_box' />(M)
						<input type='number' max='31' min='1' id='102' class='inp_box' />(D)
                           <select id="103" style="width:65px">
                               <option value='0' selected >Sun.</option>
                               <option value='1'>Mon.</option>
                               <option value='2'>Tue.</option>
                               <option value='3'>Wen.</option>
                               <option value='4'>Thu.</option>
                               <option value='5'>Fry.</option>
                               <option value='6'>Sat.</option>
                           </select>
					</div>
				</div> 
				<div class="input-group"> 
					<label>Hour/Minute/Second:</label>
					<div>
					<input type='number' max='23' min='0' id='104' class='inp_box' />(H)
					<input type='number' max='59' min='0' id='105' class='inp_box' />(M)
					<input type='number' max='59' min='0' id='106' class='inp_box' />(S)
					</div>
				</div>
               	<form method='get' class="input-group">
               	    <button type='submit' name='99' value='2' >Back</button>
               	    <button type='submit' name='100' value='2'  onclick='onBtn_Set_Time()' >Set</button>
               	</form>
        	</div>
		</center>
		<script>
			function onChg_Set_Year() {
 				var a;
 				a=Number(document.getElementById("100").value);
				if(a < 10) document.getElementById("100").value="0" + String(a);
			}

			function onBtn_Set_Time() {
				var a;
				var str="";

				for(a=100; a<107; a ++) str += (document.getElementById(String(a)).value + ",");
				document.getElementsByName('100')[0].value=str;
			}

			var para=['0','0','0','0','0','0','0'];
//		    var url = "http://192.168.4.1/?81=";
		    var url = "http://esp32monitor.local/?81=";
		    var xhr = new XMLHttpRequest();	
			var a,b,str;
      
		    xhr.open('GET', url);
		    xhr.send();
     
		    xhr.onreadystatechange = function() 
		    {
		    	if(xhr.readyState === 4 && xhr.status === 200) 
		      	{
		        	console.log( xhr.responseText );

		        	b=0;
		        	for(a=0; a<7; a++)
        			{
		        	    para[a]='';
        			    while( xhr.responseText[b] != ',') 
		        	    {
		        	        para[a] += xhr.responseText[b];
        			        b ++;
		        	    }
		        	    b ++; 
		        	}

					if(Number(para[0]) < 10) 
						para[0] += ("0" + para[0]);
			
			        for(a=0; a<7; a++)
					{
						document.getElementById(String(a + 100)).value=para[a];
			        	if(a == 3) 
							document.getElementById("103").selectedIndex=Number(para[a]);
					}
	   			}
				onChg_Set_Year();			
			}

		</script>
    </body>
</html>


menu.css

@charset "UTF-8";

body {
        font-family: Arial,Helvetica,sans-serif;
        background: #181818;
        color: #EFEFEF;
        font-size: 16px
}

.menu {
        width: 420px;
        background: #363636;
        padding: 15px;
        border-radius: 10px;
        margin-top: -30px;
        margin-right: 10px;
}

.input-group {
        display: flex;
        flex-wrap: nowrap;
        line-height: 22px;
        margin: 5px 0px;
}

.input-group label {
        padding-right: 10px;
        min-width: 38%;
	text-align: left
}

button {
        display: block;
        margin: 10px;
        line-height: 35px;
        cursor: pointer;
        color: #fff;
        background: #228b22;
        border-radius: 10px;
        font-size: 16px;
	width:200px;
}

.inp_box {
		width:40px;
        font-size: 16px;
		text-align: right;

}

測定開始

測定は以下の様に行いました。

  • 下記の様に、
    • 前回使用した温度センサのセンサー部とAM2320を缶の中に入れる。
    • AM2320は基板上のI2Cコネクタに接続する。
    • 保温器の蓋を閉め、上に温度センサ本体と今回製作した温湿度測定基板を置く。
  • Web画面で測定間隔を1分に設定し、ヒータに電源を入れる。
  • ヒーターの温度調整レバーを最低、中位、最高の3箇所にセットして各々測定した。
  • 測定時間は約60分

測定結果

測定中、センサーの値とAM2320の値を比較していたのですが両者の温度湿度が若干違いました。ただ最終的な状態では両者ほぼ同じ値を出していました。とりあえず今後は、AM2320の値を元に進める事にします。

温度と湿度の測定結果は以下の通り。

この測定で分かった事は、

  1. センサーの値から温度変化を予測した前回のイメージとほぼ同じ様に温度が変化している。
  2. 最初温度は一度オーバーシュートする。(定常状態より高くなる)
  3. 温度が一定になるのに約30分かかる。
  4. 一定になった後の変動は少ない。
  5. 温度調節に比例して最終的な温度は変化する。
  6. 湿度の管理は行っていないので高温で低湿になる。

60℃から90℃位の範囲で有れば温度調整レバーを管理すればコントロール出来そうです。湿度に関しては多分濡れたタオル等を缶の中に入れて置けばよれなりに上がると思われます。

ただ問題は、

  • 60℃以下の設定が出来ない
    • 温度調節レバー最低で60℃になるのでそれ以下は設定出来ない
    • 納豆は40から50℃の設定が必要。
  • 温度が上げる最初の段階でオーバーシュートする
    • 大体定常温度+10℃位、最初の段階でオーバーシュートする。
    • 出来ればオーバーシュートは避けたい

次回は

今回保温器の中の温度が測定出来る事が分かりました。これを基にヒータをオンオフすれば保温器の温度を管理出来る様な気がします。次回はESP32でヒータをオンオフしたいと思います。