ちょと温度を知りたい時など表示部があればかなり便利です。”超小型グラフィック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本体スケッチ
AQM1248A.cpp
#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= deltax)
{
y += ystep;
error -= deltax;
}
}
- 1行 ヘッダーファイルの読み込み。
- 詳細は次の、”AQM1248A.h”の説明を参照下さい。
- 13から18行 初期設定でRESET部分を省略。
- 今回はRESET端子を使用しないのでAQM1248の初期設定でのリセット部を省略しました。
- その他の機能は、”超小型グラフィックLCD AQM1248A”を参照下さい。
FileName: AQM1248A.h -> AMQ1248 ヘッダー
AQM1248A.h
//----------------------------------------------------------------
// AQM1248A LCD
//----------------------------------------------------------------
#include
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 本体
AM2320.cpp
#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 ヘッダー
AM2320.h
#include
#define ADR 0x5c
#include
void temp_hum(float * t_data, float * h_data);
本体スケッチの変更
前回に対し、下記の部分を変更しています。
- 測定値のLCDへの表示部。
- 測定素子を追加によるWeb画面の変更。
以下は本体スケッチ ”ESP8266_logger05.ino” です。
ESP8266_logger05.ino
#include
#include
#include
#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画面の表示は若干遅い様に思いますがこんなものでしょう。