Arduino UNO R4 Minimaでセンサ・インターフェーシング ㉕ CO2センサSCD41
Adafruitから入手したCO2センサ SCD41(Sensirion)を利用します。
温度と湿度、そしてCO2が測定できます。
第18回で掲載したボッシュBME688の気圧センサとの比較を次に示します。
型名 | 電源電圧 [V] |
気圧測定範囲 [hPa] |
温度[℃] | 湿度[%] | 空気測定の機能 |
SCD41 | 2.4~5.5 | - | -10~+60 確度;± 0.8℃ |
0~100 |
CO2 |
---|---|---|---|---|---|
BME688 | 1.7~3.6 | 300~1100 | -40~+85℃ 確度;±0.5℃ |
0~100% 確度;±3% |
MOX (金属酸化物)センサで、各種空気のにおいを検知 |
<二つのモデル>
(SCD40 は低コスト、400~2000ppm、確度は±50 ppm + 読み取り値の5%)
(SCD41 はより高価、400~5000ppm、確度は±40 ppm + 読み取り値の5%)
●AdafruitのStemma QT/Qwiicボード
Stemma QT/Qwiic(JST SH 4ピン)コネクタは2か所に装着されていて、どちらにつないでもかまいません。このコネクタを使ってI2Cで制御する場合、特に、ジャンパ線をつなぐなどは不要です。
コネクタは、表と裏のどちらも差し込めそうですが、ピンが内部の上部に並んでいるので、差し込める方向は一意です。ロック機構はないですが、すぐに抜けるということはありません。
●CO2センサSCD41のおもなスペック
- 電源電圧 2.4~5.5V
- 消費電流 17mA
- 温度測定範囲 -10~+60℃、確度;±0.8℃
- CO2測定範囲 400~5000ppm、確度;±(40ppm + 読み取り値の5%)
- 湿度測定範囲 0~100%、確度;±6%
- インターフェース I2C(最大400kHz)
- スレーブ・アドレス 0x62
●使用環境
- Arduino UNO R4 Minima
- Arduino IDE 2.2.1
- Windows10 22H2
●接続
Arduino UNO R4 MinimaのI2C信号とセンサ・ボードをJSTコネクタでつなぎます(Stemma QT/Qwiicボードの写真の比率は異なる)。
●スレーブ・アドレスを確認
従来からよく使われているi2cScanner.inoを動かしてスレーブ・アドレスを確認します。電源は3.3Vです。
0x62を見つけてきました。
(正常に動作しないときは、ボード上のリセットを押します。一度で動かない場合は、何度か押し直す)
●ライブラリの用意
SCD4で検索して、見つかったSensirion I2C SCD4Xライブラリをインストールします。
インストールを始めたとき、関連のライブラリや依存関係をインストールするかというパネルが出た場合は、全てをインストールを選びます。
●サンプル・スケッチ
メニューのファイル->スケッチ例から、Sensirion I2C SCD4XからexampleUsage.inoを選択し、コンパイル、実行します。
●4桁の7セグメントLED表示器をつないで測定結果を表示する
連載の第4回目の記事を参照しながら表示器を接続します。
Arduino UNO R4 Minimaでセンサ・インターフェーシング ④ 温湿度センサSi7021の測定結果を7セグメントLEDに表示
スケッチです。
7セグメントLED表示器は、第12回 温湿度センサ SHTC3でスレーブ・アドレスが重なったので、デフォルトの0x70から、ジャンパのA0をショートして0x71に変更してあります。デフォルトのまま使うときは0x70で使ってください。
// Copyright (c) 2021, Sensirion AG
#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
#include <Arduino.h>
#include <SensirionI2CScd4x.h>
Adafruit_7segment matrix = Adafruit_7segment();
SensirionI2CScd4x scd4x;
void printUint16Hex(uint16_t value) {
Serial.print(value < 4096 ? "0" : "");
Serial.print(value < 256 ? "0" : "");
Serial.print(value < 16 ? "0" : "");
Serial.print(value, HEX);
}
void printSerialNumber(uint16_t serial0, uint16_t serial1, uint16_t serial2) {
Serial.print("Serial: 0x");
printUint16Hex(serial0);
printUint16Hex(serial1);
printUint16Hex(serial2);
Serial.println();
}
void setup() {
Serial.begin(115200);
while (!Serial) { delay(100); }
Serial.println("SCD41 + 7segment LED");
Wire.begin();
uint16_t error;
char errorMessage[256];
scd4x.begin(Wire);
// stop potentially previously started measurement
error = scd4x.stopPeriodicMeasurement();
if (error) {
Serial.print("Error trying to execute stopPeriodicMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
}
uint16_t serial0;
uint16_t serial1;
uint16_t serial2;
error = scd4x.getSerialNumber(serial0, serial1, serial2);
if (error) {
Serial.print("Error trying to execute getSerialNumber(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
} else {
printSerialNumber(serial0, serial1, serial2);
}
// Start Measurement
error = scd4x.startPeriodicMeasurement();
if (error) {
Serial.print("Error trying to execute startPeriodicMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
}
Serial.println("Waiting for first measurement... (5 sec)");
matrix.begin(0x71);
matrix.setBrightness(0x05); // default 0x0E
}
void loop() {
uint16_t error;
char errorMessage[256];
delay(100);
// Read Measurement
uint16_t co2 = 0;
float temperature = 0.0f;
float humidity = 0.0f;
bool isDataReady = false;
error = scd4x.getDataReadyFlag(isDataReady);
if (error) {
Serial.print("Error trying to execute getDataReadyFlag(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
return;
}
if (!isDataReady) {
return;
}
error = scd4x.readMeasurement(co2, temperature, humidity);
if (error) {
Serial.print("Error trying to execute readMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
} else if (co2 == 0) {
Serial.println("Invalid sample detected, skipping.");
} else {
Serial.print("Co2:");
Serial.print(co2);
Serial.print("\t");
Serial.print("Temperature:");
Serial.print(temperature);
Serial.print("\t");
Serial.print("Humidity:");
Serial.println(humidity);
matrix.print(co2, DEC);
matrix.writeDisplay();
delay(2000);
matrix.print(temperature, DEC);
matrix.writeDisplay();
delay(2000);
matrix.print(humidity, DEC);
matrix.writeDisplay();
delay(3000);
}
}
実行例です。CO2の測定値を表示しています。机の上では400~500ppm、息を吹きかけるとゆっくり上昇に、千ppmを越えます。
●グラフィック・ディスプレイに測定結果を表示
次の記事を参考に、グラフィック・ディスプレイに測定した温度、湿度、CO2の値を表示します。
Arduino UNO R4 Minimaでセンサ・インターフェーシング ⑤ 温湿度センサSi7021の測定結果をグラフィック・ディスプレイに表示
スケッチです。
// Copyright (c) 2021, Sensirion AG
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Arduino.h>
#include <SensirionI2CScd4x.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
SensirionI2CScd4x scd4x;
void printUint16Hex(uint16_t value) {
Serial.print(value < 4096 ? "0" : "");
Serial.print(value < 256 ? "0" : "");
Serial.print(value < 16 ? "0" : "");
Serial.print(value, HEX);
}
void printSerialNumber(uint16_t serial0, uint16_t serial1, uint16_t serial2) {
Serial.print("Serial: 0x");
printUint16Hex(serial0);
printUint16Hex(serial1);
printUint16Hex(serial2);
Serial.println();
}
void setup() {
Serial.begin(115200);
while (!Serial) { delay(100); }
Serial.println("SCD41 + SSD1306");
Wire.begin();
uint16_t error;
char errorMessage[256];
scd4x.begin(Wire);
// stop potentially previously started measurement
error = scd4x.stopPeriodicMeasurement();
if (error) {
Serial.print("Error trying to execute stopPeriodicMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
}
uint16_t serial0;
uint16_t serial1;
uint16_t serial2;
error = scd4x.getSerialNumber(serial0, serial1, serial2);
if (error) {
Serial.print("Error trying to execute getSerialNumber(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
} else {
printSerialNumber(serial0, serial1, serial2);
}
// Start Measurement
error = scd4x.startPeriodicMeasurement();
if (error) {
Serial.print("Error trying to execute startPeriodicMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
}
Serial.println("Waiting for first measurement... (5 sec)");
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
display.clearDisplay();
display.drawRect(0, 0, display.width(), display.height(), SSD1306_WHITE);
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(3,3);
display.println("Temperature:");
display.setTextColor(SSD1306_WHITE);
display.setCursor(79,3);
display.println("Humidity");
display.setTextColor(SSD1306_WHITE);
display.setCursor(4,34);
display.println("CO2:");
display.display();
delay(200);
}
void loop() {
uint16_t error;
char errorMessage[256];
delay(100);
// Read Measurement
uint16_t co2 = 0;
float temperature = 0.0f;
float humidity = 0.0f;
bool isDataReady = false;
error = scd4x.getDataReadyFlag(isDataReady);
if (error) {
Serial.print("Error trying to execute getDataReadyFlag(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
return;
}
if (!isDataReady) {
return;
}
error = scd4x.readMeasurement(co2, temperature, humidity);
if (error) {
Serial.print("Error trying to execute readMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
} else if (co2 == 0) {
Serial.println("Invalid sample detected, skipping.");
} else {
Serial.print("Co2:");
Serial.print(co2);
Serial.print("\t");
Serial.print("Temperature:");
Serial.print(temperature);
Serial.print("\t");
Serial.print("Humidity:");
Serial.println(humidity);
display.setTextSize(2); // Draw 2X-scale text
display.setCursor(10,17);
display.fillRect(10, 17, 70, 16, SSD1306_BLACK);
display.println(temperature);
display.setCursor(80,17);
display.fillRect(80, 17, 46, 16, SSD1306_BLACK);
display.println(humidity,1);
display.setCursor(10, 46);
display.fillRect(10, 46, 100, 16, SSD1306_BLACK);
display.println(co2);
display.display();
}
}
実行例です。