センサの値をLCDに表示
概要
電源リーフには、電池電圧をモニタするためのADコンバータを実装。温度、湿度、照度、傾きだけでなく、電池電圧も測定し、LCDに表示させます。
温度(または、湿度)の補正の仕方
表示させたい温度(または、湿度)と4-Sensorsの温度(または、湿度)に、ずれがあるときは、2点間補正を行います。詳しくは、こちら。
使用するリーフ
Type | Name | Q’ty |
---|---|---|
AI04 | LCD | 1 |
AI01 | 4-Sensors | 1 |
AP01 | AVR MCU | 1 |
AZ01 | USB | 1 |
AX03 | Leaf×2 | 1 |
AV01 | CR2032 | 1 |
AZ62 | Connector Cover | 2 |
AZ63 | Nut Plate | 1 |
CR2032 coin cell battery | 1 | |
M2*15mm screw | 4 |
リーフの組立
ソースコード
- 書き込みには、4-Sensors、LCD、AVR MCUライブラリ(タイマ割り込み)が必要です。予め、ライブラリをインクルードしておいてください。詳しくは、こちら。
- Arduino IDEで、以下のスケッチをマイコンボードに書き込んでください。
//=====================================================================
// Leafony Platform sample sketch
// Application : 4-Sensors with LCD
// Processor : ATmega328P (3.3V /8MHz)
// Arduino IDE : 1.8.13
//
// Leaf configuration
// (1) AI01 4-Sensors
// (2) AI04 LCD
// (3) AP01 AVR MCU
// (4) AZ01 USB
//
// (c)2021 LEAFONY SYSTEMS Co., Ltd
// Released under the MIT license
// https://opensource.org/licenses/MIT
//
// Rev.00 2021/04/01 First release
//
//=====================================================================
// use libraries
// Adafruit Unified Sensor Driver
// https://github.com/adafruit/Adafruit_Sensor
// Adafruit Bus IO Library
// https://github.com/adafruit/Adafruit_BusIO
// Adafruit LIS3DH
// https://github.com/adafruit/Adafruit_LIS3DH
// SmartEverything ST HTS221 Humidity Sensor
// https://github.com/ameltech/sme-hts221-library
// ClosedCube Arduino Library for ClosedCube OPT3001
// https://github.com/closedcube/ClosedCube_OPT3001_Arduino
// ST7032 - Arduino LiquidCrystal compatible library
// https://github.com/tomozh/arduino_ST7032
//=====================================================================
//---------------------------------------------------------------------
// difinition
//---------------------------------------------------------------------
#include <MsTimer2.h> // Timer
#include <Wire.h> // I2C
#include <Adafruit_LIS3DH.h> // 3-axis accelerometer
#include <HTS221.h> // humidity and temperature sensor
#include <ClosedCube_OPT3001.h> // Ambient Light Sensor
#include <ST7032.h> // LCD
//=====================================================================
//===============================================
// シリアルモニタへの出力
// #define SERIAL_MONITOR = 出力あり
// //#define SERIAL_MONITOR = 出力なし(コメントアウトする)
//===============================================
#define SERIAL_MONITOR
//-----------------------------------------------
// IOピン一覧
//-----------------------------------------------
// D0 0 // PD0 (RXD)
// D1 1 // PD1 (TXD)
// D2 2 // PD2 (INT0)
// D3 3 // PD3 (INT1)
// D4 4 // PD4
// D5 5 // PD5
// D6 6 // PD6
// D7 7 // PD7
// D8 8 // PB0 (S-UART2_RX)
// D9 9 // PB1 (S-UART2_TX)
// D10 10 // PB2 (SS)
// D11 11 // PB3 (MOSI)
// D12 12 // PB4 (MISO)
// D13 13 // PB5 (SCK/LED)
// D14 14 // [A0] PC0
// D15 15 // [A1] PC1
// D16 16 // [A2] PC2
// D17 17 // [A3] PC3
//-----------------------------------------------
// プログラム内で使用する定数定義
//-----------------------------------------------
//------------------------------
// I2Cアドレス
//------------------------------
#define LIS2DH_ADDRESS 0x19 // Accelerometer (SD0/SA0 pin = VCC)
#define OPT3001_ADDRESS 0x45 // Ambient Light Sensor (ADDR pin = VCC)
#define LCD_I2C_EXPANDER_ADDR 0x1A // LCD I2C Expander
#define BATT_ADC_ADDR 0x50 // Battery ADC
//-----------------------------------------------
// loop interval
// MsTimer2のタイマー割り込み発生間隔(ms)
//-----------------------------------------------
#define LOOP_INTERVAL 125 // 125ms interval
//---------------------------------------------------------------------
// object
//---------------------------------------------------------------------
//------------------------------
// LCD
//------------------------------
ST7032 lcd;
//------------------------------
// Sensor
//------------------------------
Adafruit_LIS3DH accel = Adafruit_LIS3DH();
ClosedCube_OPT3001 light;
//---------------------------------------------------------------------
// プログラムで使用する変数定義
//---------------------------------------------------------------------
//---------------------------
// LCD
//---------------------------
int8_t lcdSendCount = 0;
//------------------------------
// Loop counter
//------------------------------
uint8_t iLoop1s = 0;
//------------------------------
// Event
//------------------------------
bool event1s = false;
//------------------------------
// interval Timer interrupt
//------------------------------
volatile bool bInterval = false;
//------------------------------
// LIS2DH : Accelerometer
//------------------------------
float dataX_g, dataY_g, dataZ_g;
float dataTilt;
//------------------------------
// HTS221 : Humidity and Temperature sensor
//------------------------------
float dataTemp;
float dataHumid;
//--------------------
// 2点補正用データ
//--------------------
// 温度補正用データ0
float TL0 = 25.0; // 4-Sensors温度測定値
float TM0 = 25.0; // 温度計等測定値
// 温度補正用データ1
float TL1 = 40.0; // 4-Sensors温度測定値
float TM1 = 40.0; // 温度計等測定値
// 湿度補正用データ0
float HL0 = 60.0; // 4-Sensors湿度測定値
float HM0 = 60.0; // 湿度計等測定値
// 湿度補正用データ1
float HL1 = 80.0; // 4-Sensors湿度測定値
float HM1 = 80.0; // 湿度計等測定値
//------------------------------
// OPT3001 : Ambient Light Sensor
//------------------------------
float dataLight;
//---------------------------
// Battery
//---------------------------
float dataBatt = 0;
//=====================================================================
// setup
//=====================================================================
void setup(){
Wire.begin(); // I2C 100kHz
#ifdef SERIAL_MONITOR
Serial.begin(115200); // UART 115200bps
Serial.println("=========================================");
Serial.println("setup start");
#endif
i2c_write_byte(LCD_I2C_EXPANDER_ADDR, 0x03, 0xFE);
i2c_write_byte(LCD_I2C_EXPANDER_ADDR, 0x01, 0x01); // LCD 電源ON
// LCD設定
lcd.begin(8, 2);
lcd.setContrast(30);
lcd.clear();
lcd.print("NOW");
lcd.setCursor(0, 1);
lcd.print("BOOTING!");
setupPort();
delay(10);
noInterrupts();
setupTCInt();
interrupts();
setupSensor();
MsTimer2::start(); // Timer inverval start
#ifdef SERIAL_MONITOR
Serial.println("");
Serial.println("=========================================");
Serial.println("loop start");
Serial.println("");
#endif
}
//-----------------------------------------------
// IOピンの入出力設定
// 接続するリーフに合わせて設定する
//-----------------------------------------------
void setupPort(){
}
//---------------------------------------------------------------------
// 各デバイスの初期設定
//---------------------------------------------------------------------
//------------------------------
// Sensor
//------------------------------
void setupSensor(){
//-------------------------------------
// LIS2DH (accelerometer)
//-------------------------------------
accel.begin(LIS2DH_ADDRESS);
accel.setClick(0, 0); // Disable Interrupt
accel.setRange(LIS3DH_RANGE_2_G); // Full scale +/- 2G
accel.setDataRate(LIS3DH_DATARATE_10_HZ); // Data rate = 10Hz
//-------------------------------------
// HTS221 (Humidity and Temperature sensor)
//-------------------------------------
smeHumidity.begin();
//-------------------------------------
// OPT3001 (Ambient Light Sensor)
//-------------------------------------
OPT3001_Config newConfig;
OPT3001_ErrorCode errorConfig;
light.begin(OPT3001_ADDRESS); // I2C address
newConfig.RangeNumber = B1100; // automatic full scale
newConfig.ConvertionTime = B1; // convertion time = 800ms
newConfig.ModeOfConversionOperation = B11; // continous conversion
newConfig.Latch = B0; // hysteresis-style
errorConfig = light.writeConfig(newConfig);
if(errorConfig != NO_ERROR){
errorConfig = light.writeConfig(newConfig); //retry
}
}
//=====================================================================
// 割り込み処理
//=====================================================================
//-----------------------------------------------
// 割り込み処理初期設定
// Timer interrupt (interval=125ms, int=overflow)
// メインループのタイマー割り込み設定
//-----------------------------------------------
void setupTCInt(){
MsTimer2::set(LOOP_INTERVAL, intTimer);
}
//----------------------------------------------
// Timer INT
// タイマー割り込み関数
//----------------------------------------------
void intTimer(){
bInterval = true;
}
//====================================================================
// loop
//====================================================================
//---------------------------------------------------------------------
// Main loop
//---------------------------------------------------------------------
void loop(){
//-----------------------------------------------------
// Timer interval 125ms で1回ループ
//-----------------------------------------------------
if (bInterval == true){
bInterval = false;
//--------------------------------------------
loopCounter(); // loop counter
//--------------------------------------------
// 1sに1回実行する
//--------------------------------------------
if (event1s == true){
event1s = false; // initialize parameter
loopSensor(); // sensor read
dispSencerData(); // LCD
}
}
}
//---------------------------------------------------------------------
// Counter
// メインループのループ回数をカウントし
// 1秒間隔でセンサーデータの取得をONにする
//---------------------------------------------------------------------
void loopCounter(){
iLoop1s += 1;
//--------------------
// 1s period
//--------------------
if (iLoop1s >= 8){ // 125ms x 8 = 1s
iLoop1s = 0;
event1s = true;
}
}
//---------------------------------------------------------------------
// Sensor
// センサーデータ取得がONのとき、各センサーからデータを取得
// コンソール出力がONのときシリアルに測定値と計算結果を出力する
//---------------------------------------------------------------------
void loopSensor(){
double temp_mv;
//-------------------------
// LIS2DH
// 3軸センサーのデータ取得
//-------------------------
accel.read();
dataX_g = accel.x_g; //X軸
dataY_g = accel.y_g; //Y軸
dataZ_g = accel.z_g; //Z軸
if(dataZ_g >= 1.0){
dataZ_g = 1.00;
} else if (dataZ_g <= -1.0){
dataZ_g = -1.00;
}
dataTilt = acos(dataZ_g)/PI*180;
//-------------------------
// HTS221
// 温湿度センサーデータ取得
//-------------------------
dataTemp = (float)smeHumidity.readTemperature(); //温度
dataHumid = (float)smeHumidity.readHumidity(); //湿度
//-------------------------
// 温度と湿度の2点補正
//-------------------------
dataTemp=TM0+(TM1-TM0)*(dataTemp-TL0)/(TL1-TL0); // 温度補正
dataHumid=HM0+(HM1-HM0)*(dataHumid-HL0)/(HL1-HL0); // 湿度補正
//-------------------------
// OPT3001
// 照度センサーデータ取得
//-------------------------
OPT3001 result = light.readResult();
if(result.error == NO_ERROR){
dataLight = result.lux;
}
//-------------------------
// ADC081C027(ADC)
// 電池リーフ電池電圧取得
//-------------------------
uint8_t adcVal1 = 0;
uint8_t adcVal2 = 0;
Wire.beginTransmission(BATT_ADC_ADDR);
Wire.write(0x00);
Wire.endTransmission(false);
Wire.requestFrom(BATT_ADC_ADDR,2);
adcVal1 = Wire.read();
adcVal2 = Wire.read();
if (adcVal1 == 0xff && adcVal2 == 0xff) {
//測定値がFFならバッテリリーフはつながっていない
adcVal1 = adcVal2 = 0;
}
//電圧計算 ADC * ((リファレンス電圧(3.3V)/ ADCの分解能(256)) * 分圧比(2倍))
temp_mv = ((double)((adcVal1 << 4) | (adcVal2 >> 4)) * 3300 * 2) / 256;
dataBatt = (float)(temp_mv / 1000);
//-------------------------
// シリアルモニタ表示
//-------------------------
#ifdef SERIAL_MONITOR
Serial.println("--- sensor data ---");
Serial.println(" Tmp[degC] = " + String(dataTemp));
Serial.println(" Hum[%] = " + String(dataHumid));
Serial.println(" Lum[lx] = " + String(dataLight));
Serial.println(" Ang[arc deg] = " + String(dataTilt));
Serial.println(" Bat[V] = " + String(dataBatt));
#endif
}
//---------------------------------------
// Disp sensor data
// センサーデータを文字列に変換してLCDに表示する
//---------------------------------------
void dispSencerData(){
float value;
char temp[7], humid[7], light[7], tilt[7], battVolt[7];
char sendData[40];
//-----------------------------------
//センサーデータを文字列に変換
//dtostrf(変換する数字,変換される文字数,小数点以下の桁数,変換した文字の格納先);
//変換される文字数を-にすると変換される文字は左詰め、+なら右詰めとなる
//-----------------------------------
//-------------------------
// Temperature (4Byte)
//-------------------------
value = dataTemp;
if(value >= 100){
value = 99.9;
}
else if(value <= -10){
value = -9.9;
}
dtostrf(value,4,1,temp);
//-------------------------
// Humidity (4Byte)
//-------------------------
value = dataHumid;
dtostrf(value,4,1,humid);
//-------------------------
// Ambient Light (5Byte)
//-------------------------
value = dataLight;
if(value >= 100000){
value = 99999;
}
dtostrf(value,5,0,light);
//-------------------------
// Tilt (4Byte)
//-------------------------
value = dataTilt;
if(value < 3){
value = 0;
}
dtostrf(value,4,0,tilt);
//-------------------------
// Battery Voltage (4Byte)
//-------------------------
value = dataBatt;
if (value >= 10){
value = 9.99;
}
dtostrf(value, 4, 2, battVolt);
//-------------------------
trim(temp);
trim(humid);
trim(light);
trim(tilt);
trim(battVolt);
lcd.clear();
switch (lcdSendCount){
case 0: // Tmp XX.X [degC]
lcd.print("Temp");
lcd.setCursor(0, 1);
lcd.print( String(temp) +" C");
break;
case 1: // Hum xx.x [%]
lcd.print("Humidity");
lcd.setCursor(0, 1);
lcd.print( String(humid) +" %");
break;
case 2: // Lum XXXXX [lx]
lcd.print("Luminous");
lcd.setCursor(0, 1);
lcd.print( String(light) +" lx");
break;
case 3: // Ang XXXX [arc deg]
lcd.print("Angle");
lcd.setCursor(0, 1);
lcd.print( String(tilt) +" deg");
break;
case 4: // Bat X.XX [V]
lcd.print("Battery");
lcd.setCursor(0, 1);
lcd.print( String(battVolt) +" V");
break;
default:
break;
}
if (lcdSendCount < 4){
lcdSendCount++;
}
else{
lcdSendCount = 0;
}
}
//---------------------------------------
// trim
// 文字列配列からSPを削除する
//---------------------------------------
void trim(char * data){
int i = 0, j = 0;
while (*(data + i) != '\0'){
if (*(data + i) != ' '){
*(data + j) = *(data + i);
j++;
}
i++;
}
*(data + j) = '\0';
}
//=====================================================================
// I2C 制御関数
//=====================================================================
//-----------------------------------------------
//I2C スレーブデバイスに1バイト書き込む
//-----------------------------------------------
void i2c_write_byte(int device_address, int reg_address, int write_data){
Wire.beginTransmission(device_address);
Wire.write(reg_address);
Wire.write(write_data);
Wire.endTransmission();
}
//-----------------------------------------------
//I2C スレーブデバイスから1バイト読み込む
//-----------------------------------------------
unsigned char i2c_read_byte(int device_address, int reg_address){
int read_data = 0;
Wire.beginTransmission(device_address);
Wire.write(reg_address);
Wire.endTransmission(false);
Wire.requestFrom(device_address, 1);
read_data = Wire.read();
return read_data;
}
実行結果
温度 → 湿度 → 照度 → 角度 → バッテリ残量の順に液晶の表示が変わります。
最終更新 June 30, 2021