« 2014年11月30日 - 2014年12月6日 | トップページ | 2015年1月4日 - 2015年1月10日 »

2014年12月14日 - 2014年12月20日の1件の記事

2014年12月18日 (木)

心電計プロジェクト:TFT液晶に念願の心電波形が出た

 プロジェクト開始から半年かけて、やっとのことで2.4インチTFT液晶に想定通りの心電波形を出すことに成功した。まだ、枠線を引いていないし、振幅や時間幅の調整は、UARTによるPCコンソールからで、ケースにも入っていないバラックである。実用性はまだ限りなくゼロだが、とりあえずは一段落である。当初の計画いえば第4ステップの終了にあたる。

 それにしても、このプロジェクトは次から次に課題が発生して苦難の連続だった。今回も最後の最後で、画像ルーチンのバグに悩まされ、結局、コードを書き換えるという姑息な方法でバグを回避した。以下はその顛末である。

息抜きのつもりがストレス。1005チップ部品は手では無理(12/4/2014)
 前回のブログ記事は、センサーからのデータをフォトカプラー経由でSTM32F103が受け取り、TFT液晶にその値をグラフ描画するところまでだった。このときは心電波形をまだ確認していない。でもここまで来ればあともう一息である。

 画像が無事に出て、ちょっと息抜きに別のことをやりたくなった。こういう道草が今回のプロジェクト遅延の大きな要因でもあるのだが、なかなか止められない。寄り道のタネは秋月が最近出した、極小USBシリアルアダプターである。Pc056735 こいつは、秋月の定番のFT232RLを使ったUSBシリアルアダプターより、小型で(USBコネクターはマイクロだが)、値段も安い(¥600)。特にあてはないが買ってあった。しかし、今までのUSBアダプター同様、送信口(マイコンから見れば受信側)の電圧が2.7V近く上がる。例の「セパレーター」が必要だ。

 それより気に入らないのが青色ダイオードのパイロットランプである。日本人3人がノーベル賞を受賞したのであまり大きい声で言えないが、実は所長はこの青は好きではない。パイロットランプというのは、人の神経に触らない暖色系が良いのだが、青色というのは何となく人を不安にさせる。

 で、当然換装することにした。大きさは1608なのでこのチップLEDなら、緑、赤などの手持ちがある。低温ハンダを使わずに少し強引に青色LEDをはずす。何とかはずれた。ありゃま、隣の1005の制限抵抗(1kΩ)も一緒にはずれかかった。つけなおすためこれもはずす。

 ところが、この豆粒のようなチップ抵抗が行方不明になったのである。ピンセットで少し強くつまんだら、飛び跳ねたのだ。テーブルを慎重に見回し、床を這いずり回って調べたが見つからない。やれやれ1005の抵抗なんて手持ちはない。

 探し回るうち、こんなことに時間を浪費している自分がさすがに恥ずかしくなって、パイロットランプなしで行こうと決め、周辺を片付けているときに偶然発見した。何とチップ抵抗は、ハンダ付けのための固定に使っていたミニブレッドボードの表面と中の接続端子板の隙間に入っていた。

 難儀はこれですまなかった。ハンダごての熱で基板のLEDのパターンがはがれてくる。万事休す。あきらめきれず、銅線の切れ端で強引に新しい緑LEDを固定しようとして、今度はLEDをまたピンセットで飛ばしてしまう。そのうちハンダの熱で新しいLEDも表面をはがしておしゃかにする。

 こうなったら我慢くらべのようなものである。3つめのLEDを意地になって取り付け、やっと換装が終わった。ところがこのLEDが点かないのである。息抜きのつもりで始めた電子工作がこのありさまでストレスが一気に貯まる。何もかも放り出して大声を出したい気分である。

 ばかばかしいことをしている自分に無性に腹が立つが、ここで爆発しては今までの苦労がすべて無駄になる。ぐっとこらえて(笑ってください)、気分を鎮め、状況を最初から確認する。そのうち、基板を触ると一瞬LEDが点いたのが幸運だった。ハンダ付け不良の疑いが濃い。

 しかし、ちょっと見た所では問題はなさそうである。さらに色々触って試してみる。その結果、1005のチップ抵抗の一方が完全にハンダ付けされていないことを発見した。ハンダが多すぎてチップをとりかこんではいるが接触していなかったのである。やれやれ。

コンペアマッチが効かないのもお恥ずかしい基本的なミス(12/10/2014)

 雑事で忙しかったこともあるが、わかってしまえば極く当たり前のことに、この3日間頭を抱えていた。今度もここに書くのもお恥ずかしい基本的なミスである。

 心電波形の表示は、時間軸を可変にしておきたい。というのでARMのタイマーにコンペアマッチのステートメントを入れたのだが、これが、がんとして指定の時間に割り込みが入らないのだ。

 気に入らないのが、コンペアマッチの割り込みは順調にかかっているのに、どうしても時間が指定の時間にならない。必ずタイマーのオーバーフローの時間になる。

 いざとなれば、オーバーフローのタイマー設定値を変えても良いのだが、これまでARMのタイマーでコンペアマッチの機能は使ったことがない。経験値を高めるためにも、動かしておきたい。しかしAVRと違って、ARMのタイマーは高機能なので設定することが山ほどある。どれが正しい設定かわからない。

 PWM出力ピンも使わない単純なコンペアマッチだが、それだけでも10近いステートメントで定義しなければならない。ひとつひとつを何度も参考書やウェブのサンプルと見比べるが、どこも間違っていない(ように見える)。謎は、割り込みは正常にオーバーフローと区別しているのに時間が変わらないことである。

 結局、オーバーフロー割り込みとコンペアマッチ割り込みの2つの時間をオシロに出して、始めてその間違いに気づいた。画面にはコンペアマッチの指定分だけ遅れた同じ幅の波形が出た。あ、あ、あ、何という事だ。もう情けないというか、ただ笑うしかない、基本的な勘違いである。

 要するにカウンターがコンペアマッチしたときにリセットしていないのが原因である。AVRではコンペアマッチするとカウンターがリセットされていたので、そのままにしていた。あーあ、何で今まで気が付かなかったのだろう。

 ちゃんと、コンペアマッチで割り込みがかかっても、レジスターをそのままにしておけば、次の割り込みは、レジスターが一周してくるときだ。つまりオーバーフロー値から一歩も動かない時間となる。当たり前だ。

 ARMの関数一覧から、レジスターの値を設定する関数を探し出し、ゼロにするステップを加えて、めでたくタイマーは指定の時間に割り込みがかかるようになった。コンペアマッチで必ずカウンターがリセットされるという思い込みが招いたお粗末である。

グラフもそれらしい波形が出てきた。増幅が難しい(12/12/2014) 
 PCコンソールからのコマンド入力で、表示速度が変化できるようになった。表示される心電波形も、腕のサポートを少しきついハンカチにして、時間をおくと(数分)、だいぶそれらしい波形が出てきた。皮膚と電極の間の抵抗は、時間をかけないと低くならないようだ。Pc116761 ただ、表示波形は、振幅がまだ小さいので、増幅してやる必要がある。しかし、やみくもに、出た数字を大きくしても電圧の高いところでの変化はオーバーしてしまう。AC測定のような工夫が必要である。

 中位電位の設定が難しい。出てくるデータが必ずしも、中間で上下しているわけではない。しかも移動する。始め、中位電圧をコマンドで指定するようにして、そこを起点にAC測定ということにしたが、中位点を固定してしまうと波形がそこからずれると表示されなくなる。難しいものだ。

 そのうち、うまい方法を思いついた。1フレーム(画面)程度のデータの平均値をとり、それを次の画面の中位電位にして、そことの差分を増幅する。画面ごとに中位電位が変動するが、これにより、相当程度増幅(10倍近く)しても、折れ線グラフがはずれなくなった。

 増幅度も、コマンドで調整できるようになり、これで心電波形もかなりはっきりでてきた。嬉しい。やっと完成に近づいてきた。やはり、腕に電極をしっかりつければ倍率を上げなくても明瞭に出てくる。しかし、グラフ表示がドット単位なので、値が飛ぶところは、点だけになってしまう。Pc146773

 これは、以前からわかっていたことで、大きく値が変化したところは何らかの補正をしてドットを補っていく必要があるが、考えているうちもっと良い方法を思いついた。しかし、この実現にはまた難儀が待っていたのである。

ラインを引く描画関数のバグに悩まされるが、回避した(12/16/2014)
 折れ線グラフの補正は、何も、大きく変動したときだけに限定する必要はない。始めから、ドットではなく、前の値からの線分を引けば、完全な折れ線グラフになる。おお、これは完全な解決だ。こういう解決は気分が良い。線を引く関数は、たいていの描画関数には揃っているはずだ。

 あった、あった。Disply_DrawLine_If()という関数を見つけた。画面上の2点を指定すれば、そこに指定した色で線を引いてくれる。これまでのDisplay_FillRect_If()という描画関数(グラフを太くするため2X2の領域塗りつぶし関数)をこれに換えるだけで良いはずだ。

 ただし、起点と終点がいるので、起点となる前の値を残しておく変数を新たに設定する。コーディングはあっという間に完成した。上機嫌でテストに入る。

Pc166774 おやあ、変な斜め線が入って正しい波形にならない。これは何だろう。値が急激に上昇するときにヒゲが沢山入る。下降の時は問題ないが、よく見ると上昇のときはわずかな変化でも正しい線が引かれていない。

 最初は、符号付の指定である関数の引数に符号なしのデータを入れているのが原因かと思って、データを揃えたが変わらない。仕方なく関数のソースコードを調べ始めた。

 何やら難しい手法で線を引いている。コメントによれば Bresenham Algorithum(ブレゼンハムアルゴリズム)というのらしい。ウェブで調べると、こういう描画の時の古典的な定番のテクニックらしく、色々なサイトで紹介されている。

 少し調べたが、間違いはなさそうだ。こういうソースコードにバグは考えにくい。何か、前提となるところが間違っているのだと思うが、思い当るところがない。もしかしたら、入れている数値がおかしいのかもしれない。

 こうなると意地になるのが所長の特徴である。コマンドを新しく作って、心電波形に近いピークの波形(一方が最少の変化で、もう一方が激しく動く)をリテラルで指定し表示させてみた。見事に間違った波形が表示された。よし、関数のバグであることに間違いない。

 しかし、どこが間違っているのか特定できない。机上の計算では間違いないのに何故か暴れる。暴れる原因は、線分のX座標の低いところから高いところの線だけがおかしく、逆は問題ない。Y座標はどちらでもセーフである。

 考えているうち、簡便な解決法を思いついた。線を引くだけなら、どちらを始点にしても変わらない。関数のバグは解明できなくても、描画する前に始点と終点を調べて、バグが出ない方向で関数を呼び出せばよいのだ。

 早速、コードを追加し(ifで同じ関数を引数だけ換えて呼び出すだけ)、テストに入った。でました。でました。これまでのような飛び飛びの描画ではなく、連続したグラフが美しく表示されるようになった。ラインを2重に引いた(座標を1つずらす)ので折れ線グラフがはっきり見えるようになった。

Pc176775

 まだ、細かいところや、枠線などがないので完璧とは言えないが、当面の心電波形の表示はこれで完成と言える。いやあ、長かったけれど何とかここまできた。達成感で胸が膨らむ。

 このあとは、スケールを描くこと、PCコンソールではなく、ロータリーエンコーダのようなもので調整が出来るようにすること、ケースに入れることなどが残っているが峠は越した。

 ただ、少しひっかかるところがある。表示波形のR波(一番鋭いところ)のピーク値が低いことだ。後のT波、U波と同じくらいである。もしかしたら病気なのかも知れないが、そうではなくて、サンプリングが少ない可能性の方が強い(希望的観測)。

 AVRとARMのUARTインターフェースで、第一バイトを識別するためデータを端折っている。残さずデータをARMに送るのは、以前、コメントでいただいた、5ビットづつの2バイト送信ロジックを検討してみるのも面白いかもしれない。いやいや、やることはまだ山ほどある。

| | コメント (4) | トラックバック (0)

« 2014年11月30日 - 2014年12月6日 | トップページ | 2015年1月4日 - 2015年1月10日 »