センサの値を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

リーフの組立

assemble1

ソースコード

  • 書き込みには、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;
}

4-Sensors_LCD.ino

実行結果

温度 → 湿度 → 照度 → 角度 → バッテリ残量の順に液晶の表示が変わります。

overview

前のページに戻る


最終更新 June 30, 2021