● 実験テーマ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へ →