さて、一番手を加えたのが通信部分である。関係するパラメータはCOM_REFRESHで、コメントでは50msになっているが、最終的には25msとした。またバッファサイズを定義するBUFSIZE以外に、通信用のバッファサイズとしてCOMBUFSIZEを定義し、これを32にしている。

コードそのものは、WinProc()の中のMessage Dispatchの中で、WM_TIMERイベントの処理である。温度センサーの時と同じく、今回はタイマーを2種類利用しており、TIMER_ID1はCOMポートと通信を行ってArduinoからデータを読み取る処理、TIMER_ID2は最終的に消費電力を画面を更新する処理である。まずこのTIMER_ID1であるが、確実にArduinoからデータを受け取るためには、

・不必要に受信バッファサイズを大きくしない
・1回の受信で複数回分のデータを受け取る可能性を考慮する

の2つの配慮が必要となった。温度センサーのときはそこまでデータ送信頻度が高くなかったので、これらがそれほど問題になることは無かったのだが、最大だと2周期毎(50Hz地域では毎秒25回:40ms毎)にデータを送りつけてくるWattMeterでは、

・バッファサイズを大きくしすぎると、ReadFile()がバッファが一杯になるまで帰ってこないため、時として25ms毎のTimer Eventの間に読み込みが終わらないトラブルが頻発した。そこでバッファそのものは256Bytes(BUFSIZE)で確保しつつも、受信サイズは32Bytes(COMBUFSIZE)に制限を掛ける事で早めにReadFile()を終わらせる事が可能となる。

ロジック的に言えば、ReadFile()の代わりにReadFileEx()を使って非同期読み出しを掛け、同時に更にタイマーを掛けて「時間までに帰ってこなかったら強制タイムアウト」という処理を実装することも可能だが、ここまでやる必要があるか? というのはちょっと疑問であり、今回はあっさりReadFile()で済ませることにした。

で、実はここまでやってもまだ1回のReadFile()の読み取りで、複数回分のデータを読み取っている可能性がある。温度センサーの場合はこれを切り捨てて最初の1つだけデータを読み取って終わりにしたが、今回はこれだと精度が下がるため、ReadFile()の後で読み取ったバッファの内容をfor()ループで廻して、全データの読み取りを行うことにした。この場合に問題になるのが、「それぞれのデータが正しく読み取れているか」である。例えばArduinoから、

15573 363 105
15535 352 104
15590 349 104

というデータが送られたとする。ところが、必ずしもこれをReadFile()で正しく読み取れるとは限らず、例えば、

5573 363 105
15535 352 104
15590 349 10

といった具合に前後が欠損して受け取る場合も考えられる。これを避けるために、かならずデータの頭に"a"、最後に"z"を付加して、

a15573 363 105z
a15535 352 104z
a15590 349 104z

と送るようにした訳だ。これにより、やはりデータが欠損して、

15573 363 105z
a15535 352 104z
a15590 349 104

となっても、一つ目のデータはaがないので読み飛ばし、二つ目のデータの処理を行う。そして3つ目はzがないのでやはり読み飛ばして終了である。前後のデータが欠落するのは勿体無いが、変な値として読み取るよりはずっとマシであろう。そんなわけで、for()ループの中ではstrchr()を使い、まず"a"、ついで"z"を検索し、この両方がある場合にのみsscanf_s()で値のParseを行って次に進むという処理を行うように書き換えている。

もう一つ、平均値の求め方もちょっと工夫した。例えば5回データをまとめて受け取ったとする。この電圧の値とサンプル回数が、

電圧値 サンプル数
1500 100
1510 101
1500 100
1490 99
1500 100

となったとする。この平均値をどう求めるか? 一番簡単なのは、まず積算してそのあと割り算である。こうすると平均値はジャスト15になる。ところが個別に計算すると、

電圧値 サンプル数 1回あたりの電圧平均値
1500 100 15
1510 101 14.9505
1500 100 15
1490 99 15.0505
1500 100 15
5回の平均値 15.0002

で、微妙にずれることになる。

実際これがどの程度影響するのかは微妙なところで、例えば個別に平均値を求めて合算だと計算数が増えることになり、これが取り込みに深刻な影響を与えるなら多少誤差があってもまとめて合算したほうがマシである。ところがこの処理はPC側で行っており、この程度の計算は殆ど影響を与えない。そんなわけで、Arduinoから1回分のデータをとるごとに1回あたりの電圧平均値を算出し、これをあとで平均するという仕組みにした。この平均を取るために、storeVol/storeAmp/storeWatt/numSampleという変数を新たに導入している。

(続く)