Loggerの製作-05 LCDの追加

ちょと温度を知りたい時など表示部があればかなり便利です。”超小型グラフィックLCD AQM1248A”でLCDについて説明しています。このLCDをこの測定に付ける事にしました。

まずは回路図

現在の回路は、以下の様になっています。

AQM1248A素子との通信はSPI。その他、チップセレクト。コマンド、データ切り替えピンが必要です。ピン数は7ピン。ピン配置を以下に示します。

  • 1番ピン: 電源。3.3Vと接続
  • 2番ピン: CS。 チップセレクト。 
  • 3番ピン: RESET。リセット。 
  • 4番ピン: RS。コマンドとデータの識別用端子。
  • 5番ピン: SCLK。クロック。
  • 6番ピン: SDI。MOSI。
  • 7番ピン: GND

ちょっと変わっているのは、SPI通信なのに、MISOピンを使用しない所です。これは、ホストからスレーブにデータを送る(表示器なので当たり前)が、スレーブ側からホストにデータは送れない(表示器の状態が分からない)と言う事です。ESP8266のデフォルトのSPIピン配置は

  • SCL:  GPIO14
  • MOSI: GPIO13
  • MISO: GPIO12

となっています。これらを踏まえて回路を下記の様に変更しました。

  • GPIO14:
    • 現在このピンは、”測定/設定切り替え用スイッチ” が配線されていますが、それを止めて、AQM1248のSCLK(ピン5)と接続。
  • GPIO13:
    • 現在このピンはパイロットLEDに配線されていますが、それを止めて、AQM1248のSDI(ピン6)と接続。
  • GPIO12:
    • SPIでは、MOSIとなるピンですが、ここに、”測定/設定切り替え用スイッチ” を配線。
  • GPIO15:
    • ESP8266このピンは起動時、”Low”にする必要が有るみたいですが、起動後はユーザーが使用可能の様です。
    • ここに、パイロットLEDを配線しました。
  • GPIO:2
    • このピンをAQM1248のCS(ピン2)に接続しました。
    • このピンもESP8266起動時状態を決めるピンの1つですが、この配線で起動に問題は有りませんでした。
  • GPIO0:
    • このピンをAQM1248のRS(ピン4)に接続しました。
    • このピンもESP8266起動時状態を決めるピンの1つですが、この配線で起動に問題は有りませんでした。
  • AQM1248 RESET(ピン3)ピン
    • ESP8266に空きピンが無く、今回はESP8266のRESETピンに接続しています。

配線後はこんな感じです。

スケッチ

AQM1248

AQM1248のスケッチは、”超小型グラフィックLCD AQM1248A”に有りますが、このままでは今回のスケッチに追加出来ません。簡単に使用出来る様にスケッチを、”AQM1248A.cpp” と ”AQM1248A.h” に分けました。

FileName: AQM1248A.cpp -> AMQ1288本体スケッチ

#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);

/*
    pinMode(LCD_RSET, OUTPUT);     
    digitalWrite(LCD_RSET,LOW);
    delay(500);
    digitalWrite(LCD_RSET,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 a,b,c,d;
    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;
            }
            LCD_PSET(x_data,y_data + c,d);
            s <<= 1; 
        }
        x_data ++;
    }
    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 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);
//        Serial.println(*c_data,HEX);
        a --; x_data += 6; 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;
        }
    }
  • 1行   ヘッダーファイルの読み込み。
    • 詳細は次の、”AQM1248A.h”の説明を参照下さい。
  • 13から18行 初期設定でRESET部分を省略。
    • 今回はRESET端子を使用しないのでAQM1248の初期設定でのリセット部を省略しました。
  • その他の機能は、”超小型グラフィックLCD AQM1248A”を参照下さい。

FileName: AQM1248A.h -> AMQ1248 ヘッダー

//----------------------------------------------------------------
//        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);
void LCD_Print_Str(int x_data, int y_data, char *c_data, int cl);
void LCD_LINE(int x0, int y0, int x1, int y1, int cl);

#define LCD_CS          2    
#define LCD_RS          0
#define LCD_RSET      -1
#define SPI_CLK         14


//    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
                    
};
  • 6から11行  関数の宣言
  • 13から16行 使用GPIOピンの宣言
    • AQM1248で使用するピンの宣言をしています。
    • RESETピンは使用しないので、−1としています。

AM2320

この素子、”AM2320を使う”は、温度と湿度が測定出来ます。今回はこの素子をサポートします。AQM1248同様、本体とヘッダーを作成しています。

FileName: AM2320.cpp -> AM2320 本体

#include "AM2320.h"

void temp_hum(float * t_data, float * h_data)
{
 float hu,tp;
 uint8_t data[8];
 int flg,len;
 String str;

  Wire.beginTransmission(ADR);
  Wire.endTransmission();

  Wire.beginTransmission(ADR);
  Wire.write(0x03);         
  Wire.write(0x00);         
  Wire.write(0x04);            
  Wire.endTransmission();

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

    flg = 1;
    if(data[2] & 0x80) flg = -1;
    data[2] &= 0x7f;
    *h_data = ((float)(data[2]*256+data[3]))/10 * flg;
     
    flg = 1;
    if(data[4] & 0x80) flg = -1;
    data[4] &= 0x7f;
    *t_data = ((float)(data[4]*256+data[5]))/10 + flg; 
    
  }
}

FileName: AM2320.h -> AM2320 ヘッダー

#include <Wire.h>
#define ADR 0x5c
#include <string.h>

void temp_hum(float * t_data, float * h_data);

本体スケッチの変更

前回に対し、下記の部分を変更しています。

  • 測定値のLCDへの表示部。
  • 測定素子を追加によるWeb画面の変更。

以下は本体スケッチ ”ESP8266_logger05.ino” です。

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Wire.h>
#include "LittleFS.h" 

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

#define Adt_On           0
#define Adt_Off          3

#define Pilot_LED       15
#define Mode_switch     12

#define mem_inter        0
#define mem_no           4
#define mem_state        8
#define mem_chk         12

#define Mic_Min         60000000

/* Set these to your desired credentials. */
const char *ssid = "ESP8266";
const char *password = "12345678";

ESP8266WebServer server(80);
int m_state,ope_fl,ope2_fl;

void handleRoot() 
{
  String cmd;
  float t_da,h_da; 
  int a,b,c;
  uint32_t m_data;
  File dataFile;

    cmd = server.argName(0);
    switch(cmd.toInt())
    {
      case 1:   // Start Log
                // interval time
                cmd = server.arg("1");
                m_data = cmd.toInt();
                ESP.rtcUserMemoryWrite(mem_inter, &m_data, sizeof(m_data)) ;

                // measurement No.
                m_data = 0;   
                ESP.rtcUserMemoryWrite(mem_no, &m_data, sizeof(m_data)) ;

                // Sencer State
                cmd = server.arg("2");
                m_state = m_data = cmd.toInt();
                ESP.rtcUserMemoryWrite(mem_state, &m_data, sizeof(m_data)) ;
                
                ope_fl = 1;
                pinMode(Mode_switch,INPUT);
                if(!digitalRead(Mode_switch)) ope2_fl = 1;
                break;
                
      case 3:   // Measure
                cmd = server.arg("3");
                m_state = cmd.toInt();
                break;
                
      case 10:  // Send data
                cmd="";
                b=1;
                for(a=0; a<4; a++)
                {
                    if(m_state & b) cmd += (String(get_Temp(0x48 + a),1) + ',');
                    else cmd += "xx.x,";
                    b <<= 1;
                }
                
                if( m_state & b)
                {
                    temp_hum(&t_da, &h_da);
                    cmd += (String(t_da,1) + ',');
                    cmd += (String(h_da,1) + ',');
                }
                else cmd += "xx.x,xx.x,";
                
                cmd += (String(Battery_chk(),1) + ',');
                
                ESP.rtcUserMemoryRead(mem_no, &m_data, sizeof(m_data)) ;
                a = m_data;
                cmd += (String(a) + ',');

                ESP.rtcUserMemoryRead(mem_inter, &m_data, sizeof(m_data)) ;
                a = m_data;
                cmd += (String(a) + ',');
                cmd += (String(m_state) + ',');

                if(ope_fl)
                {
                    if(!ope2_fl) 
                    {
                        cmd += "1,";
                        ope_fl = 0;
                    }
                    else cmd += "0,";
                }
                else cmd += "0,";

                server.send(200, "text/plain", cmd);
                break;
    }
    
    dataFile = LittleFS.open("index.html", "r");
    server.streamFile(dataFile, "text/html");

    if(ope_fl * ope2_fl)
    {
      LCD_CLS(0);  
      Serial.println("Start");

      m_data=0;
      ESP.rtcUserMemoryWrite(mem_chk, &m_data, sizeof(m_data)) ;

      LittleFS.remove("/data/data.txt");
      LittleFS.remove("/data/data1.txt");
      make_Headder("/data/data.txt");
      make_Headder("/data/data1.txt");
      get_save_Data();
      Adt_ope_mode(Adt_Off);
      
      ESP.rtcUserMemoryRead(mem_inter, &m_data, sizeof(m_data)) ;
      ESP.deepSleep(m_data * Mic_Min);
      delay(500);
    }
}

void make_Headder(String fn)
{
  File dataFile;
  String str;
  int a,b,c;
  uint32_t m_data;

    dataFile = LittleFS.open(fn, "w");
    a = 0x48;
    b =1;
    str = "";
    for(a = 0; a < 4; a ++)
    {
        str += String(a + 0x48 ,HEX);
        if(m_state & b) str += ":ON, ";
        else str += ":OFF, ";
        b <<= 1;
    }
    if(m_state & b) str += "T:ON, H:ON, ";
    else str += "T:OFF, H:OFF, ";

    str += "Interval:";
    ESP.rtcUserMemoryRead(mem_inter, &m_data, sizeof(m_data)) ;
    a = m_data;
    str += String(a);
    dataFile.println(str);
    dataFile.close();
}

void setup() 
{
  String buf;
  File dataFile;
  uint32_t offset,m_data;
  double inter_time;
  int a;
  
    delay(500);
    Serial.begin(115200);
    Serial.println();

    Wire.begin(); 
    Serial.println("I2C started");

    LittleFS.begin();
    Serial.println("LittleFS started");

    Adt_ope_mode(Adt_On);
    delay(500);

    pinMode(Mode_switch,INPUT);
    if(digitalRead(Mode_switch))
    {
        Serial.print("Configuring access point...");
        // You can remove the password parameter if you want the AP to be open. 
        WiFi.softAP(ssid, password);

        IPAddress myIP = WiFi.softAPIP();
        Serial.print("AP IP address: ");
        Serial.println(myIP);

        Serial.println(ssid);
        Serial.print("IP address: ");
        Serial.println(WiFi.localIP());

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

        pinMode(Pilot_LED, OUTPUT);
        digitalWrite(Pilot_LED, HIGH);

        SPI.begin(); 
        Init_LCD();
        LCD_CLS(0);
        ope_fl = ope2_fl = 0;

        ESP.rtcUserMemoryRead(mem_chk, &m_data, sizeof(m_data));
        if(m_data)
        {
            offset = m_data = 0;             
            for(a = 0; a < 3; a ++) 
            {
                ESP.rtcUserMemoryWrite(offset, &m_data, sizeof(m_data)) ;
                offset += 4;
            }
        }

        // Senser State
        ESP.rtcUserMemoryRead(mem_state, &m_data, sizeof(m_data)) ;
        m_state = m_data;
    }
    else
    {
        get_save_Data();
        Serial.println("Measured");
      
        Adt_ope_mode(Adt_Off);
      
        // interval time
        ESP.rtcUserMemoryRead(mem_inter, &m_data, sizeof(m_data)) ;
        inter_time = m_data * Mic_Min;
        ESP.deepSleep(inter_time);
        delay(500);
    }
}

float Battery_chk()
{
  float d_temp; 
  int a;

    d_temp = 0;
    for(a = 0; a < 5; a ++)
    {
      d_temp += (system_adc_read() * 9.822 / 1024);
      delay(10);
    }
    
    return d_temp/5;
}

void Adt_ope_mode(int data)
{
  int a;

    data <<= 5;
    for(a = 0x48; a < 0x4c; a ++)
    {
        Wire.beginTransmission(a);
        Wire.write(0x03);
        Wire.write(data);
        Wire.endTransmission();
    }
}

void loop() 
{
    char l_cls[20] = "         ";
    char disp_buf[20];
    float t_data[7];
    int a,len;
    String str,temp,temp1;
      
    server.handleClient();
  
    get_Data(t_data);
    for(a = 0; a < 4; a ++)
    { 
        LCD_Print_Str(8,a * 10 + 5,l_cls,1);
        str = String(a + 1) + ':' + String(t_data[a],1) + "'C" ;
        len = str.length() + 1; 
        str.toCharArray(disp_buf,len);
        LCD_Print_Str(8,a*10+5,disp_buf,1);
    }

    for(a = 4; a < 7; a ++)
    { 
        LCD_Print_Str(68,(a - 4) * 10 + 5,l_cls,1);
        switch(a)
        {
            case 4: temp = "T"; temp1 = "'C"; break;
            case 5: temp = "H"; temp1 = "%"; break;
            case 6: temp = "V"; temp1 = 'V'; break;
        }
        str = temp + ':' + String(t_data[a],1) + temp1 ;
        len=str.length() + 1; 
        str.toCharArray(disp_buf,len);
        LCD_Print_Str(68,(a - 4) * 10 + 5,disp_buf,1);
    }
}

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(".js")) dataType = "application/javascript";
    else if(path.endsWith(".png")) dataType = "image/png";
    else if(path.endsWith(".gif")) dataType = "image/gif";
    else if(path.endsWith(".jpg")) dataType = "image/jpeg";
    delay(5);
    
    dataFile = LittleFS.open(path.c_str(), "r");
    server.streamFile(dataFile, dataType);
    dataFile.close();
    delay(5);
}

float get_Temp(int addr)
{
  short int t_data;
  float f_data;
  
    Wire.requestFrom(addr, 2);
    t_data = Wire.read() << 8;  
    t_data |= Wire.read();      
    t_data >>= 3;                          
    f_data = (float)t_data  / 16.0;          
    return f_data;
}

void get_Data(float * f_data)
{
  int a,b;

    for(b = 0; b < 4; b ++)
    {
        f_data[b] = 0;
        for(a = 0; a < 5; a ++)
        {
          f_data[b] += get_Temp(0x48 + b);
          delay(50);
        }
        f_data[b] /= 5;
    }
    temp_hum(&f_data[4],&f_data[5]);
    f_data[6] = Battery_chk();
}

void get_save_Data()
{
  float f_data[7];
  int a,b,c;
  uint32_t m_data;

    get_Data(f_data);
    
    ESP.rtcUserMemoryRead(mem_state, &m_data, sizeof(m_data)) ;
    m_state = m_data;
    ESP.rtcUserMemoryRead(mem_no, &m_data, sizeof(m_data)) ;
    save_Data("data/data.txt",f_data,m_data);
    save_Data("data/data1.txt",f_data,m_data);
    m_data += 1;
    ESP.rtcUserMemoryWrite(mem_no, &m_data, sizeof(m_data)) ;
}

void save_Data(String fn, float *data_buf, uint32_t m_data)
{
  File dataFile;
  char temp[16]; 
  String str_time;
  int a,b;

    dataFile = LittleFS.open(fn, "a");
    dataFile.print(String(m_data) + ",");

    if(m_state & 0x10) m_state |= 0x20;
    m_state |= 0x40;
    
    b = 1;
    for(a = 0; a < 7; a++)
    {
      if(m_state & b)
      {
        dtostrf(data_buf[a], 5, 1,temp);
        str_time = temp;
      }
      else str_time = " xx.x";
      
      if(a != 6) dataFile.print(str_time + ",");
      else dataFile.println(str_time);
      b <<= 1;
    }
    dataFile.close();
}

ESP8266はAPモードでサーバを上げています。ESP8266とつなぐ時はスマホ等で行って下さい。

測定値の表示 LCD

  • 測定値のLCDへの表示は、280行から304行で行っています。
  • 今回は、ADT7410は温度のみ。AM2320は温度と湿度。ESP8266で電圧を測定しています。
  • よって、温度が5個、湿度が1個、電圧が1個の合計7個の測定値が有ります。
  • AQM1248Aは128x48ドットで今回はフォントが6x8ドットなので、縦8文字、横21文字の表示が可能です。
  • 計7個の表示を2列x4行で行っています。
  • 1列目はADT7410の温度の値で、”素子のアドレス:測定値”の形式で表示します。
  • 2列目はAM2320の測定値と電圧を表示します。先頭に温度は、”T:”、湿度は、”H:”、電圧は、”V:”と表示しその後に測定値が続きます。
  • I2Cのポートに素子が取り付けられていなくても値は表示します。

測定値の表示 Web画面

  • これまでは、”Loggerの製作-02-測定回路”の様にスケッチ内のHTMLのコードを埋め込んでいました。
  • 今回は、”LittleFS” を使って、HTMLを別ファイルに独立させました。
  • HTMLは、document.addEventListener()を使用しHTMLのコードがクライアントに読み込まれた後にサーバーから測定値が送られる様にしています。
  • 測定しながら値を送っているので表示に若干時間がかかります。
  • HTMLファイルを以下に示します。ファイル名は、”index.html”です。
<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <title>ESP8266 Logger</title>
  <style type='text/css'>
    button.bt1 {background:#90ee90;font-size:50px;padding:10px;margin:20px;border-radius:30px;box-shadow:4px 4px #555;}
    input.temp {scale:3;vertical-align:middle;}
  </style>
 </head>
<body>
 <div style='width:550px; background-color:#d8a373; border-style:solid; border-radius:30px; border-color:#6b3f31;margin-left:auto;margin-right:auto'>
  <div style='font-size:75px;text-align:center'><b><i><u>Temp Logger</u></i></b></div>
  <div style='font-size:60px;'>
   <div style='margin-left:60px'>
    <input type='checkbox' id='20' class='temp' />  48: <span id='10'>xx.x</span> 'C<br>
    <input type='checkbox' id='21' class='temp' />  49: <span id='11'>xx.x</span> 'C<br>
    <input type='checkbox' id='22' class='temp' />  4A: <span id='12'>xx.x</span> 'C<br>
    <input type='checkbox' id='23' class='temp' />  4B: <span id='13'>xx.x</span> 'C<br>
    <input type='checkbox' id='24' class='temp' />  TP: <span id='14'>xx.x</span> 'C<br>
     _ HU: <span id='15'>xx.x</span> %<br>
    Battery: <span id='16'>0.00</span> V<br>
    Times: <span id='17'>0</span> <br>
   </div>
  <div style='text-align:center'>
   <form method='get'>
    <button type='submit' name='3' id='t3' onclick='onBtnM_S(0)' class='bt1'>Measure</button><br>
   </form>
   <form method='get'>
    <input type='number' max='71' id='18' style='font-size:40px;width:100px;' name='1'/>
    <button type='submit' name='2' id='t2' onclick='onBtnM_S(1)' class='bt1'>Start</button><br>
   </form>
   <a href='./data/data.txt' download='data.txt'>Download</a><br>
   <a href='./data/data1.txt' download='data1.txt'>Backup</a><br>
  </div>
 </div>
 <script>

var para=['0','0','0','0','0','0','0','0','0','0','0','0'];

document.addEventListener('DOMContentLoaded', function (event) 
{
    var url = "http://192.168.4.1?10=";
    var xhr = new XMLHttpRequest();
    var a,b,c,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 < 11; a ++)
        {
            para[a] = '';
            while( xhr.responseText[b] != ',') 
            {
                para[a] += xhr.responseText[b];
                b ++;
            }
            if( a < 8) 
            	document.getElementById(String(a + 10)).innerHTML = para[a];
            b ++; 
        }
        document.getElementById('18').value = Number(para[8]);

        b = 1;
        c = Number(para[9]);
        for(a = 20; a < 25; a ++)
        { 
        	str = false;
        	if(c & b) str = true;  
            document.getElementById(String(a)).checked = str;
            b <<= 1;
        }
     	if(para[10] == '1') alert('測定モードにして下さい');
     }
   }
});

function onBtnM_S(mode) 
{
	var a,b,c;
	
	a = 0;
	b = 1;

	for(c = 20; c < 25; c ++)
	{
		if(document.getElementById(String(c)).checked) a |= b;
		b <<= 1;
	}
	
	if(mode) document.getElementById('t2').value = a;
	else document.getElementById('t3').value = a;
}

history.pushState(null,null,'/');
 </script>
</body>
</html>

実際の表示は以下の様になります。

  • 1:ESP8266の電源をONした時の最初の画面
    • ADT7410の温度測定値、”48”から”4B”。
    • AM2320用の温度を”TP” 湿度を”HU”
    • バッテリー電圧、”Battery”
    • 測定回数(この時点では”0”回)
    • 現在の温度等を測定する ”Measure”ボタン
    • 測定間隔設定欄、(今は”0”)とログ開始ボタン、”Start”
  • 2:現在の値を測定する。”Start”ボタン
    • ”48”から”TP”のチェックボタンをチェックするとそのセンサーの値を表示します。
    • AM2320用は温度と湿度を同時に読み込むので、チェックボタンは”TP”のみです。
    • バッテリの値は常に表示されます。
    • 対象のセンサをチェック後(今回は、”49”から”4B”と”TP”をチェック)、”Start”ボタンを押して下さい。測定値が表示されます。
  • 3:ログの開始
    • ”2”の状態からインターバル時間を設定。(上記では”3”に設定)
    • モードスイッチを測定に切り替えて、”Start”ボタンを押せばログが開始します。
    • 開始後、Webの画面は、”1”の様になります。この時点でサーバは測定用に切り替わっているのでデータは送られて来ず、タイムアウトになります。
    • 何回か測定した後、モードスイッチを設定に切りなえると、”3”の様な画面になります。
    • 前回の測定条件、測定回数(”Times”の欄)が表示されます。例では測定回数は7回です。

データの保存

  • LittleFS”を使用しているので、今回は測定データを、”data”フォルダーを作ってそこに保存しています。
  • また保存ファイルの先頭に測定条件を書き込みました。下記の1行目がそれです。各センサーの”On”,”Off”状態、測定時間が保存されます。
48:OFF, 49:ON, 4a:ON, 4b:ON, T:ON, H:ON, V:ON, Interval:3
0, xx.x, 29.1, 29.3, 29.3, 29.5, 69.6,  0.0
1, xx.x, 29.0, 29.3, 29.3, 29.5, 69.5,  0.0
2, xx.x, 28.9, 29.3, 29.3, 29.5, 69.5,  0.0
3, xx.x, 29.0, 29.3, 29.2, 29.5, 69.5,  0.0
4, xx.x, 28.9, 29.3, 29.2, 29.5, 69.5,  0.0
5, xx.x, 29.0, 29.3, 29.3, 29.5, 69.5,  0.0
6, xx.x, 28.9, 29.3, 29.2, 29.5, 69.5,  0.0
  • その下に、測定回数と各測定が保存されます。接続されていないセンサーの欄には”xx.x”が保存されます。上記では”48”センサーが接続されていません。
  • ちなみに、電圧センサは有りますが今回は、電池を使わずに外部電源を使用しているので、0.0Vとなっています。

コンパイルと実行

今回は、

  • ”ESP8266_logger05.ino”がスケッチ本体です。
  • このファイルが保存されているホルダーに、”AQM1248A.cpp” 、 ”AQM1248A.h”、”AM2320.cpp”、”AM2320.h”を保存します。
  • 本体が保存されているホルダーに、”data”という名前のホルダーを製作
  • この”data”ホルダーに、”index.html”を保存。

の様に各ファイルを保存して下さい。保存後、スケッチをコンパイル。データをUpload、(”LittleFS”を参照下さい)実行してみて下さい。LCDにはこんな感じで値が表示されます。(ちょっと画像がボケてます)

最後に

これで、スマホが無くても温度の測定が出来る様になりました。ログを取る必要が無い時には便利です。Web画面の表示は若干遅い様に思いますがこんなものでしょう。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする