はらぺこらいおん

日々、思ったことを。

ArduinoでCO2濃度を計測する(MH-Z19)

ArduinoでCO2濃度を計測するためにいろいろやってみました。

使用パーツ

AE-ATMEGA328-MINI(Arduino Pro Mini互換)

f:id:pictzzz:20170729122213j:plain

akizukidenshi.com

秋月で780円だったので、使ってみることにしました。

USBシリアル変換

f:id:pictzzz:20170729122327j:plain

akizukidenshi.com

ロジックレベルを5Vと3.3Vで切り替えられて、便利なのでよく使ってます。

ブレッドボード

f:id:pictzzz:20170729122427j:plain

akizukidenshi.com

個人的にこれくらいのサイズが使いやすいです。サイズが足りなければ連結できます。

LCD

f:id:pictzzz:20170729122356j:plain

akizukidenshi.com

計測結果を表示するために用意しました。Arduino用のサンプルコードがあり、3.3Vと5Vで接続できます。

MH-Z19(CO2センサー)

f:id:pictzzz:20170729122259j:plain

今回のメイン、CO2センサーです。いろいろなサイトで探してみたのですが、高額だったり、大量ロットで注文しなければならなかったり、なかなか買えませんでした。

下記AliExpressという中国のサイトで見つけて安かったので、今回は試しに買ってみました。2週間ほどで無事に届きました。

AliExpress.com Product - 1PCS module MH-Z19 infrared co2 sensor for co2 monitor Free shipping new stock best quality

CO2センサーからArduinoへデータ取得

CO2センサーからの情報の取得はシリアルとPWMが選択できます。今回はPWMで取得してみようと思います。

まずは、macArduinoを接続します。ツールから以下を選択します。

  • Board: “Arduino Pro or Pro Mini”
  • Processor: “ATmega328 (5V, 16MHz)”
  • Port: “/dev/cu.usbserial-A1032FAZ”

Arduinoとセンサーの接続はシンプルで以下の3本です。

センサーが正常に動作しているかを確認するため、シリアルにログを出力するコードを実行してみます。

#define PWM_PIN 3

int prev_val = LOW;
long high_level_start = 0L;
long high_level_end = 0L;
long low_level_start = 0L;
long low_level_end = 0L;

void setup() {
  Serial.begin(9600);
  pinMode(PWM_PIN, INPUT);
}

void loop() {
  long cycle_start_time = millis();
  int pin_in = digitalRead(PWM_PIN);

  if (pin_in == HIGH) {
    if (prev_val == LOW) {
      long time_high = high_level_end - high_level_start;
      long time_low = low_level_end - low_level_start;
      long ppm = 5000 * (time_high - 0.002) / (time_high + time_low - 0.004);
      Serial.println("PPM = " + String(ppm));
      
      high_level_start = cycle_start_time;
      prev_val = HIGH;
    } else {
      high_level_end = cycle_start_time;
    }
  } else {
    if (prev_val == HIGH) {
      low_level_start = cycle_start_time;
      prev_val = LOW;
    } else {
      low_level_end = cycle_start_time;
    }
  }
}

出力は以下のようになります。室内は少しCO2濃度が高めのようです。

PPM = 905
PPM = 906
PPM = 901
PPM = 941
PPM = 940
PPM = 936
PPM = 941
PPM = 941
PPM = 920
PPM = 916
PPM = 921

仕様書を読むと2000をかけると書かれているのですが、5000にしないと値があわないようでした。

http://clima-sensor.ru/files/MH-Z19_Manual_V2.pdf

ArduinoからLCD(ディスプレイ)へ結果の出力

センサーからの結果をLCDに出力するようにしてみます。

接続は以下の4本です。

I2Cのプルアップ抵抗は初めからArduino側で実装されていましたので、そのまま接続します。

プログラムは以下のようになります。(※ 見直し中)

#include <Wire.h>

#define LCD_ADRS 0x3E
#define PWM_PIN 3

int prev_val = LOW;
long high_level_start = 0L;
long high_level_end = 0L;
long low_level_start = 0L;
long low_level_end = 0L;
int ppm = 0;

boolean is_output_ready = false;

char moji[] = "CO2 = ";

void writeData(byte t_data) {
  Wire.beginTransmission(LCD_ADRS);
  Wire.write(0x40);
  Wire.write(t_data);
  Wire.endTransmission();
  delay(1);
}

void writeCommand(byte t_command) {
  Wire.beginTransmission(LCD_ADRS);
  Wire.write(0x00);
  Wire.write(t_command);
  Wire.endTransmission();
  delay(10);
}

void init_LCD() {
  delay(100);
  writeCommand(0x38);
  delay(20);
  writeCommand(0x39);
  delay(20);
  writeCommand(0x14);
  delay(20);
  writeCommand(0x73);
  delay(20);
  writeCommand(0x52);
  delay(20);
  writeCommand(0x6C);
  delay(20);
  writeCommand(0x38);
  delay(20);
  writeCommand(0x01);
  delay(20);
  writeCommand(0x0C);
  delay(20);
}

void setup() {
  Serial.begin(9600);
  pinMode(PWM_PIN, INPUT);
  Wire.begin();
  init_LCD();
}

void loop() {
  long cycle_start_time = millis();
  int pin_in = digitalRead(PWM_PIN);

  if (pin_in == HIGH) {
    if (prev_val == LOW) {
      long time_high = high_level_end - high_level_start;
      long time_low = low_level_end - low_level_start;
      ppm = 5000 * (time_high - 0.002) / (time_high + time_low - 0.004);
      is_output_ready = true;
      
      high_level_start = cycle_start_time;
      prev_val = HIGH;
    } else {
      high_level_end = cycle_start_time;
    }
  } else {
    if (prev_val == HIGH) {
      low_level_start = cycle_start_time;
      prev_val = LOW;
    } else {
      low_level_end = cycle_start_time;
    }
  }

  if (is_output_ready) {
    writeCommand(0x00 + 0x01);
    for (int i = 0; i < 6; i++) {
      writeData(moji[i]);
    }
    String ppm_text = String(ppm);
    char ppm_print[4];
    ppm_text.toCharArray(ppm_print, 4);
    for (int i = 0 ; i < 4 ; i++) {
      writeData(ppm_text[i]);
    }
    is_output_ready = false;
  }
}

LCDへの文字の出力処理を実装し、Arduinoにアップロードします。

うまくいけば、以下のようにCO2の濃度が出力されます。

f:id:pictzzz:20170729173639j:plain