二酸化炭素濃度を測定する

  • 投稿日:
  • by
  • カテゴリ:

家に、何かの時に買ったESP32-C6-LCD-1.47というLCDのついたESP32-C6が転がっていまして、何かに使えないかなあと思っていたのです。そんな折、密林で、ENS160+AHT21のセンサーボードが売られていたので、これ使えば炭酸ガス濃度を測定するデバイスになるのではと思い、購入しました。

とりあえず、ブレッドボード上にのせて実験します。このボードはVIN(5V)と3V3の端子があり、ESP32-C6側の3V3を3V3につなげば動作します。I2Cバスにて通信するので、GNDのほかに、SCLとSDAの二つもつなぎます。ESP32-C6側はGPIOピンが13露出していますので、このうち GPIO1とGPIO2をそれぞれ SCLとSDAにつなぎます。

ENS160というガスセンサーは、温度と相対湿度による補償を必要としているため、AHT21という温湿度センサーも搭載していて、それぞれI2Cバスに 0x53, 0x38のアドレスで接続しています。ボード上のAHT21はENS160の影響があるため実測より温度が高く、結果湿度が低く出るため、ガス濃度も正確性に欠けるという話はありますが、とりあえず、それはそれ。

あとは、プログラムを書いてやればいいわけです。

わたしは普段はArduinoの開発には VSCode + PlatformIOを使っているのですが、ESP32-C6という RISC Vコアに対して、PlatformIOはボード設定を更新しておらず、Arduino フレームワークでの開発ができません。

仕方がないので Arduino IDEを使うことにしたのですが、ESP32 by Espressif32 のボード定義がWindows上でダウンロードしようとするとタイムアウトでインストールできないのです。結局 Linux上でダウンロードして、開発することに。

液晶は ST7789というチップでSPI接続していて、Lovyan GFXでばっちりいけます。あとは ENS160 も AHT21もライブラリがあるので、それを。あとはボード上にRGB LEDがひとつ乗っているので、これも制御用のライブラリを持ってきておきます。CO2濃度が1000未満で青、1000-2000未満で黄色、2000以上で赤とすれば数字を見ないでもガス濃度レベルを知れるというものです。

#include <Wire.h>
#include <LovyanGFX.hpp>
#include "LGFX_ESP32C6_LCD147.hpp"

#include <DFRobot_ENS160.h>
#include <Adafruit_AHTX0.h>
#include <Adafruit_NeoPixel.h>

LGFX lcd;
DFRobot_ENS160_I2C ens(&Wire, 0x53);
Adafruit_AHTX0 aht;

#define LED_PIN  8   // ※基板の実配線に合わせる
#define LED_NUM  1

Adafruit_NeoPixel pixels(LED_NUM, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(115200);

  pixels.begin();
  Wire.begin(2, 1); // SCL=GPIO1, SDA=GPIO2

  lcd.init();
  lcd.setRotation(1);
  lcd.fillScreen(TFT_BLACK);
  lcd.setTextColor(TFT_WHITE);
  lcd.setTextSize(2);
  lcd.setCursor(10,10);

  lcd.println("Initializing...");
  pixels.setPixelColor(0, pixels.Color(128, 255, 0));
  pixels.show();
  int aht_adrs = 0x38;
  while (!aht.begin(&Wire, 0, aht_adrs)) {
    Serial.printf("AHT21 not found (0x%x)\r\n", aht_adrs);
    usleep(100000);
  }
  pixels.setPixelColor(0, pixels.Color(0, 128, 255));
  pixels.show();
  while (ens.begin() != 0) {
    Serial.println("ENS160 init failed");
    usleep(100000);
  }
  pixels.setPixelColor(0, pixels.Color(255, 0, 0));
  pixels.show();
  ens.setPWRMode(ENS160_STANDARD_MODE);
}

void loop() {

  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);

  ens.setTempAndHum(temp.temperature, humidity.relative_humidity);

  int co2 = ens.getECO2();
  uint32_t rgb_color = pixels.Color(0, 0, 255); // blue (normal)
  if (co2 > 1000) {
    rgb_color = pixels.Color(255, 255, 0); // yellow
  }
  if (co2 > 2000) {
    rgb_color = pixels.Color(0, 255, 0); // red
  }
  pixels.setPixelColor(0, rgb_color);
  pixels.show();

  lcd.fillScreen(TFT_BLACK);

  lcd.setTextColor(TFT_WHITE);
  lcd.setTextSize(2);

  lcd.setCursor(10, 40);
  lcd.printf("Temp : %.1f C", temp.temperature);

  lcd.setCursor(10, 80);
  lcd.printf("Hum  : %.1f %%", humidity.relative_humidity);

  lcd.setCursor(10, 120);
  lcd.printf("CO2  : %d ppm", co2);

  delay(1000);
}