Wio NodeでCO2などの観測

会社がどうも眠いので、CO2濃度が高すぎるんじゃね、ということで測ってみることにしました。

ちなみに、オフィスのCO2上限は建築物環境衛生管理基準によると1000ppmですかね。北海道でトンネル掘ってた頃を思い出して、坑内の上限を調べてみたら、労働安全衛生規則第五百八十三条によれば、CO2濃度は1.5%以下。15000ppm............

測定マイコンについて

会社に雑において使う予定なのでローコストかつ最低限の外付け回路で動く作戦でゆきます。今回はWio NodeというESP8266を載せた小型のIoTボードを使うことにしました。1kぐらいから買えます。
www.switch-science.com
Wio Nodeはそれ単体で書き換えなくてもなんか遊べるらしいですが、そうではなくESP8266のArduinoボードとして使っています。普通にESP8266のブレイクアウトを買うと、ファーム書き込みモード切替回路とかつけないとあかんけど、Wio NodeはすでにGROOVEコネクタで外につながるとか5VのUSB給電から3.3Vに降圧してESP8266に給電するなどの本質的でない部分がすでに実装済みで楽です。それに、LiPoバッテリつなぐ回路もついているので、移動する際もUSB給電すっこ抜いて移動するとかできて楽。

CO2センサについて

さて本題のCO2センサ。いろいろ調べた結果、MH-Z19BというNDIRセンサをAliExpressで発注しました。
www.aliexpress.com
qiita.com

MH-Z19Bの上限は5000ppmなので、トンネルのような過酷な場所で測定するならMH-410Dとかでしょうか。普通は2000ppmもあれば人間センサが文句を言い出す(らしい)ので5000ppmもあれば十分だと思いたい。

ちなみにこのセンサ、5Vを要求してきます。一方でESP8266は3.3Vで動くし、WioNodeも出力は3.3Vしかない。回路内見るとLiPoチャージャETA6003から出てるの5Vっぽいんだけど、基盤見ても小さすぎて引っ張り出せる気がしない。そこで、秋月行って5V出力の昇圧DDコンバータを調達。
akizukidenshi.com

センサとマイコンをつなぐ。

センサのIFを調べると、UART(9600bpsシリアル通信)とPWM(Hiレベルの継続時間)とアナログ電圧の3つがあって、UARTが一番ラクじゃろとUARTを選択。

とはいえ、ESP8266のUARTが事実上一つしかない*1上にそのUARTが何から何まで吐き出すコンソールなので、そのままデバイスを繋ぐのは微妙すぎるからなんか考えないといけない。

SoftwareSerial作戦

最初はソフトウェアメインでSoftwareSerialを使う作戦を考えた。ちゃんとESP8266版実装もある。
github.com

実際に組んでみると、まずSoftwareSerialは起動直後に取りにゆくとデータが正しく読めなかったので暫く待ってから読むようにした。そうすれば起動直後は景気よく動くんですがしばらく(数十分)ほっとくとデータが取れなくなるというか、おかしなデータを受信する。

なんでやなぁと思いながらソースを見ると、データ受信をピンに対するハードウェア割り込み使ってる部分が目に入った。ESP8266はWiFiバイス積んでることを考えると自分の意図しない割り込みたくさん使ってることが想定され、暫くほっとくとデータ受信のタイミングで他の割り込みが被って割り込みタイミングがずれてデータがおかしくなる気がした。flushを呼ぶと内部バッファのインデックスが初期化される*2ので、データをやりとりする直前に呼ぶようにするとデータが数日間安定して取れるようになりました。

これでCO2測定はできたんですが、ついでにBME280もつないでやろうと欲を出す。
akizukidenshi.com

BME280はI2C接続で、Wio NodeはESP8266デフォルトのI2C IOと繋がる。そうするとソフトウェアシリアルを繋ぐGPIOがなくなってしまう。

Wio Nodeはオープンソースハードウェアなので、「ESP8266のGPIOが10以上あってUARTとかI2Cとかに使われてるとはいえなんぼか余ってるやろと」と公開されている回路図とかパターンを見てみるとGPIO12~14が使われずNCになってる。
f:id:W53SA:20180627025106p:plain
f:id:W53SA:20180627025120p:plain

そこで、GROVEコネクタを買ってきて、UEW線を頑張ってはんだ付けした。コネクタは付ける場所が他にないのでESP-WROOM-02上に子亀。


GPIOふたつと、VccとGND合計四本引っ張っておく。あとはSoftwareSerialのTX/RXに使うピンをそっちに変えれば動いた*3

f:id:W53SA:20180704015258p:plain
最終的な見てくれはこんな感じ。とりあえずこれを会社に持ってゆき、隅っこに放置して記録をAmbientに投入して様子を見ています。

I2C-UART作戦

コネクタ増設はちょっと見てくれが良くないので、せっかくI2Cでデバイスを繋いでるんだからインタフェイスI2CなUARTぐらいあるじゃろ、と思ったら16450互換のUARTを積んでインタフェイスがI2Cの石、SC16IS750を見つけた。

日本で買うと、手っ取り早いのはスイッチサイエンスのやつ。
www.switch-science.com
でも、こいつは12MHzのXTALが載ってる。データシート曰く*4、通信速度を指定する式は以下。
divisor = \frac{(\frac{XTAL freq.}{prescaler})}{{baud rate \times 16}}
ここでXTAL freq.に12M(=12000000)を入れると、レジスタに書くdivisorが78.125で整数にならない。適当にdivisorを78にすると、9615.38bpsとかになって、これ通信できるの・・・?(誰かチャレンジしてほしいなぁ)

調べたところ、Sparkfunのbreakoutが14.7456MHzのXTALを積んでて、これなら9600bpsでもdivisorが96なので設定できる。
www.sparkfun.com
これはディスコンなんですが、インターネットを検索するとCJMCU-750という名前で同じデザインの基盤がAliExpressあたりで売ってる。
www.aliexpress.com
スクショを見る限りは14.7456MHzのXTALを積んでるように見えたので発注してみる。

届いたものを見ると無事に14.7456MHzが載ってたので、組んでみた。

ついでにI2CのLCDもぶら下げてある。
akizukidenshi.com
℃とかない文字はカスタム文字をキャラクタ情報に突っ込んであります。
maxpromer.github.io
いい時代なのでジェネレータがあります。

ブレッドボードに組み上げたら、こんな感じ。
f:id:W53SA:20180704015412p:plain

余談

f:id:W53SA:20180710121525p:plain
Wio Nodeの外部デバイスに電源供給する3V3BラインはGPIO15をHiにすると流れるってWikiにも書いてある*5。どうも起動時にGPIO15がINPUTになって3V3Bへの供給が不安定なのか、起動直後のBME280取得データがおかしな感じになっていたので1秒ぐらい読み捨てする実装を入れました。もしかしたらSoftwareSerialで最初にCO2センサとの会話が失敗したのも、SoftwareSerialでの書き込みがうまくいってないのかも(ちゃんと調べてない)。

内部状態が安定するまでウェイト入れたりしなきゃいけないんだなーというのを再確認して、なんというかハードウェアは大変やな(ほんまか)。

*1:2つ目のUARTはTxDしかない

*2:HardwareSerialの実装は違っていてTXが空っぽになるのを待つ実装になっているので差異に注意。cf. https://github.com/esp8266/Arduino/blob/master/cores/esp8266/HardwareSerial.cpp#L99

*3:I2Cのピンを変えてもいいんだろうけど未検証

*4:詳しくは7.8 Programmable baud rate generatorを参照

*5:これ書いた時点でのWikiは「VCC converge together and can be controlled with GPIO 15. 」です。