M5 ATOM Lite ENVⅲセンサーを使う
今回は、ATOM Lite に、ENV3センサー を接続して
温度、湿度、気圧を計測して、SSD1306液晶に表示させます。
<開発環境 追加ライブラリー>
開発環境 VScode + PlataformIO
・M5ATOM by M5Stack
・FastLED by Daniel Garcia
・LovyanGFX by lovyan03
・M5Unit-ENV byM5Stack
<M5 ENV3センサー>
ENV3には2つのモジュールが入っています。
SHT30:気温、湿度センサー
QMP6988:気圧センサー(現地気圧)
※海面気圧(sea level pressure)と現地気圧(station pressure)は違います。
だいたい高度10mで、約1hPaの割合で低くなります。
<M5 ENV3センサー初期化方法>
SHT30,QMP6988ともにarduinoのWire0を使用します。
Wire0を初期化したのち、
SHT30とQMP6988の両方の、初期関数を呼び出します。
#include "myENV3.h"
/// @brief myENV3クラスコンストラクタ
myENV3::myENV3()
{
sht30.init();
qmp6988.init();
}
<ESP32のタイマー割り込みを使う方法>
ENV3センサーの読み取り間隔を、
ESP32のタイマー割り込みを使って設定します。
Tickerクラス内にあるattach_ms関数を使用して、
割込み処理関数を登録し、割込み時に呼び出せるようにします。
ESP32ライブラリ Ticker.h 45行目
void attach_ms(uint32_t milliseconds, callback_t callback
{
_attach_ms(milliseconds, true, reinterpret_cast<callback_with_arg_t>(callback), 0);
}
ESP32ライブラリ Ticker.cpp 34行目
void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, uint32_t arg) {
esp_timer_create_args_t _timerConfig;
_timerConfig.arg = reinterpret_cast<void*>(arg);
_timerConfig.callback = callback;
_timerConfig.dispatch_method = ESP_TIMER_TASK;
_timerConfig.name = "Ticker";
if (_timer) {
esp_timer_stop(_timer);
esp_timer_delete(_timer);
}
esp_timer_create(&_timerConfig, &_timer);
if (repeat) {
esp_timer_start_periodic(_timer, milliseconds * 1000ULL);
} else {
esp_timer_start_once(_timer, milliseconds * 1000ULL);
}
}
<C++ reinterpret_cast 演算子>
C++で使用されるキャスト演算子。
ポインターが他のポインター型に変換。
整数型から任意のポインター型への変換およびその逆の変換する。
reinterpret_cast 演算子は、本質的に安全でない char* から int* へ、One_class* から Unrelated_class* へなどの変換に使用できます。
<今回のソースコード>
<main.c>
#include <M5ATOM.h>
#include "myLovyanGFX.h"
#include "myENV3.h"
#include "myInterrupt.h"
//グローバル変数********************************************************
uint colorNumber=0;//RGBLEDの色配列指定
int color[3]={0xFF0000,0x008000, 0x0000FF};//RGBLED Red(8),Green(8),Blue(8)
myENV3* env3;
//LovyanGFXインスタンス*************************************************
static LGFX_SSD1306 lcd;
static LGFX_Sprite canvas(&lcd); //スプライトバッファ
/***************************************************************
* setup
**************************************************************/
void setup()
{
int i;
//ATOM初期化---------------------------------------------------------
M5.begin(true,false, true); //初期化(UART, I2C wire0 , LED)
//割り込み処理-------------------------------------------------------
myInterrupt();//割り込み初期化
//SSD1306初期化 LovyanGFX--------------------------------------------
lcd.init();
canvas.createSprite(lcd.width(), lcd.height());
canvas.setTextWrap(false); //自動折返し:無し
//ENV3初期化---------------------------------------------------------
Wire.begin(26,32,400000U);
env3 = new myENV3();
//SSD1306初期描画-----------------------------------------------------
canvas.beginTransaction();/// 通信トランザクションを開始する。(ペリフェラルを占有する);
canvas.fillScreen(TFT_BLACK); //背景塗り潰し
canvas.setTextColor(TFT_WHITE); //文字色
canvas.setFont(&fonts::Font4);
canvas.setTextSize(0.8);
canvas.drawString("EVN3",5,0);
canvas.pushSprite(0,0);
canvas.endTransaction();/// 通信トランザクションを終了する。(ペリフェラルの占有を終了する);
//RGBLED点灯
M5.dis.drawpix(0,color[2]);//blue点灯
delay(500);
}
/**************************************************************
* メインループ
****************************************************************/
void loop()
{
if(Ticker2.flag)
{
Ticker2.flag=false;
M5.dis.drawpix(0,color[0]);//red点灯
if(env3->sht30.get()==0)
{
env3->tmp = env3->sht30.cTemp;
env3->humi = env3->sht30.humidity;
Serial.printf(
"Temp: %2.1f \r\nHumi: %2.0f%% \r\nPressure:%2.0fPa\r\n---\n",
env3->tmp,env3->humi,env3->pressure);
canvas.beginTransaction();
canvas.fillScreen(TFT_BLACK); //背景塗り潰し
canvas.setCursor(3,25);
canvas.printf("%2.1fC",env3->tmp);
canvas.setCursor(60,25);
canvas.printf("%2.1f%%",env3->humi);
env3->pressure = env3->qmp6988.calcPressure()/100;
canvas.setCursor(3,45);
canvas.printf("%4.1fhPa",env3->pressure);
canvas.pushSprite(0,0);
canvas.endTransaction();
}else
{
env3->tmp=0;
env3->humi=0;
}
M5.dis.drawpix(0,color[2]);//blue点灯
}
delay(10);
}
<myInterrupt.h>
割り込み処理で使う構造体と関数、クラスの宣言をしています。
#ifndef _myINTERRUPT_H_
#define _myINTERRUPT_H_
#include <M5Atom.h>
#include <Ticker.h>
/// @brief timer割り込み構造体
typedef struct{
Ticker ticker; //ESP32Tickerクラス
bool flag; //time up flag
int Count; //counter
}_myTickerInterrupt;
/// @brief タイマー割り込み構造体
extern _myTickerInterrupt Ticker1,Ticker2, Ticker3;
/// @brief 割り込み処理クラス
class myInterrupt
{
public:
myInterrupt(); //コンストラクタ
};
/// @brief Ticker2割り込み処理関数
void Ticker2Int();
#endif //_myINTERRUPT_H_
<myInterrupt.cpp>
割り込み処理で使う構造体と関数、クラスメンバの実装。
#include "myInterrupt.h"
_myTickerInterrupt Ticker1,Ticker2, Ticker3;
myInterrupt myInt;
/// @brief 割り込み処理クラスコンストラクタ
myInterrupt::myInterrupt()
{
Ticker2.flag=false;
Ticker2.Count=0;
//Ticker初期化
Ticker2.ticker.attach_ms(1000,Ticker2Int);
}
/// @brief Ticker2割り込み処理関数
void Ticker2Int()
{
Ticker2.Count++;
if(Ticker2.Count==3)//1000ms*x
{
Ticker2.Count=0;
Ticker2.flag=true;
}
}
<myENV3.h>
ENV3センサーの処理で使うクラス宣言。
#ifndef _myENV3_H_
#define _myENV3_H_
#include <M5ATOM.h>
#include "M5_ENV.h"
/// @brief myENV3クラス
class myENV3
{
public:
float tmp; //温度
float humi; //湿度
float pressure; //気圧
SHT3X sht30; //SHT30インスタンス
QMP6988 qmp6988;//QMP6988インスタンス
public:
myENV3();//コンストラクタ
};
#endif //_myENV3_H_
<myENV.cpp>
#include "myENV3.h"
/// @brief myENV3クラスコンストラクタ
myENV3::myENV3()
{
sht30.init();
qmp6988.init();
}
<myLovyanGFX.h>
SSD1306液晶をLovyanGFXを使って描画するための準備をしています。
#ifndef _myLOVYANGFX_H_
#define _myLOVYANGFX_H_
#include <M5ATOM.h>
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
// コンストラクタを作成し、ここで各種設定を行います。
class LGFX_SSD1306 : public lgfx::LGFX_Device
{
lgfx::Panel_SSD1306 _panel_instance; // SSD1306構造体のインスタンス
lgfx::Bus_I2C _bus_instance; // バス設定用の構造体を取得します。
// コンストラクタ
public:
LGFX_SSD1306()
{
{ //I2Cバスクラスの構造体に設定。
auto cfg = _bus_instance.config(); // I2Cバス構造体インスタンスの取得
cfg.i2c_port = 1; // 使用するI2Cポートを選択 (0 or 1)Wire0, Wire1の選択
cfg.freq_write = 400000; // 送信時のクロック クロック周波数
cfg.freq_read = 400000; // 受信時のクロック クロック周波数
cfg.pin_sda = 25; // SDAを接続しているピン番号 SDAピン
cfg.pin_scl = 21; // SCLを接続しているピン番号 SCLピン
cfg.i2c_addr = 0x3C; // I2Cデバイスのアドレス スレーブアドレス
_bus_instance.config(cfg); //設定値をバスに反映します。
_panel_instance.setBus(&_bus_instance); //バスをパネルにセットします。
}
{ // 表示パネル制御の設定を行います。
auto cfg = _panel_instance.config();
// 以下はST7735やILI9163のようにピクセル数が可変のドライバで表示がずれる場合にのみ設定してください。
//cfg.memory_width = 128; // ドライバICがサポートしている最大の幅
//cfg.memory_height = 64; // ドライバICがサポートしている最大の高さ
cfg.offset_rotation = 2; //回転方向のオフセット 0~7 (4~7は上下反転)
_panel_instance.config(cfg); //再設定
}
setPanel(&_panel_instance); // 使用するパネルをセットします。
}
};
#endif //_myLOVYANGFX_H_