Edited at

二酸化炭素センサー MH-Z19 のPWM入力プログラムを割り込み処理で実現

More than 1 year has passed since last update.

二酸化炭素センサー MH-Z19 のPWM入力でデータを取得したくて

Arduino用のサンプルプログラムを使ってみたのですが、

このプログラムPWMのパルス長の計測をメイン処理の中でやっていたので、

このままでは他のセンサーとの併用が難しいので、

データ取得部分を割り込み処理に変更してみました。

割り込みには「MsTimer2」ライブラリを使用しています。

またデータのフィルタリングの処理も追加しています。

公開されていた元のプログラム


mh-z19.ino

#define pwmPin A0

#define LedPin 13

int prevVal = LOW;
long th, tl, h, l, ppm;

void setup() {
Serial.begin(9600);
pinMode(pwmPin, INPUT);
pinMode(LedPin, OUTPUT);
}

void loop() {
long tt = millis();
int myVal = digitalRead(pwmPin);

if (myVal == HIGH) {
digitalWrite(LedPin, HIGH);
if (myVal != prevVal) {
h = tt;
tl = h - l;
prevVal = myVal;
}
} else {
digitalWrite(LedPin, LOW);
if (myVal != prevVal) {
l = tt;
th = l - h;
prevVal = myVal;
ppm = 5000 * (th - 2) / (th + tl - 4);
Serial.println("PPM = " + String(ppm));
}
}
}


割り込み処理に変更したプログラム


mh-z19_int.ino

/*

MH-Z19
Intelligent Infrared CO2 Module

MsTimer2 is a small and very easy to use library to interface Timer2 with
humans. It's called MsTimer2 because it "hardcodes" a resolution of 1
millisecond on timer2
For Details see: http://www.arduino.cc/playground/Main/MsTimer2

2017/08/20
NextStep/Kaz Ueno
*/

#include <MsTimer2.h>

/* Switch on LED on and off each half second */

#define LedPin 13 /* LED to pin 13 */
#define pwmPin A0
/* CO2 data input to pin A0 */

boolean prevVal = LOW;

uint32_t CO2_data = 0L;
uint8_t data_count = 0L;

uint32_t th, tl, h, l, ppm, ppm_now;

uint32_t ppm_befor = 0L;
uint32_t tt = 0L;

void flash()
{
uint8_t myVal = digitalRead(pwmPin);

tt++ ;
if (myVal == HIGH) {
digitalWrite(LedPin, HIGH);
if (myVal != prevVal) {
tl = tt ;
prevVal = myVal;
tt =0L;
}
} else {
digitalWrite(LedPin, LOW);
if (myVal != prevVal) {
th = tt;
prevVal = myVal;
ppm = 5000 * (th - 2) / (th + tl - 4); // 取得したデータを二酸化炭素データ(ppm)に変換
ppm_now = ppm_befor * 0.8 + ppm * 0.2 ; // 差分方程式のディジタルフィルタ処理
ppm_befor = ppm_now;
data_count++ ;
CO2_data += ppm_now;
tt = 0L;
}
}
}

void setup()
{
Serial.begin(9600);
pinMode(pwmPin, INPUT);
pinMode(LedPin, OUTPUT);

MsTimer2::set(1, flash); // 1ms毎に割り込みを発生させる
MsTimer2::start();
delay(5000);
}

void loop()
{
uint32_t CO2_data_ave;
CO2_data_ave = CO2_data / data_count; // 取得した回数分の平均
Serial.println("PPM = " + String(CO2_data_ave) +"," + String(ppm_now) +"," + String(ppm));
CO2_data = 0L;
data_count = 0L;

delay(5000);
}


これで loop()内に他のセンサーの取り込みプログラムが書けます。

なおデジタルフィルタリング処理に関しては

センサの入力などに使うディジタルフィルタ

こちらのページの解説が分かりやすいです。