編集履歴一覧に戻る
maruaのアイコン画像

marua が 2023年01月04日14時34分38秒 に編集

初版

タイトルの変更

+

MH-Z19C使用 CO2モニタ

タグの変更

+

ArduinoIDE

+

ラズパイPico

メイン画像の変更

メイン画像が設定されました

記事種類の変更

+

製作品

ライセンスの変更

+

(CC BY-SA 4+) Creative Commons Attribution-ShareAlike CC BY-SA version 4.0 or later

本文の変更

+

ファンヒータを使用する時期になったので、以前買っておいたCO2センサ「MH-Z19C」を使って CO2モニタを作りました。 MH-Z19Cは シリアル出力(3.3V) または PWM出力なので、シリアルポートの多い「ラズパイ Pico」を使ってみました。 AeduinoIDEで ATmega328以外のCPUを初めて使用しましたが、思った以上にすんなりプログラムを作成できました。 (Serial1.write()の引数の型NGには ハマりましたが...) 起動すると、  (1)センサのアイドル時間(60s) 待機  (2)3秒間隔で co2濃度を読み取り どいう動作を実行します。 ![CO2濃度表示](https://camo.elchika.com/8dee5f18db944c227735e1c12a1ac4be232a219a/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33633934613036612d653465342d343838392d383133342d3434636466393330333066352f62303739313238622d313536332d346137362d383135632d643662346339613666356538/) - 環境設定 ArduinoIDEの環境設定については、[ロジカラブログ](https://logikara.blog/raspi-pico-arduinoide/)の記事を参考にしました。 備忘録を兼ねて 以下に簡単にまとめておきます。 1. ArduinoIDEを立ち上げ、「ファイル」-「環境設定」の「追加のボードマネージャURL」に 「[https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json]()」 を追加 ![ボードマネージャURLの追加](https://camo.elchika.com/1b43910a1d46ff5307ab975f69732c0428c68935/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33633934613036612d653465342d343838392d383133342d3434636466393330333066352f30323063353736382d666463642d343964352d396334362d363235313432313365346262/) 2. 「ツール」-「ボード」-「ボードマネージャ」でボードマネージャを立ち上げ、Philhowerさん作成の「Raspberry Pi Pico/RP2040」をインストール。 ![ボードの追加](https://camo.elchika.com/c9830bab35e8c00c0c82b024344f5a961ff9b2e8/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33633934613036612d653465342d343838392d383133342d3434636466393330333066352f31643730353233322d346361332d343335302d383263622d643061633863633936656666/) 3.「ツール」-「ボード」から、「Raspberry Pi RP2040 Boards」-「Raspberry pi pico」を選択 ![ボードを選択](https://camo.elchika.com/f19ae7fb8c3880562ae6b3ad7d221065188c3412/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33633934613036612d653465342d343838392d383133342d3434636466393330333066352f32663536633931322d656431362d346462362d626532372d613962646566393034383633/) - 主な使用部品 | No. | 品名 | 型番 | 備考 | |:---:|:---:|:---:|:---:| | 1 | Raspberry Pi Pico |   | 秋月電子 M-16132 | | 2 | CO2センサ | MH-Z19C | 秋月電子 M-16142 | | 3 | I2C接続液晶 | AE-AQM1602A | 秋月電子 K-08896 | - ソースコード ```arduino:CO2モニタ #include <Wire.h> #define LCD_ADRS 0x3E //Slave address of LCD(Arduino ver.) String VRAM1 = " "; // 16文字 String VRAM2 = " "; // 16文字 unsigned long Lchika_tim0; unsigned long Lchika_timH = 1000; unsigned long Lchika_timL = 1000; byte Lchika_task, Lchika_cnt; unsigned long co2_tim0; byte co2_task, co2_RD_pos, co2_cnt, co2_enum; byte co2_RDat[10]; word co2_resalt; // the setup function runs once when you press reset or power the board void setup() { // initialize digital pin LED_BUILTIN as an output. pinMode(LED_BUILTIN, OUTPUT); Wire.begin(); init_LCD(); Lchika_timH = 500; Lchika_timL = 500; VRAM1 = " 0:Wait"; LCD_DISP_16_1(); Serial.begin(9600); // USB Serial1.begin(9600); // UART1 co2_tim0 = millis(); // (co2_tim0)に基準時間セット co2_enum = 0; // エラーNo. = 0: エラー無し } // the loop function runs over and over again forever void loop() { Lchika(); read_CO2(); } // ■■ Read CO2 data ■■ void read_CO2() { byte sum; switch (co2_task) { case 0: // pre Heat if ( (millis() - co2_tim0) > 1000) { co2_cnt ++; VRAM1 = " 0:Wait "+ String(co2_cnt); LCD_DISP_16_1(); co2_task ++; } break; case 1: // if ( co2_cnt < 60 ) { co2_tim0 = millis(); // (co2_tim0)に基準時間セット co2_task = 0; } else { VRAM1 = " 1:STT"; LCD_DISP_16_1(); Serial.println(" CO2 sens start"); Lchika_timH = 1000; Lchika_timL = 1000; co2_task ++; } break; case 2: // send Read cmd if (Serial1.available() ) { Serial1.read(); break; } // 受信バッファ 強制読出し send_CO2_read(); // Read comd co2_RD_pos = 0; co2_tim0 = millis(); // (co2_tim0)に基準時間セット co2_task ++; break; case 3: // 受信完了待ち if (Serial1.available() ) { co2_RDat[co2_RD_pos] = Serial1.read(); co2_RD_pos ++; if (co2_RD_pos >=9) {co2_task ++;} } if ( (millis() - co2_tim0) > 10000) {co2_task = 99; } // 10s経過で 再送 break; case 4: // 受信データ処理 sum = 0; for (int i=0; i<8; i++ ) { sum += co2_RDat[i]; } if (co2_RDat[0] != 0xff) { co2_task = 99; co2_enum = 11; break; } if (co2_RDat[1] != 0x86) { co2_task = 99; co2_enum = 12; break; } if ((0xff - sum) != co2_RDat[8]) { co2_task = 99; co2_enum = 19; break; } co2_resalt = co2_RDat[2]*256 + co2_RDat[3]; Serial.print(co2_resalt); Serial.print(", "); Serial.print(sum,HEX); Serial.print(", "); Serial.print(co2_RDat[8],HEX); Serial.println(); VRAM1 = " 3:Receive " + String(co2_resalt); LCD_DISP_16_1(); co2_tim0 = millis(); // (co2_tim0)に基準時間セット co2_task ++; break; case 5: if ( (millis() - co2_tim0) > 3000) {co2_task = 2; } // 3s経過で 再読込み break; case 6: co2_task = 2; break; case 99: Serial.print("NG "); Serial.print('E'); Serial.print(co2_enum); Serial.print(" sum="); Serial.print(sum); Serial.print(" , "); Serial.print(co2_RDat[8], HEX); Serial.print(" , "); Serial.print(co2_RDat[0], HEX); Serial.println(); co2_tim0 = millis(); // (co2_tim0)に基準時間セット co2_task = 5; break; default: co2_task = 0; break; } } void send_CO2_read() { Serial1.write(0xff); // 1 Serial1.write(0x01); // 2 Serial1.write(0x86); // 3 Serial1.write((byte) 0x00); // 4 Serial1.write((byte) 0x00); // 5 Serial1.write((byte) 0x00); // 6 Serial1.write((byte) 0x00); // 7 Serial1.write((byte) 0x00); // 8 Serial1.write(0x79); // 9(SUM) } // ■■ L-chka ■■ void Lchika() { switch(Lchika_task) { case 0: digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) Lchika_tim0 = millis(); Lchika_task++; //Serial.println(Lchika_cnt ++); break; case 1: if ( (millis() - Lchika_tim0) > Lchika_timH) { Lchika_task ++; } break; case 2: digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW Lchika_tim0 = millis(); Lchika_task++; break; case 3: if ( (millis() - Lchika_tim0) > Lchika_timL) { Lchika_task ++; } break; default: Lchika_task = 0; break; } } // ■■ LCD control ■■ void writeLcdCmd(byte t_command) { //コマンド書き込み Wire.beginTransmission(LCD_ADRS); Wire.write(0x00); Wire.write(t_command); Wire.endTransmission(); delay(10); } void writeLcdDat(byte t_data) { //データ書き込み Wire.beginTransmission(LCD_ADRS); Wire.write(0x40); Wire.write(t_data); Wire.endTransmission(); delay(1); } void LCD_DISP_16_1(void) { //上段の行にデータ書き込み writeLcdCmd(0x00 + 0x80); // for (int i = 0; i < 16; i++) { writeLcdDat(VRAM1[i]); } } void LCD_DISP_16_2(void) { //下段の行にデータ書き込み writeLcdCmd(0x40 + 0x80); // for (int i = 0; i < 16; i++) { writeLcdDat(VRAM2[i]); } } void init_LCD() { delay(100); //液晶初期化 writeLcdCmd(0x38); delay(20); // FUNCTION SET writeLcdCmd(0x39); delay(20); // IS=1 writeLcdCmd(0x14); delay(20); // INT OSC FREQUENCY writeLcdCmd(0x73); delay(20); //7faONTRAST SET0,1,2,3(3.3V=0x73,5V=0x7A) writeLcdCmd(0x56); delay(20); // 54CONTRAST SET 4,5 (3.3V=0x56, 5V= 0x54) writeLcdCmd(0x6C); delay(20); // F0LLOWER CONTROL writeLcdCmd(0x38); delay(20); // IS=0 writeLcdCmd(0x01); delay(20); // Clear Display writeLcdCmd(0x0C); delay(20); // Display ON } ```