RX72N Envision KitとMH-Z19Bで二酸化炭素濃度を測定する

今回の目的
---
私の職業では職場勤務、在宅勤務を問わず部屋の二酸化炭素(CO2)濃度が高くなりがちで、手持ちのマイコンで測定してみたいと予てから考えていました。
Envision Kitを購入したのをきっかけに、導入報告の多いMH-Z19をamazonで注文したのですが…
![2020-05-01 14-06-35.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624954/2135e064-8f22-5073-c61e-5d42325ff3bf.jpeg)
商品写真と明らかに違うものが届きました。
裏面も安っぽく、またPCとUSB-UART変換してTeraTermと通信しても応答がないため、KitとUART接続してこれで動作しなければ返品しようということになりました。

情報収集
---
今回は製品のデータシートと、
https://www.winsen-sensor.com/d/files/PDF/Infrared%20Gas%20Sensor/NDIR%20CO2%20SENSOR/MH-Z19%20CO2%20Ver1.0.pdf

コードの類の記載はないのですがこちらのサイトを参考にさせて頂きました。
https://kohacraft.com/archives/1068007971.html

ArduinoとMH-Z19を接続して動作させていらっしゃるサイトは多いのですが、参照先のライブラリが意外と大規模でArduino系のライブラリの移植に手間がかかるKitには向きませんでした。
https://github.com/WifWaf/MH-Z19

今回はUARTでの戻り値要求の送信と、データの受信のみを確認しました。

接続
---
MH-19BはUARTで制御し、出力はUARTまたはPWMで得る仕組みです。今回は送受信ともUARTとし、PMOD2に接続しました。
![2020-05-01 14-06-18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624954/d356be90-a364-bb56-746d-70f7d813ae45.jpeg)
MH-19Bの電源は5V系、信号は3V系でも可となりますので、電源は別途USB-UARTの変換ボードから取り信号はそのままRX72Nに繋げました。
* P92/SMISO7/RXD7 <-> TXD(MH-Z19B)
* P90/SMSI7/TXD7 <-> RXD(MH-Z19B)

コーディング
---
端子設定に注意点はなく、SCI7をUART設定としBaudRateはデータシートの通り9600としました。

```
SCI7.BRR = 0x67;                  //N=((32*10^6)/(64*2^(-1)*9600))-1 = 103.16..(dec)
```

メイン関数をそのまま貼りました。UART送信時のコマンドは9byte構成で、データシートの7.1章に説明があります。
スタートByteは0xFFで、測定データ要求は0x86というコマンドになります。0x01はデバイス番号、0x79はチェックサムです。

```
int main(void) {

	int i;
	char c;
	int co2_raw, temp_data;
	uint8_t Gas_Concentration[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
	uint8_t Return_Value[9];

	//System Init
	SYSTEM.PRCR.WORD = 0xA503;				//PRC1,0 Write Enable
	clk_init();

	//SCI Init
	serial_init();
	serial_pmod2_init();

	ee_printf("START\n");

    while(1) {
    	//Command Send
    	for (i=0;i<9;i++) {
    		while(SCI7.SSR.BIT.TDRE == 0);
    		SCI7.TDR = Gas_Concentration[i];
    		while(SCI7.SSR.BIT.TEND == 0);
    	}
    	for (i=0;i<10;i++) {}

    	//Get Return Value
    	for (i=0;i<9;i++) {
    		while(SCI7.SSR.BIT.RDRF == 0);
    		Return_Value[i] = SCI7.RDR;
    	}
    	co2_raw = (int)((Return_Value[2] << 8) | Return_Value[3]);
    	temp_data = (int)(Return_Value[4]) - 40;
    	ee_printf("Return_Value: ");
    	for (i=0;i<9;i++) {
    		//ee_printf("Return_Value[%d],0x%x\n",i, Return_Value[i]);
    		ee_printf("0x%x,", Return_Value[i]);
    	}
    	ee_printf("\n");
    	//ee_printf("CO2:%d[ppm], Ta:%d[C]\n",co2_raw, temp_data);
    	ee_printf("CO2:%d[ppm]\n\n",co2_raw);				//温度データは気温というよりも内部の補正用なので、表示はしない

    	//wait
        for (i=0;i<5000000;i++) {}	//(temp)
        for (i=0;i<5000000;i++) {}	//(temp)
        for (i=0;i<5000000;i++) {}	//(temp)
    }

return 0;
}
```

9Byte送信し9Byte受け、結果を計算しています。濃度のデータは2,3バイト目で2バイト目が上位、3バイト目が下位となる16bitのデータとなります。
4バイト目は温度を示しているとのことですが、室温というよりもCO2測定時に内部で使用されている値が出てきているという話が複数サイトに書かれていました。このためターミナルへの出力はしていません。

動作確認
---
動くか怪しい商品でしたが、ロジアナでTXDを確認したところ戻り値が正しく得られていました。
![MH-Z19B_応答波形.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624954/ce313c52-73f6-80a2-6027-1602d4efc963.png)
いつの間にかデザインが変わったか、コピー商品がしれっと送られてきたかは分かりませんが今回はよしとします。

結果
---
TeraTermで結果を確認したところそれっぽいCO2濃度が測定されています。
![MH-Z19B_ログ出力.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624954/b348b007-5eae-8043-c921-0217c0bfe73f.png)
上記ログは窓を開けてしばらく待っていた時の値なのですが、1000ppm超えの状態から880ppm程度まで下がることは確認できました。

感想
---
動かない金色の箱を掴まされたと思ってしばらく凹んでいましたが、無事動くのが確認できて得した気分になりました。
また、取得した結果から窓を開けても急にはCO2濃度は変わらず、結構待つ必要があるというのが体感できました。