01-05-2021 06:41 PM
ESP32はWiFiとブルートゥースを内蔵したマイクロコントローラで、Arduino IDEでもプログラミングができます。「ESP32でLINX」で紹介したM5StickCもESP32を使用しています。
「ESP32でLINX(その2)」では使用できるピン数が豊富で安価な「ESP32 MH-LIVE Mini Kit」をLabVIEW LINXで使ってみます。LEDを光らせる「LINX-Blink(Simple)(TCP)」で基本動作を確認して、I2C接続の空気品質センサー「CCS811」を接続します。
記事はこま切れになりますが、
(1)「ESP32 MH-LIVE Mini Kit」とTANAKA Masayuki氏の「LinxESP32」ライブラリを使って「LINX-Blink(Simple)(TCP)」でデジタル出力の確認と、
(2)CCS811空気品質センサーの紹介、
(3)「LinxESP32」ライブラリ(2行改変)でI2C接続のCCS811空気品質センサーを使ってみる。
という流れで書いてみようと思います。
WiFi接続のLINXデバイスは使いようがありそうだということを感じてもらえるでしょうか?
2021.1.06
01-05-2021 11:12 PM - 編集済み 01-05-2021 11:15 PM
ESP32を使ったボードは多数ありますが、私はコンパクトでIOピンが多数ある「MH ET LIVE ESP32MiniKit」を愛用しています。
$6から$8ぐらいの値段でピンソケットが付属しています。
ボードの裏側にピン名が印刷されていますが、裏返しにして名前を確認したあとで、ピンを差し込むときに場所を間違えやすいので注意が必要です。
各ピンの機能は以下のサイトの情報を参考にしてください。
ESP32 MH-ET LIVE Mini Kitのピン配置
例えば、IO21ピンはデジタル入出力21としても使えますが、I2CではSDAピンとして使われます。また、IO22ピンはデジタル入出力22としても使えますが、I2CではSCLピンとして使われます。いまのところLINXからは使えないと思いますが、ESP32の面白い機能としてタッチセンサーが10個あります。
ESP32でLINXを使う方法については、以下のサイトに必要十分な分かりやすい説明があります。
ESP32でLINX for LabVIEW入門 その1 環境構築とLチカ
Arduino IDEのダウンロード
Arduino IDEへのESP32ボード群の登録
Arduino IDEを起動して、ファイルメニューの”環境設定”を開き、”追加のボードマネージャーのURL”欄に以下のサイトに書かれている”Stable release link: ”のURLを転記します。
OKボタンを押して、ツールメニューのボード欄からボードマネージャーを開いて、ESP32のボード群をインストールします。
Arduino IDEへのESP32ボード群の登録に関してすごく詳しく書いてあるサイトがありました。
Arduino IDEにESP32ボード群が登録されれば、ツールメニューのボード欄には"MH ET LIVE ESP32MiniKit"があらわれますので、それを選択します。
ここまでで、MH ET LIVE ESP32MiniKitがArduino IDEで使えるようになりました。
Arduino IDEでプログラムの書き込みができるかどうか、LEDを点滅するサンプルスケッチ"Blink"で試します。MH ET LIVE ESP32MiniKitには点滅できるLEDは内蔵されていませんので、IO16ピンにLEDのプラス側を接続し、適当な抵抗を介してグラウンドに落とします。
サンプルスケッチ"Blink"に次の一行を追加してIO16ピンが点滅するようにします。
#define LED_BUILTIN 16
/*
Blink
Turns an LED on for one second, then off for one second, repeatedly.
*/
#define LED_BUILTIN 16
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(100); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(100); // wait for a second
}
ツールメニューのシリアルポートを指定して、上部の右矢印アイコンをクリックしてスケッチを書き込みます。書き込みが終わって、LEDが点滅すればOKです。
2021.01.06
01-06-2021 02:23 AM
Arduino用LINXファームウェアは、LINXでサポートされているデバイスの場合はFirware Wizardからアップロードされます。
Arduinoに書き込まれたLINXファームウェアは、PC上のLabVIEWからのコマンドに応じてプログラムを実行し、実行結果を返します。複雑で全容がつかみにくいですが、基本は"Blink.ino"と同じようなプログラムなので、Arduino IDEからも書き込むことができます。
ESP32用のLINXファームウェアはArduino用のライブラリとして提供されていて、Arduino IDEを使用してアップロードします。Arduino IDEへのライブラリの追加は、スケッチメニュー >> ライブラリをインクルード >> ライブラリを管理...とたどります。
ライブラリマネージャが開きますので、”LINX"でフィルターをかけます。LinxESP32が表示されますので、これをインストールします。
インストールするとファイルメニューのスケッチ例に"LinxESP32"が現れます。ESP32_WiFiを選択します。
これを書き込めばWiFiで接続できるLINXデバイスになりますが、アクセスポイントの設定が必要です。
ESP32は最後に接続されたWiFiアクセスポイントを記憶しているということなので、Lang-Shipさんの記事 の”LinxESP32ライブラリ追加”以降を参照してください。
インストールされたライブラリは(私のPC環境では)ドキュメントのArduino > libraries > LinxESP32に格納されています。
LinxESP32は現時点でバージョン0.1.1で、各機能を検証しながらライブラリを調整中とのことです。I2Cについてはまだブログに掲載されていませんので、検証中ということだと思いますが、様子見ということで使わせてもらおうと思います。バージョン0.1.1ではコメントアウトでI2Cが死んでいるので、LinxWiringDevice.cppファイルのコメントアウトを外してみました。他の機能に害は与えないと思いますが、もっと良い外し方があるかもしれません。(ArduinoMega2560用のLINXライブラリと見比べて見当をつけました。)
int LinxWiringDevice::I2cOpenMaster(unsigned char channel)
{
if (*(I2cRefCount + channel) > 0)
{
//Channel Already Open, Increment Ref Count
//*(I2cRefCount + channel) = *(I2cRefCount + channel) + 1;
*(I2cRefCount + channel) = *(I2cRefCount + channel) + 1;
}
else
{
//Channel Not Yet Open, Open And Set Refcount = 1
//Wire.begin(); //TODO ONLY SUPPORT ONE CHANNEL ATM
Wire.begin(); //TODO ONLY SUPPORT ONE CHANNEL ATM
}
return 0;
}
ESP32_WiFi.inoの中にもWire.begin();(ArduinoではI2CのことをWireと呼ぶ慣例があります)がコメントアウトされているので、そっちを外しても良いかもしれません。
また、ESP32は2チャンネルのI2Cがあるのですが今回使っているのはデフォルトのSDA/21pin,SCL/22pinだけです。
WiFiの接続ができるようにしてから、シリアルモニターのボーレートを115200にしてESP32_WiFi.inoを書き込みます。LINXで接続するために必要なIPアドレスとポート番号が表示されますのでメモします。
2021.01.06
01-06-2021 05:42 AM
I2Cを機能させるための一時的な変更は、わかりやすい方が良いだろうと考えなおしました。
LinxWiringDevice.cppファイルの変更はやめて、ESP32_WiFi.inoを変更しました。
ESP32_WiFi.inoを別名で保存して下記の// 21.01.06_modと書かれた2行を追加します。
#include <LinxESP32.h>
#include <Wire.h> //21.01.06_mod
//Create A Pointer To The LINX Device Object We Instantiate In Setup()
LinxESP32* LinxDevice;
//Initialize LINX Device And Listener
void setup()
{
//Instantiate The LINX Device
LinxDevice = new LinxESP32();
// PWM & Servo Setup
uint8_t pwmList[] = {}; // Max16Ch {0, 26, ...}
uint16_t pwmFrequency = 12000; // LED:12000, Servo:50
for (int i = 0; i < sizeof(pwmList); i++) {
ledcSetup(i, pwmFrequency, 8);
pinMode(pwmList[i], OUTPUT);
ledcAttachPin(pwmList[i], i);
}
// I2C Begin ch0:Wire, ch1:Wire1
//Wire.begin();
Wire.begin(); //21.01.06_mod
//Wire1.begin(32, 33);
// The LINX Listener Is Pre Instantiated.
2021.01.06
01-06-2021 07:27 AM
CCS811は比較的安価なCO2センサーです。
I2CアドレスはADD_pin=HIGHで0x5B、ADD_pin=LOWで0x5Aとなります。
WAK_pinはI2C通信中はLOWにする必要があります。
INT_pinとRST_pinはここでは使いません。
VCC_pinは3.3Vを接続します。
GNG_pinはGNDに接続します。
SCL_pinはIO22に接続します。
SDA_pinはIO21に接続します。
Arduino用のライブラリはSparkFunがライブラリを用意してくれているので、
サンプルスケッチ Example1_BasicReadings.inoのように
CCS811 mySensor(CCS811_ADDR)
mySensor.begin()
mySensor.dataAvailable()
mySensor.readAlgorithmResults()
mySensor.getCO2()
mySensor.getTVOC()
などを使って空気品質を測定することができます。
LINXでは基本的に素の状態でデータシートを見ながらI2Cで読み書きすることになります。
それはかなり厄介なので、LINXを使うか、ArduinoをセンサーとのインターフェースにしてデータだけLabVIEWで受け取るか、全体のバランスを良く考えることが重要です。
ライブラリを読み解きながら、ライブラリ不要のArduinoスケッチを作成するのも良い方法だと思います。こうしておけば、LINXの関数で置き換えていけます。
//CCS811 Ultra-Low Power Digital Gas Sensor for Monitoring Indoor Air Quality
//for ESP32MiniKit
//Koji Ohashi
//http://keisoku-lab.mond.jp/
//CJMCU-811
//WAK pin should be LOW during I2C communication
#include <Wire.h>
#define CCS811_ADDR 0x5B //Default I2C Address [ADDR pin HIGH]
//#define CCS811_ADDR 0x5A //Alternate I2C Address [ ADDR pin LOW]
#define MEAS_MODE 0x01
#define APP_START 0xF4
#define SW_RESET 0xFF
int Time0=0;
void setup()
{
Serial.begin(115200);
Serial.println("ESP32MiniKit_CCS811");
Wire.begin(21,22); //Wire.begin(SDA, SCL)
startApp(); //Start to Communicate
setMode(1); //0:idle, 1:1sec, 2:10sec, 3:60sec,
}
void loop()
{
if (dataReady())
{
readData();
Time0=millis();
}
else {
int TimeNow=millis()-Time0;
if (TimeNow > 10000){
resetSensor();
Time0=millis();
}
}
delay(100);
}
void resetSensor(){
Wire.beginTransmission(CCS811_ADDR);
Wire.write(SW_RESET);
Wire.write(0x11);
Wire.write(0xE5);
Wire.write(0x72);
Wire.write(0x8A);
Wire.endTransmission();
Serial.println("SW_RESET");
delay(100);
startApp();
}
void startApp(){
Wire.beginTransmission(CCS811_ADDR);
Wire.write(APP_START);
Wire.endTransmission();
}
void setMode(byte operation){
byte val=operation<<4;//DRIVE_MODE bit6-4
Wire.beginTransmission(CCS811_ADDR);
Wire.write(MEAS_MODE);
Wire.write(val);
Wire.endTransmission();
}
void readData(){
Wire.beginTransmission(CCS811_ADDR);
Wire.write(0x02);
Wire.endTransmission();
Wire.requestFrom(CCS811_ADDR, 4);
while (Wire.available()) {
byte val1 = Wire.read();
byte val2 = Wire.read();
byte val3 = Wire.read();
byte val4 = Wire.read();
int CO2=val1*256+val2;
int TVOC=val3*256+val4;
Serial.print(CO2);
Serial.print(",");
Serial.println(TVOC);
}
}
boolean dataReady(){
boolean newData=false;
Wire.beginTransmission(CCS811_ADDR);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom(CCS811_ADDR, 1);
while (Wire.available()) {
byte val = Wire.read();
newData = (val & 0x08) > 0 ;
}
return newData;
}
CCS811のDatasheet の15ページに書かれているCCS811 Application Register Mapとそれ以降のレジスタの説明を見ればArduinoスケッチの内容が確認できると思います。
電源オン直後は、ブートモードになっているので、レジスタアドレス0xF4を書き込んでアプリケーションモードにする必要があります。これは24ページに書いてあります。
ライブラリを使って動かして、ライブラリを外して動かして、LINXに持っていく、、というのが近道なのではないかと思います。もちろんデータシートを隅々まで読み解いてからプログラムを書くタイプの人も多いとは思いますが、、。
2021.01.06
01-06-2021 10:09 PM
サブVIにまとめずに書き出してみました。Arduinoのスケッチとほぼ同じですので、対応させてみればわかりやすいと思います。
1チャンネルだけですが、一応I2Cが動いていますのでESP32をLINXで使う利用範囲は広いと思います。
時々原因不明のエラーがでて、誤ったデータが出力されます。前回値よりもかけ離れた数値の時にはそのデータは使わないなどの処理で逃げられるレベルかなと思います。
WiFiに接続をします。一発でつながることもありますが、何回かトライする必要がある場合もありました。
I2C通信を開始します。
0xF4を書き込むとセンサーはブートモードからアプリケーションモードになります。ブートモードのままでは測定できません。
レジスタ0x01に0x10を書き込むと1秒間隔で測定するモードになります。なので、0x01と0x10を連続で書き込みます。書き込みのルールはセンサーごとに異なりますので、データシートを確認する必要があります。
データ更新とエラー状態はレジスタ0x00に書かれていますので、読み取るレジスタ0x00を書き込んだ後で、1バイト読み取ります。1バイトのデータの中で、第0ビットがエラー状態、第3ビットが新しいデータ有無を示します。
0:新データなしでエラーなし、1:新データありでエラーなし、2と3:エラーありの3状態でケース分けします。0の場合は何もしません。2と3の場合は2秒間待ちます。1の場合にデータを読み取ります。
レジスタ0x02にCO2とTVOCそれぞれ2バイトのデータで合計4バイトの新しいデータがありますので、読み取るレジスタ0x02を書き込んだ後で、4バイト読み取ります。I32にしてチャートに表示します。
新しいデータが読み込まれた時にはLEDを光らせます。ストップボタンが押されるとループを抜けて、I2Cを終了し、LINXも終了します。
WiFi接続のLINXデバイスは使いようがありそうだということを感じてもらえるでしょうか?
2021.01.07
とりあえず、I2Cが1チャンネル使える状態に改変した"ESP32_Wifi_mod.ino"も添付しておきます。TANAKA Masayuki氏の「LinxESP32」ライブラリをインストールしてある状態で"ESP32_Wifi_mod.ino"をMH-LIVE ESP32 Mini Kitに書き込めばOKだと思います。