● 実験テーマ91
「PIC16F_心電計制御・表示部の実験」
(前作の計装アンプと組合せ、PIC16F1938を使って、AC誘導ノイズを、ソフト演算のみで除去し、GLCDに心電波形を表示する実験です。)
※ 170518:
ソフトを更新し、_V1aとしました。
<修正点>
@ 1S/Dを追加。500mS/Dとの切替は、P_ON時の、READY SWの状態で行う。
押さないで、P_ON:500mS/D・押して、P_ON:1S/D
としました。
以下に、1S/Dで観測した、私の心電波形をアップしました。
R波が 4つ見えるようになったので、より、ECGらしくなったと思います。
左から、1本目の破線のX軸が、心拍数=60bpmに相当します。
その半分のところが、90bpmになるので、70〜75bpm位でしょうか。 ←170703:誤記修正
その半分のところが、120bpmになるので90bpm位でしょうか
5月17日からの記事を参照してください。
以下、この実験の顛末記です。
■ 2017.4.12
・実験テーマ89では、計装アンプ出力を、AD変換した後、dsPICの、DSP機能によるノッチフィルタを通し、
さらにDA変換して、その出力を、自作のオシロで、心電波形としてモニタしていたが、今回は、DSP機能に
頼ることなく、PICのソフト演算のみで、AC誘導ノイズ除去し、そのまま液晶に表示する実験をしてみました。
つまり専用の心電計制御・表示部(とは言っても、外観はオシロのような物ですが・・・)の作成ということになります。
・最終的には、アンプ部を含めて、全体を電池駆動としたい為、出来るだけ省エネにしたい。
そうすうと、必然的に、GLCDは、モノクロで、バックライト無しで使うことになる。
ちょっと大きいが手持ちの、いつもの、GLCD(128 x
64dot):SG12864ASLB-GBを使うことにした。
最初、手軽にテストするとして、現行の、dsPIC30Fトレーニング基板をつかおうと思った。
そこで、GLCDのデータバス8bitをアクセスするのに、D0〜D7まで連続したポートを使いたいが、
dsPIC30F4013では、8つ連続しているポートが無いようだ。
今回は、dsPICにこだわらない方が良いかも。
普通のPICで、移動加算・平均を行い、AC誘導ノイズを除去するのが主目的だし。
Web例では、PIC16F819(18pin)とか、PIC16F873A(28pin)を使っているが。
■ 2017.4.13
・PICに何を使うかまだ迷っているが、先にアナログ入力部を検討することにした。
心電計アンプ部はそのままにする。(帯域:0.3Hz〜
約1kHz)
制御部側の、アンプ部は基本、dsPIC30Fトレーニング基板と同じにする。
但し、2ndの、多重帰還形アクティブLPFのカットオフは、5kHzでは高すぎるので、300Hz程度に落とす。
1st反転アンプで、x1〜 x6倍の、GAIN可変、2ndLPF(反転)で、ZERO可変が出来る様にポテンショを
実装する。
■ 2017.4.14
・適当にSWポートは、2つ位、用意。LEDポートは、1つでよいだろう。
波形ホールドは必要なので、HOLD SWと、SINGLEトリガ時の、READY
SWとする。
LEDは、READY LEDとして使う。(自作オシロと同じになったが・・・)
また、トリガレベルは、R波の立上りに同期するように、820(約4V相当)を考えているが、最初は
FG入力でテストするので、センタレベル:512固定にしておく。(10bitAD,
Vref= Vdd= 5V)
ADサンプルは、時間軸レンジ:500mS/D相当のサンプル周期を考えている。(これも固定で実験)
・迷っていたPICであるが、Web例の、PIC16F819(18pin)とか、PIC18F873A(28pin)は、やや古目の
機種(8bitミッドレンジ・シリーズ)でもあるので、最近の、PIC16F1シリーズを使った方が、消費電流も
少なくなっているようなので、F1シリーズを使ってみることにした。
Web例で、PIC16F1938を使った、SG12864A表示テストの例が、「きむ茶工房ガレージハウス」さん
のHPに載っていたので、それを参考に、まずは、自分なりに、PIC16F1938での、GLCDテスト・ソフト
を考えてみることにした。
(PIC16F1938は、超小型2行x8キャラ表示の液晶を使った、湿度・気圧計の時、使ったことあるが、
SG12864Aを動かすのは初めて。)
省エネ思考なので、Fosc=
8MHzで動かす。
またきむ茶工房さんのは、液晶ライブラリ化されてない。
私が今迄使ってきた、大元が後閑さん作成のライブラリとフォントデータが使えるように、改修したいと考えている。
■ 2017.4.15
・ポート割付けを考えた。
きむ茶工房さんは、GLCDの、8bitデータバスを、RB0〜
RB7に割付けているが、SW取り込みを、
状態変化割込みで扱えるようにしたいと考えている。
ところが、このPICは、状態変化割込みを使用できるポートは、RBポートに限られている。
なので、RBポートは、SWポートとして使い、GLCDの、8bitデータバスは、RA0〜 RA7に割付けることにした。
そしてアナログ入力ピンは、AN12(RB0)に割付けることにした。
■ 2017.4.17
・今迄の考えを基本に、回路図を水魚堂にて作成した。
・ハードウエアを作らないといけないので、部品を手配した。(今回もユニバーサル)
・心電計ソフト検討
まずは、PIC16F1938で、GLCDテストプロを動かすのを目標にする。
■ 2017.4.18〜 2017.4.26
・この期間は、ちょっと寄り道して、JA1WBYさんの、PIC32MX_GAME基板を使っての、液晶実験などを
やっていた。→ 実験テーマ90
■ 2017.4.27
・寄り道が一段落したので、心電計に戻ることに。
ハードのパーツは既に揃っているが、PIC16F1938での、GLCDテストプロを作成した。
開発環境は、MPLAB X IDE + XC8コンパイラ + PIKkit3
である。
以前作成した、C30或いは、C32での、テストソースを基に、XC8に適応するように置換える作業を行った。
結構、記述上異なる点(遅延関数の記述とか、ビット単位での記述は、単にポート名或いは、ビット名
だけで、・・.bitsの記述は省略可等)があり、多少とまどったが、何とか、まとめ上げた。
ようやく基板加工を始めた。
■ 2017.5.2
・部品実装が上がった。
・HEX書込みが最初出来なかった。
デバイスIDエラーになってしまう?
これは、凡ミス(配線ミス)が原因だった。
PICkit3-3ピン:RESETが、GNDのままになっていたので当然だ。
タクトSWのピン配置の見方の、勘違いによる配線ミスだった。(3個のSW全て)
このSW、4ピンあるが、縦・横で、ピッチが異なる。
内部で、ショートしている部分が、SW機構になっている。それは、長手方向だった。
これを、短い方向と勘違いしてしまった。修正で、無事HEX書込みOKとなる。
・いよいよ動作確認。
まず駄目。CS1側が表示しない。
これは以前の私のメモを見たらヒントがあった。
全てのコントロール信号レベルの初期化が必要である。
特に必要なのは、CS1,CS2を、Hiに初期化と思われる。
コントロール・ポートの方向レジスタ設定後に、この初期化を追加した。
(この順番は、以前PIC24H等では、逆で100%問題なかったが、今回PIC16F1は、この順にしないと
100% OKにならなかった。出力ポートの構成に何かハード的な違いがあるのだろうか?未調査だが・・)
これで、GLCD表示テストは、OKになった。
以下に、いつもと同じだが、表示サンプルを示す。
■ 2017.5.3
・アナログ・アンプ部のチェックを行う。
特に問題はなかった。ポテンショの、CWとCCWの逆配線ミス位だった。
きちんと、ZERO/GAINの調整をすれば、動作範囲の中で、正しくセロシフトすることを確認。
尚、アナログ・コンディションの実測は、以下の通りだった。
1Vp-p入力→ 1stアンプ(G≒3倍)出力=
反転3Vp-p(センタ≒2.5V)→ 2ndLPF出力= 3Vp-p(DC4Vピーク)
また多重帰還型LPF部の、F特の実測もしてみた。以下の写真にあるように、Fc≒300Hzで、1kHz以降は、-18dB
程度で下げ止まりになる。前にも、dsPIC30Fトレーニング基板の、Fcは異なるが同じ多重帰還型LPFで特性を
見た時と、同じである。どうも多重帰還型LPFの特徴のようだ。
■ 2017.5.5
・PIC16F1938での、ADC動作を検討(このPICでは、初)
今迄、PIC24H、PIC32MXなどの、T3タイマーと連動した、ADC割込みを、このPICでも
やりたいが出来るのか?
後閑さんのHPの記事によると、CCP2(キャプチャ・コンペア/PWMの略)側の、スペシャル・イベント・トリガ
を使うと、一定間隔でアナログ信号を取込んでAD変換できるらしい。
ただ、これを使った場合、AD変換タイミングが適切に行われるか保証されないと、このデバイスのデータシート
には書いてある。
単純に、タイマー割込みの中で、手動スタート→DONEチェック→AD変換値読込みを繰返す方が良いかも。
・プリスケーラ・ポストスケーラとの組合せで、TMRxと、PRxの一致で、割込みが発生する、タイマー2(T2)
を使うことにした。
とりあえず、ADC単体のテストプロとして、T2割込み(周期は、AC50Hzノイズ除去のサンプルF=1.6kHz=0.625mS)
を使って、この中で手動で、AD変換し、10bitの変換値を液晶に表示するだけのプログラムを組んでみる。
AD変換値の表示には、sprintf文を使って、HEX表示するようにした。
結果は、以下の通りである。
<測定データ>
・CUSTOM CDM-10 テスター使用
・Vref= Vcc= 5.21V
・大元の入力を0Vにして、ZEROポテンショを動かし、FULL=5.19V/
≒Vref/2= 2.604V/ ZERO= O.0067V
を、AN12に入力しテストを行った。
・AN12入力: 5.19V→ 表示値: 0x03FB→ 理論値:
0x03FC→ OK
AN12入力: 2.604V→ 表示値: 0x0200→ 理論値:
0x0200→ OK
AN12入力: 0.0067V→ 表示値: 0x002→ 理論値:
0x0001→ OK
・尚、T2周期の実測は、いつものトグルLEDで確認したところ、Fカウンタで、0.798kHz(0.001253mS)
なので、T2周期としては、その半分の、0.625mSとなり、OKである。
■ 2017.5.7
・本番のソフトを考え始める。
このPICでの、割込み処理も、今迄と相違があるようなので、その辺から検討することにした。
今回、割込みは、SWの状態変化割込みと、T2割込み(AC誘導ノイズ除去のための移動加算・平均を含むAD変換処理)
の、2種類を使う。
まず留意しないといけないのは、このPICは、割込みベクターが、1つしかないこと。
なので、割込み関数の記述も、interrupt属性と、適当な関数名(ISRとか)を付け、void関数にする。
そして、関数の中で、割込みフラグ・ビットをチェックして、どの割込みが入ったか判断し、分岐処理(頭で各割込みフラグをクリア)
を行うことになる。
当然、処理する順番が優先順位になる。
また、SW(RBポート)の状態変化割込みだが、このPICでは、IOCと称されている。
これには、以下の、4つの設定が必要。今回の設定例を示します。
@ 内部プルアップの指定
WPUB= 0b00111000; // RB3-5は、内部プルアップに指定
A プルアップ有効化
OPTION_REGbits.nWPUEN = 0; //プルアップ有効化
B IOC有効化
INTCONbits.IOCIE= 1; // IOC有効化
C 検知するエッジ設定
IOCBN= 0b00101000; // RB3:HOLD SW/RB5:READY SW 立下りエッジ検知
・肝心な、AC誘導ノイズ除去のための移動加算・平均処理結果と、実際に液晶に表示させる波形データとの関係
が今一、理解できてないが、何とかソフトは書き上げた。
後は、実際に動かしながら、詰めて行くことにした。
■ 2017.5.8
・デバッグ開始。
現在は、T2割込みの中で、0.625mS周期:移動加算・平均フィルタ処理+2.5mS周期:波形BUFへの格納処理
と、SW読込み処理を行うようにしてある。(あまり時間軸レンジとの関係は考えてない。)
移動加算・平均処理は、関東在住なので、AC誘導ノイズの周期は、50Hz(20mS)で、これを、0.625mS周期
で、32サンプルすると、ノイズ波形の、1サイクル分の、移動加算・平均処理が完了することになる。
ここらの詳細については、このサイトの記事を御覧ください→ 「私設研究所ネオテックラボ」
そして、この処理を行いながら、2.5mS周期毎に、波形バッファに、som値を格納している。
ここらが、理解不足で不安だが、今はこうしている。
T2割込みの中で、AD変換を行い、波形バッファに、192ワード(10bit)格納すると、EOCフラグを立て
このフラグをメインで監視し、立っていたら、座標・波形表示などの画面表示を行う流れだ。
EOCフラグは立つのだが、どういう訳か、メインで行っている、EOCチェックのループを抜けてこない?
■ 2017.5.9
・調べている内に、イージーミスを発見。
TRIG_MODE_SW(RB4)を読込み、AUTO側か判断している、IF文の、Then節の後までRUNしてない。
ハード的に調べたら、
@ RB4のプルアップ(PIC-25pin)は、
AUTO(SW OFF)時→ 5.19V
SINGLE(SW ON)時→ 0.00V
で、プルアップ設定は、OKなことを確認。
A 次に、アナログ/デジタル入力設定の確認
RBポートは、AN12(RB0)以外は、デジタル入力にしないといけないのが、勘違いで、RB4が
アナログ入力で他がデジタル入力の設定になってしまっていた。
以下のように修正して、この件はOKになる。
// ANSELB= 0b00010000; // AN12のみアナログ入力、他は全てデジタルI/Oとする
ANSELB= 0b00000001; // AN12(RB0)のみアナログ入力、他は全てデジタルI/Oとする
・ADテストの時、 ANSELB= 0b00010000; の、RB0(AN12)が、デジタル入力になっていても、
さして問題なく動いていたので、気が付かなかった。
デジタル入力であるべきポートビットが、アナログ入力になっていた場合は動かないので判るのだが。
念のため、この設定に修正して、ADテストの再テストをやってみたが、変換値の違いはなかったので
少しほっとした。
これで、EOCチェックの後まで来て、波形データを表示したが、まともな波形が出てこない。
画面半分が出なかったり、座標がバラケタリする?
ここで、移動加算・平均処理は置いといて、波形データバッファにsum値を格納してたのを、そのまま
Din(AD変換値)を格納して、通常のオシロ動作を確認してみたところ、波形は表示されたが、
あまり考えず、サンプル周期(2.5mS)を決めたせいで、時間軸(今は、250mS/Dのつもり)と
実際の波形周期が合っていない。
■ 2017.5.10
・まず、サンプル周期の、2.5mSは、駄目で、5mS(0.625mS x
8)にする必要があった。
時間軸の、1目盛は、51dot分((250mS/5mS)+1= 51)だからである。
そして、0.625mS周期が元の、T2割込みで、それをカウントし、cnt=
4で、波形バッファへの格納
処理をしていたのも間違いだった。
ここは、cnt= 8(0.625 x 8= 5mS)にしないといけない。
この修正で、時間軸レンジとも合った。
・よくよく考えると、私の勘違いで、250mS/Dでは、心電波形を見るには、拡大し過ぎ。
1周期分も見れない。
やはり最初の実験の時と同じ、500mS/Dにしてみる。(1秒/Dが有っても良いが、今回は見送り)
そうすると、サンプル周期は、10mSになる。
(50Hzに対し、倍のサンプルFになる。ナイキスト周波数ギリギリである。)
これにより、cnt= 8→ 16に変更。
これらの修正で、通常のオシロ動作(AUTO/ 500mS/D)はOKになる。
■ 2017.5.11
・HOLD SWによる、波形ホールド機能が、昨日から上手く行ってない。
IOC割込み動作がおかしい。
1回割込みが入ると、次の割込みがうまく行ってないような動きをする。
HOLD解除が出来ないのだ。
データ・シートを見ると、IOC割込みフラグは、INTCONレジスタの、IOCIFと思ったが、
これは、ハード的にエッジセンスした時にセットされるリードオンリ・ビットで、ソフトウエア上の,書込みが
可能な、IOC割込みフラグは、IOCBFレジスタの、IOCBFxビットであることが判明。
なので今迄、IOC2IF= 0;としてたのは無意味で、IOCBF2= 0;でないと駄目。
この修正で、HOLD→ HOLD解除の、トグル動作になるようになったが、未だ駄目。
300mSの表示更新インターバルの間で、HOLD ONにした場合、直ぐにその波形で止まらず、1回変換後
に波形が止まるが、その波形は途中がおかしくなっている。(データが飛ばされている感じ。)
これはどうも、AD変換中(EOC待ち)に、SWが押されて割込みが入ると、2つの割込みが同時に入る
ことになり、実行中のAD変換は正常に処理されるが、その後に、SWリードの処理(チャッタ―防止でmSオーダー
の遅延が入っている)が余計に入るため次の割込みに影響が出てくるためと思われる。
なので、若干、SWセンスの感度は悪くなるが、AD変換中(EOC待ち)は、SW(IOC)割込みを禁止し、
EOC後、禁止を解除することにした。
これで、波形が途中でおかしくホールドされることはなくなった。
■ 2017.5.12
・基本的なオシロ動作は、HOLD機能を含めて、OKになったので、ACノイズ除去ソフトを試行錯誤する
ことにした。
参考先の上田さんサイトの、この部分のソフト抜粋には、移動加算平均と行っても、FIFOバッファの深さ(nFIFO=
32)
で割る記述が見当たらない? このことが多少、引っかかっていた。
そこでサイトの別の個所の説明を良く読込んでみた。
次の説明文が目に留まった。
「sumに毎回、1/nFIFOを乗じて加算平均値:aveを得る」とある。
毎回の、sum計算後に、ave= sum/nFIFO
が必要と思われる。
結局、移動加算・平均処理は、次のような流れで、処理すれば良いことが解った。
※ 0.625mS周期で、AC誘導ノイズ(50Hz=20mS)をサンプルし、サンプル毎に、ave=
sum/nFIFOを、繰返し、
この処理が32サンプル(50Hzの、1cycle分)完了したら、nFIFO=
0 に戻し循環するようにする。但し、ここで、sum値はクリアしない。
その、ave値を、同じT2割込みの中で、0.625 x 16=
10mS周期で、波形バッファに格納する。
これで、50Hzの、サイン波を入力した時、綺麗に、出力が、0Vになればしめたものだ。
結果、見事、綺麗に、0Vレベルになった。
以下に、FGからの、サイン波入力で、移動加算・平均処理動作の確認をした時の、波形サンプルを示した。
尚、移動加算・平均処理をしないで、10mSサンプル(500mS/D)で、50Hzをサンプルして表示すると、写真のように、
棒状にほぼ周期分並んだ波形が観測される。これが、フィルタリングで、0Vになる。
また、他の周波数での挙動についても興味深い。
50Hz以下の周波数(1〜20Hz)に対しては、移動加算・平均処理の影響は殆どない。、
サンプル周期が、10mSと遅いので、50Hz以上では、ナイキスト周波数以下になり、正しい波形を再現でき
なくなり結果、レベルも減衰してくる。
しかし、実際に表示された心電波形を見ると、R波前後の波形(P,Q,S,T波)も観測出来ているので
これで妥協した。心電計のF帯域としては、1〜100Hz程度で十分のようだ。
・実際に、以前作った心電計アンプと組合せ、プローブを人体にセットして、心電波形を確認してみた。
今度は、綺麗な、心電波形が表示された。(トリガレベルは、約820(4V)固定とした)
割と簡単な、ソフト演算だけで、見事、ACノイズが消えた。
・シングル・トリガ・モードも、OKを確認。
・最後に、この制御・表示ユニットの、5V消費電流を実測してみた。
≒30mAほどだった。
---<ここから、追試:「ソフト更新:V1a」の記事>-------------------------------------
■ 2017.5.17
・1S/D(1秒/div)を追加してみる。
ただこうすると、20mSのサンプル周期になるので、波形再現度は下がるが、R波が、4つ見えれば
良しとする。
まあ、カラーQVGA液晶にして、表示解像度を上げれば、サンプル周期も速くできるのだが、
今回は、電池駆動を前提に省エネ思考としているので、断念した。
V1aとしてプロジェクトを組み実験を進めることにした。
レンジ切替は、切替えSWは増設しないで、P_ON時の、READY
SWの状態で分岐処理する方法を
取った。
切替えは、基本のノイズキャンセル用サンプル周期:0.625mSに対し、500mS/Dだったら、
x16= 10mSのサンプル周期にし、1S/Dだったら、x32= 20mSのサンプル周期にするだけである。
・以下に、1S/D(サンプル周期=20mS)に於ける、各周波数入力での、出力波形を示した。
尚、移動加算・平均処理をしないで、普通にオシロとして動かした場合の、50Hz入力に対する
応答は、サンプル周期=
信号入力周期なので、サンプル定義の条件から外れ、いわゆる偽の波形
が表示される。(たぶん、N倍周期の遅いサイン波になっている。)
これに、移動加算・平均処理を加えると、見事、0レベルになっていることが判ると思う。
・実際に、心電アンプ・ユニとと組合せ、電極を人体にセットして、観測した心電波形(1S/D)の例を
冒頭の写真と同じだが以下に示した。
これでも、未だ心電波形の特徴は十分、観測出来ているようだ。
<回路図>
・こちらから、どうぞ→ 「心電計制御部実験回路」
<最終ソース及びヘッダファイル>
・こちらから、どうぞ→ 「PIC16F_ECG_Scope.c」 (V1相当)
「PIC16F_ECG_Scope_V1a.c」 (※ 1705017
ソフト更新:1S/D追加版)
/// GLCDライブラリ
glcd_PIC16F_lib.c
glcd_PIC16F_lib.h
///
アスキーフォント
font.h
← 実験テーマ1に戻る TOP PAGEに戻る 実験テーマ92へ →