前回書いた 心拍センサを Seeeduino で使ってみる 記事では、公式ページで紹介されているサンプルコードをベースに心拍センサでの心拍の検知をインタラプトで受け取るため、 Grove コネクタにジャンパケーブルを挿して D2 ピンを使っていました。
ですがこれだと折角 Grove コネクタがついているのにそのメリットを活かすことができません。インタラプトで受け取ることありきで考えていたので仕方ないかなと思っていたのですが、前回の記事公開後に下記のようなコメントをいただきました。
そこで今回は Grove コネクタで I2C に接続して、ポーリングで処理する版を試してみました。
回路構成
今回の回路は Grove コネクタを Seeduino の Grove コネクタの I2C に接続するだけなのですっきりシンプル構成です。
ファームウェア
前回のコードをベースにいくつか変更を加えました。
前回は setup()
で attachInterrupt()
を使って割り込みを受け付ける設定をしていましたが、その部分を削除し、代わりに pinMode()
で A5 ピンからセンサの入力を読み取るための設定をしています。
また、 前回は loop()
では何もしていませんでしたが、前回割り込み検知時に実行していた処理を 100ms の delay で繰り返し実行するようにし、その中で A5 ピンの入力値をチェックするようにしています。
A5 ピンからの入力値が 0 の場合もしくは 1 の状態が続いているときは何もせずに return し、0 から 1 に変化した時には前回同様の後続の処理を行うことで、インタラプト使用時と同じ挙動になるようにしてみました。もし 100ms 未満の間隔で心拍を検知してまた 0 に戻るようなことがあると検知できないのですが、最初に入力値が 1 かどうかだけをチェックしてやってみたところ、 100ms の delay で 1 の状態が複数回続いていたので、今回はこのやり方でやってみています。
unsigned char counter; unsigned long temp[21]; unsigned long sub; bool data_effect = true; unsigned int heart_rate; int hrm_output; int hrm_output_tmp; const int max_heartpluse_duty = 2000; void setup() { Serial.begin(9600); Serial.println("Please ready your chest belt."); delay(5000); arrayInit(); Serial.println("Heart rate test begin."); pinMode(A5, INPUT); } void loop() { interrupt(); delay(100); } void sum() { if(data_effect) { heart_rate = 1200000 / (temp[20] - temp[0]); Serial.print("Heart_rate_is:\t"); Serial.println(heart_rate); } data_effect = 1; } void interrupt() { hrm_output_tmp = digitalRead(A5); if(hrm_output_tmp == 0) { hrm_output = 0; return; } if(hrm_output_tmp == hrm_output) { return; } hrm_output = hrm_output_tmp; temp[counter] = millis(); Serial.println(counter,DEC); Serial.println(temp[counter]); switch(counter) { case 0: sub = temp[counter] - temp[20]; Serial.println(sub); break; default: sub = temp[counter] - temp[counter - 1]; Serial.println(sub); break; } if(sub > max_heartpluse_duty) { data_effect = 0; counter = 0; Serial.println("Heart rate measure error,test will restart!" ); arrayInit(); } if (counter == 20 && data_effect) { counter = 0; sum(); } else if(counter != 20 && data_effect) counter++; else { counter = 0; data_effect = 1; } } void arrayInit() { for(unsigned char i = 0; i < 20; i++) { temp[i] = 0; } temp[20] = millis(); }
これを実行すると前回同様に Serial モニタに下記のように出力されます。前回のコードで実行した時と大体同じような結果になったので、ひとまず計測できているようです。
0 1620177 1001 1 1621079 902 2 1622079 1000 3 1623079 1000 4 1623981 902 5 1624881 900 6 1625882 1001 7 1626782 900 8 1627583 801 9 1628583 1000 10 1629485 902 11 1630285 800 12 1631086 801 13 1631987 901 14 1632988 1001 15 1633889 901 16 1634789 900 17 1635690 901 18 1636590 900 19 1637491 901 20 1638292 801 Heart_rate_is: 66
まとめ
センサからのデータの発生タイミングに依存する処理を行う場合には、インタラプト処理の方がポーリング間隔等を気にする必要もないので向いていると思いますが、一方でプロトタイピングを行う場合は Grove コネクタ等を活用することで半田付けや複雑な配線をしなくて済むのはメリットが大きいですね。特に仕事でプロトタイピングをする場合はいかに機材を少なくして半田付けもなしで試せるかというのは重要なので、やりたい内容によって使い分けるのが重要に思います。
@maris_HY さん、コメントありがとうございました!