心電計プロジェクト:TFT液晶に念願の心電波形が出た
プロジェクト開始から半年かけて、やっとのことで2.4インチTFT液晶に想定通りの心電波形を出すことに成功した。まだ、枠線を引いていないし、振幅や時間幅の調整は、UARTによるPCコンソールからで、ケースにも入っていないバラックである。実用性はまだ限りなくゼロだが、とりあえずは一段落である。当初の計画でいえば第4ステップの終了にあたる。
それにしても、このプロジェクトは次から次に課題が発生して苦難の連続だった。今回も最後の最後で、画像ルーチンのバグに悩まされ、結局、コードを書き換えるという姑息な方法でバグを回避した。以下はその顛末である。
息抜きのつもりがストレス。1005チップ部品は手では無理(12/4/2014)
前回のブログ記事は、センサーからのデータをフォトカプラー経由でSTM32F103が受け取り、TFT液晶にその値をグラフ描画するところまでだった。このときは心電波形をまだ確認していない。でもここまで来ればあともう一息である。
画像が無事に出て、ちょっと息抜きに別のことをやりたくなった。こういう道草が今回のプロジェクト遅延の大きな要因でもあるのだが、なかなか止められない。寄り道のタネは秋月が最近出した、極小USBシリアルアダプターである。 こいつは、秋月の定番の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コンソールからのコマンド入力で、表示速度が変化できるようになった。表示される心電波形も、腕のサポートを少しきついハンカチにして、時間をおくと(数分)、だいぶそれらしい波形が出てきた。皮膚と電極の間の抵抗は、時間をかけないと低くならないようだ。 ただ、表示波形は、振幅がまだ小さいので、増幅してやる必要がある。しかし、やみくもに、出た数字を大きくしても電圧の高いところでの変化はオーバーしてしまう。AC測定のような工夫が必要である。
中位電位の設定が難しい。出てくるデータが必ずしも、中間で上下しているわけではない。しかも移動する。始め、中位電圧をコマンドで指定するようにして、そこを起点にAC測定ということにしたが、中位点を固定してしまうと波形がそこからずれると表示されなくなる。難しいものだ。
そのうち、うまい方法を思いついた。1フレーム(画面)程度のデータの平均値をとり、それを次の画面の中位電位にして、そことの差分を増幅する。画面ごとに中位電位が変動するが、これにより、相当程度増幅(10倍近く)しても、折れ線グラフがはずれなくなった。
増幅度も、コマンドで調整できるようになり、これで心電波形もかなりはっきりでてきた。嬉しい。やっと完成に近づいてきた。やはり、腕に電極をしっかりつければ倍率を上げなくても明瞭に出てくる。しかし、グラフ表示がドット単位なので、値が飛ぶところは、点だけになってしまう。
これは、以前からわかっていたことで、大きく値が変化したところは何らかの補正をしてドットを補っていく必要があるが、考えているうちもっと良い方法を思いついた。しかし、この実現にはまた難儀が待っていたのである。
ラインを引く描画関数のバグに悩まされるが、回避した(12/16/2014)
折れ線グラフの補正は、何も、大きく変動したときだけに限定する必要はない。始めから、ドットではなく、前の値からの線分を引けば、完全な折れ線グラフになる。おお、これは完全な解決だ。こういう解決は気分が良い。線を引く関数は、たいていの描画関数には揃っているはずだ。
あった、あった。Disply_DrawLine_If()という関数を見つけた。画面上の2点を指定すれば、そこに指定した色で線を引いてくれる。これまでのDisplay_FillRect_If()という描画関数(グラフを太くするため2X2の領域塗りつぶし関数)をこれに換えるだけで良いはずだ。
ただし、起点と終点がいるので、起点となる前の値を残しておく変数を新たに設定する。コーディングはあっという間に完成した。上機嫌でテストに入る。
おやあ、変な斜め線が入って正しい波形にならない。これは何だろう。値が急激に上昇するときにヒゲが沢山入る。下降の時は問題ないが、よく見ると上昇のときはわずかな変化でも正しい線が引かれていない。
最初は、符号付の指定である関数の引数に符号なしのデータを入れているのが原因かと思って、データを揃えたが変わらない。仕方なく関数のソースコードを調べ始めた。
何やら難しい手法で線を引いている。コメントによれば Bresenham Algorithum(ブレゼンハムアルゴリズム)というのらしい。ウェブで調べると、こういう描画の時の古典的な定番のテクニックらしく、色々なサイトで紹介されている。
少し調べたが、間違いはなさそうだ。こういうソースコードにバグは考えにくい。何か、前提となるところが間違っているのだと思うが、思い当るところがない。もしかしたら、入れている数値がおかしいのかもしれない。
こうなると意地になるのが所長の特徴である。コマンドを新しく作って、心電波形に近いピークの波形(一方が最少の変化で、もう一方が激しく動く)をリテラルで指定し表示させてみた。見事に間違った波形が表示された。よし、関数のバグであることに間違いない。
しかし、どこが間違っているのか特定できない。机上の計算では間違いないのに何故か暴れる。暴れる原因は、線分のX座標の低いところから高いところの線だけがおかしく、逆は問題ない。Y座標はどちらでもセーフである。
考えているうち、簡便な解決法を思いついた。線を引くだけなら、どちらを始点にしても変わらない。関数のバグは解明できなくても、描画する前に始点と終点を調べて、バグが出ない方向で関数を呼び出せばよいのだ。
早速、コードを追加し(ifで同じ関数を引数だけ換えて呼び出すだけ)、テストに入った。でました。でました。これまでのような飛び飛びの描画ではなく、連続したグラフが美しく表示されるようになった。ラインを2重に引いた(座標を1つずらす)ので折れ線グラフがはっきり見えるようになった。
まだ、細かいところや、枠線などがないので完璧とは言えないが、当面の心電波形の表示はこれで完成と言える。いやあ、長かったけれど何とかここまできた。達成感で胸が膨らむ。
このあとは、スケールを描くこと、PCコンソールではなく、ロータリーエンコーダのようなもので調整が出来るようにすること、ケースに入れることなどが残っているが峠は越した。
ただ、少しひっかかるところがある。表示波形のR波(一番鋭いところ)のピーク値が低いことだ。後のT波、U波と同じくらいである。もしかしたら病気なのかも知れないが、そうではなくて、サンプリングが少ない可能性の方が強い(希望的観測)。
AVRとARMのUARTインターフェースで、第一バイトを識別するためデータを端折っている。残さずデータをARMに送るのは、以前、コメントでいただいた、5ビットづつの2バイト送信ロジックを検討してみるのも面白いかもしれない。いやいや、やることはまだ山ほどある。
| 固定リンク
「電子工作」カテゴリの記事
- 生存証明2(2022.10.19)
- 生存証明(2022.01.23)
- パソコン連動テーブルタップの修理を諦めて自作(2021.02.16)
- 半年ぶりのブログ更新に漕ぎつけた(2019.09.19)
- 研究所活動は停滞したままでCCDカメラ顕微鏡導入など(2019.02.08)
「ARM」カテゴリの記事
- 心電計プロジェクト:スケールが出ると心電計らしくなる(2015.01.08)
- 心電計プロジェクト:TFT液晶に念願の心電波形が出た(2014.12.18)
- 心電計プロジェクト:STM32F103の心電波形表示で悪戦苦闘(2014.12.03)
- 心電計プロジェクト:CooCoxでARMの表示系ソフトを開発する(2014.10.16)
- 心電計プロジェクト:表示部のARM基板の開発環境を一新する(2014.09.19)
コメント
O-familyさん、コメントありがとうございます。
ちょっと忙しくて対応が遅れ申し訳ありませんでした。
>左右逆ではないですか?
はい、承知しています。枠線を引くときに直す予定ですが、
他にやることが沢山あって進んでいません。
でも、これ、表示装置を逆にして、波形の極性を逆転
(手の電極を左右逆に)すれば、正しい方向に
なるんですよね。迷っています。
詳しい解説ありがとうございます。
ははは、診断ができるほどの精度は考えていません。
ノイズがとれませんね。それでも、心拍数くらいは出せそうです。
投稿: がた老 | 2014年12月27日 (土) 12時21分
心電計が進展しているようですね。すばらしいです!
心電図の描画方向が左右逆ではないですか?
一般的な心電計は、画面の左から、
・P波-小さな山(心房が起動)
・QRS郡-落ち込みがQ波、ピークがR波、再度落ち込むのがS波(心臓の収縮)
・T波-幅の広い大きな山(心臓の拡張)
・U波-見えるか見えないかの小山
病気の判定は、四肢誘導(Ⅰ,Ⅱ,Ⅲ,aVR,aVL,aVF誘導)と胸部誘導(V1~V6)の12個の極性や変異を見て、おおよその診断がされます。
Ⅰ誘導だけでは、期外収縮、心房(心室)細動、頻拍、除拍などの、明らかな異常なら見つかると思います。
まずは、R波-R波間の時間を計って、心拍数を表示してみてはいかがですか!
投稿: O-Family | 2014年12月22日 (月) 23時34分
ねむいさん、早速のご対応ありがとうございました。
何か狙い打ちのように、ねむいさんのコードのあらさがしをしているようで申し訳ありません。
いずれ差し替えますが、今のところ無事表示はできていますのでご心配なく。
投稿: がた老 | 2014年12月18日 (木) 21時25分
がた老さまこんばんは、ねむいです。
直線描画のルーチンにおいて各軸の終点の値が起点より小さいときに
正しく表示されないバグがありました。真に申し訳ありません。
私の置場のSTM32F107向けの作例はひとまず修正しましたので
お手数ですが差し替え願います。また、直線描画関数の引数順序もレクタングル
系のものとすべて統一しました。同じくお手数ですがお手元のプログラム
は新しい引数の順序に修正願います。
投稿: ねむい | 2014年12月18日 (木) 21時10分