実現したいこと
- SHT30(温湿度センサ)とSGP30(ガスセンサ)の値を競合を回避して両方取得したい
前提
M5StickC PlusのHat端子にENV II Hat(SHT30温湿度センサ)、Grove端子にSGP30ガスセンサを同時に接続しています。まず、ENV II Hatの公式サンプルから不要な気圧部分を削除した下記のコードで温湿度単体で正常に値を取得できることを確認しました。
cpp
1#include <M5StickCPlus.h> 2#include "M5_ENV.h" 3 4SHT3X sht30; 5 6float tmp = 0.0; 7float hum = 0.0; 8 9void setup() { 10 M5.begin(); 11 M5.Lcd.setRotation(1); 12 Wire.begin(0, 26); 13 sht30.init(); 14 M5.Lcd.println(F("ENVII Unit(SHT30) test...\n")); 15} 16 17void loop() { 18 sht30.get(); 19 tmp = sht30.cTemp; 20 hum = sht30.humidity; 21 M5.Lcd.setCursor(0, 20); 22 M5.Lcd.fillRect(0, 20, 100, 60, BLACK); 23 M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\n", tmp, hum); 24 delay(2000); 25}
次にSGP30の公式サンプルを参考にしながら、画面表示処理を上記のコードに似せた下記のコードでガスセンサ単体でも正常に値を取得できることを確認しました。
cpp
1#include <M5StickCPlus.h> 2#include "Adafruit_SGP30.h" 3 4Adafruit_SGP30 sgp; 5 6uint16_t tvoc = 0; 7uint16_t eco2 = 0; 8 9void setup() { 10 M5.begin(); 11 M5.Lcd.setRotation(1); 12 sgp.begin(); 13 M5.Lcd.println(F("SGP30 test...\n")); 14} 15 16void loop() { 17 sgp.IAQmeasure(); 18 tvoc = sgp.TVOC; 19 eco2 = sgp.eCO2; 20 M5.Lcd.setCursor(0, 20); 21 M5.Lcd.fillRect(0, 20, 100, 60, BLACK); 22 M5.Lcd.printf("TVOC: %4.0u ppb \r\neCO2: %4.0u ppm \r\n", tvoc, eco2); 23 delay(2000); 24}
そして温湿度どガスセンサ両方の値を得るために上記2つのコードを組み合わせた下記のコードでは、温湿度は正常に取得できてガスセンサの値は取得できないという結果になりました。
cpp
1#include <M5StickCPlus.h> 2#include "M5_ENV.h" 3#include "Adafruit_SGP30.h" 4 5SHT3X sht30; 6Adafruit_SGP30 sgp; 7 8float tmp = 0.0; 9float hum = 0.0; 10uint16_t tvoc = 0; 11uint16_t eco2 = 0; 12 13void setup() { 14 M5.begin(); 15 M5.Lcd.setRotation(1); 16 Wire.begin(0, 26); 17 sht30.init(); 18 sgp.begin(); 19 M5.Lcd.println(F("SHT30 & SGP30 test...\n")); 20} 21 22void loop() { 23 sht30.get(); 24 tmp = sht30.cTemp; 25 hum = sht30.humidity; 26 sgp.IAQmeasure(); 27 tvoc = sgp.TVOC; 28 eco2 = sgp.eCO2; 29 M5.Lcd.setCursor(0, 20); 30 M5.Lcd.fillRect(0, 20, 100, 60, BLACK); 31 M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\n", tmp, hum); 32 M5.Lcd.printf("TVOC: %4.0u ppb \r\neCO2: %4.0u ppm \r\n", tvoc, eco2); 33 delay(2000); 34} 35
setup関数内の
Wire.begin(0, 26);
sht30.init();
と
sgp.begin();
の順序を入れ替えると逆にガスセンサの値は正常に取得できて温湿度が取得できないという状態になったため、おそらくI2Cまわりで競合が発生していることまでは分かったのですが、その修正方法が分からない状態です。
試したこと
・このサイトを参考に都度Wire.begin()する下記のコードを試したのですが、結果は温湿度が正常でガスセンサは値なしでした。
cpp
1#include <M5StickCPlus.h> 2#include "M5_ENV.h" 3#include "Adafruit_SGP30.h" 4 5SHT3X sht30; 6Adafruit_SGP30 sgp; 7 8float tmp = 0.0; 9float hum = 0.0; 10uint16_t tvoc = 0; 11uint16_t eco2 = 0; 12 13void setup() { 14 M5.begin(); 15 M5.Lcd.setRotation(1); 16 Wire.begin(0, 26); 17 sht30.init(); 18 Wire.begin(32, 33); 19 sgp.begin(); 20 M5.Lcd.println(F("SHT30 & SGP30 test...\n")); 21} 22 23void loop() { 24 Wire.begin(0, 26); 25 sht30.get(); 26 tmp = sht30.cTemp; 27 hum = sht30.humidity; 28 Wire.begin(32, 33); 29 sgp.IAQmeasure(); 30 tvoc = sgp.TVOC; 31 eco2 = sgp.eCO2; 32 M5.Lcd.setCursor(0, 20); 33 M5.Lcd.fillRect(0, 20, 100, 60, BLACK); 34 M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\n", tmp, hum); 35 M5.Lcd.printf("TVOC: %4.0u ppb \r\neCO2: %4.0u ppm \r\n", tvoc, eco2); 36 delay(2000); 37}
・このサイトを参考にWireとWire1を使用する下記のコードを試したのですが、結果は温湿度が0でガスセンサの値は正常でした。
cpp
1#include <M5StickCPlus.h> 2#include "M5_ENV.h" 3#include "Adafruit_SGP30.h" 4 5SHT3X sht30; 6Adafruit_SGP30 sgp; 7 8float tmp = 0.0; 9float hum = 0.0; 10uint16_t tvoc = 0; 11uint16_t eco2 = 0; 12 13void setup() { 14 M5.begin(); 15 M5.Lcd.setRotation(1); 16 Wire1.begin(0, 26); 17 sht30.init(); 18 Wire.begin(32, 33); 19 sgp.begin(); 20 M5.Lcd.println(F("SHT30 & SGP30 test...\n")); 21} 22 23void loop() { 24 sht30.get(); 25 tmp = sht30.cTemp; 26 hum = sht30.humidity; 27 sgp.IAQmeasure(); 28 tvoc = sgp.TVOC; 29 eco2 = sgp.eCO2; 30 M5.Lcd.setCursor(0, 20); 31 M5.Lcd.fillRect(0, 20, 100, 60, BLACK); 32 M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\n", tmp, hum); 33 M5.Lcd.printf("TVOC: %4.0u ppb \r\neCO2: %4.0u ppm \r\n", tvoc, eco2); 34 delay(2000); 35}
・TwoWireを事前に2つ宣言してsht30.init()とsgp.begin()の引数に渡す下記のコードを試したのですが、結果は温湿度が0でガスセンサの値は正常でした。
cpp
1#include <M5StickCPlus.h> 2#include "M5_ENV.h" 3#include "Adafruit_SGP30.h" 4 5SHT3X sht30; 6Adafruit_SGP30 sgp; 7 8TwoWire wireSGP30 = TwoWire(0); 9TwoWire wireSHT30 = TwoWire(1); 10 11float tmp = 0.0; 12float hum = 0.0; 13uint16_t tvoc = 0; 14uint16_t eco2 = 0; 15 16void setup() { 17 M5.begin(); 18 M5.Lcd.setRotation(1); 19 sht30.init(0x44, &wireSHT30); 20 sgp.begin(&wireSGP30); 21 M5.Lcd.println(F("SHT30 & SGP30 test...\n")); 22} 23 24void loop() { 25 sht30.get(); 26 tmp = sht30.cTemp; 27 hum = sht30.humidity; 28 sgp.IAQmeasure(); 29 tvoc = sgp.TVOC; 30 eco2 = sgp.eCO2; 31 M5.Lcd.setCursor(0, 20); 32 M5.Lcd.fillRect(0, 20, 100, 60, BLACK); 33 M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\n", tmp, hum); 34 M5.Lcd.printf("TVOC: %4.0u ppb \r\neCO2: %4.0u ppm \r\n", tvoc, eco2); 35 delay(2000); 36}
・y_waiwaiさんの回答を受けてTwoWireを1つにした下記のコードを試したのですが、結果は温湿度が0でガスセンサの値は正常でした。
cpp
1#include <M5StickCPlus.h> 2#include "M5_ENV.h" 3#include "Adafruit_SGP30.h" 4 5SHT3X sht30; 6Adafruit_SGP30 sgp; 7 8TwoWire wire = TwoWire(0); 9 10float tmp = 0.0; 11float hum = 0.0; 12uint16_t tvoc = 0; 13uint16_t eco2 = 0; 14 15void setup() { 16 M5.begin(); 17 M5.Lcd.setRotation(1); 18 sht30.init(0x44, &wire); 19 sgp.begin(&wire); 20 M5.Lcd.println(F("SHT30 & SGP30 test...\n")); 21} 22 23void loop() { 24 sht30.get(); 25 tmp = sht30.cTemp; 26 hum = sht30.humidity; 27 sgp.IAQmeasure(); 28 tvoc = sgp.TVOC; 29 eco2 = sgp.eCO2; 30 M5.Lcd.setCursor(0, 20); 31 M5.Lcd.fillRect(0, 20, 100, 60, BLACK); 32 M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\n", tmp, hum); 33 M5.Lcd.printf("TVOC: %4.0u ppb \r\neCO2: %4.0u ppm \r\n", tvoc, eco2); 34 delay(2000); 35}
・y_waiwaiさんの回答を受けてTwoWireを1つにしてセンサの初期化処理をloop内に移した下記のコードを試したのですが、結果は温湿度が0でガスセンサの値はTVOCが非表示でeCO2が400でフリーズしている状態でした。
cpp
1#include <M5StickCPlus.h> 2#include "M5_ENV.h" 3#include "Adafruit_SGP30.h" 4 5SHT3X sht30; 6Adafruit_SGP30 sgp; 7 8TwoWire wire = TwoWire(0); 9 10float tmp = 0.0; 11float hum = 0.0; 12uint16_t tvoc = 0; 13uint16_t eco2 = 0; 14 15void setup() { 16 M5.begin(); 17 M5.Lcd.setRotation(1); 18 M5.Lcd.println(F("SHT30 & SGP30 test...\n")); 19} 20 21void loop() { 22 sht30.init(0x44, &wire); 23 sht30.get(); 24 tmp = sht30.cTemp; 25 hum = sht30.humidity; 26 sgp.begin(&wire); 27 delay(15000); // SGP30初期化の推奨待機時間15秒 28 sgp.IAQmeasure(); 29 tvoc = sgp.TVOC; 30 eco2 = sgp.eCO2; 31 M5.Lcd.setCursor(0, 20); 32 M5.Lcd.fillRect(0, 20, 100, 60, BLACK); 33 M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\n", tmp, hum); 34 M5.Lcd.printf("TVOC: %4.0u ppb \r\neCO2: %4.0u ppm \r\n", tvoc, eco2); 35 delay(2000); 36}
解決したコード
こちらのサイトを参考にWire1を正常に使えるように修正し、tmpさんの回答と組み合わて無事動作するようになったコードは下記の通りです。
cpp
1#include <M5Unified.h> 2#include "M5_ENV.h" 3#include "Adafruit_SGP30.h" 4 5SHT3X sht30; 6Adafruit_SGP30 sgp30; 7 8float tmp = 0.0; 9float hum = 0.0; 10uint16_t tvoc = 0; 11uint16_t eco2 = 0; 12 13void setup() { 14 // Wire1を使うために内部I2Cを無効にする処理 15 auto cfg = M5.config(); 16 cfg.pmic_button = false; // これで電源ボタン状態取得を行わなくなる 17 cfg.internal_imu = false; // これで内蔵IMUを使わなくなる 18 cfg.internal_rtc = false; // これで内蔵RTCを使わなくなる 19 M5.begin(cfg); 20 Wire1.end(); 21 22 Wire1.begin(0, 26); 23 sht30.init(0x44, &Wire1); 24 sgp30.begin(); // デフォルトでスレーブアドレス0x58と&Wireを使用 25 M5.Lcd.setRotation(1); 26 M5.Lcd.println(F("SHT30 & SGP30 test...\n")); 27} 28 29void loop() { 30 sht30.get(); 31 tmp = sht30.cTemp; 32 hum = sht30.humidity; 33 sgp30.IAQmeasure(); 34 tvoc = sgp30.TVOC; 35 eco2 = sgp30.eCO2; 36 M5.Lcd.setCursor(0, 20); 37 M5.Lcd.fillRect(0, 20, 100, 60, BLACK); 38 M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\n", tmp, hum); 39 M5.Lcd.printf("TVOC: %4.0u ppb \r\neCO2: %4.0u ppm \r\n", tvoc, eco2); 40 delay(2000); 41}
補足情報(FW/ツールのバージョンなど)
Arduino IDE 2.2.1
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/11/17 08:19