PICのプログラミング再開:12F1822
久々にPICのプログラミングに戻ってきました。
4桁LEDクロックのSTCの8051互換のプログラムを見ていて、勉強になったところがあったので、PICのプログラムを改善しようと思ったからです。
プログラムをする対象のPICを使ったモノは、以前手掛けた5灯LEDランプです。実は、以前プログラムしたものは、あまり期待した動作をしなかったので、不満がありました。そのうち、電池切れになってしまい、かなりの間、電池交換もせず放置状態で、使っていない状態になっていました。
何が期待した動作になっていないというと、せっかくの人感センサの反応が悪く、点灯してほしい時に、点灯しないという状況だったのです。
原因は、おそらくセンサのデータ検出の回路、つまり適当に仕上げたアンプの方でもあるかもしれませんが、プログラムでカバーできるはずだと思っていながら、うまくできませんでした。ただ、アナログ信号のデータがどのようになっているか把握ができていなかったので、想像でプログラムしていて、うまく対応できない状態だったのだろうと思います。しかし解決に至らず、そのまま現在に至ってしまったというわけです。
適当に仕上げたというアンプ部ですが、参考回路をもとに、センサからの出力を手持ちのLM358を使った回路で増幅していますが、その出力がどのようになっているのか知るすべがないのが現状なのです。
信号は、アナログで、かつAC的に動いているので、手持ちの機器では把握しにくいというか、まったくわからない状態なのです。手持ちのマルチメータではDCレベルならわかるものの、AC信号はよくわからないですし。 PICでAD変換した数値を取得するも、ほんのわずかな時間の状態しかわからず、かつ解析も面倒で二の足を踏んでいました。いつのデータを取るのかというのも、トリガとなるものを設置できなかった(しなかった)ので、ここぞというデータが取れずじまいという状況だったのでした。
単にPICに入力している焦電センサからの出力がどんな波形になっているのか知りたいだけだったのですけどね。普通なら、そのチェックをオシロで行えばよいのですが、オシロは持っていないし。。。という状況です。
じゃあ、オシロがあったらいいのだなと思い、最近オシロも安くなっているという話もあったように思うので、どんな感じかなと色々物色しましたが、結局買えていない状態のまま今に至っています。調べてみると、数万円も出すと、そこそこのデジタルオシロは買えるようなのですが、そんなに使用頻度も高くないと思われるものにそこまで出すのかと決心がつかなかったのです。
でも、ネットでオシロについて調べている時に、2千円ほどの価格のDSO138なるオシロのキットを見つけてしまいました。ここで、脇道に入り込み、迷走しました。
オシロって自作できるんだと思って、色々な方のレポートを読んだりしたのですが、何か面白そう。ただし、それだと、200KHz程度のアナログ帯域しななく、オーディオ用とか。サンプリングレートは、1Mspsなのですがね。まあ、サンプリングの定理で行くと、サイン波を仮定したら、半分の500KHzの信号まで見えることになりますが、波形情報としては、そういう風に見える状態にはなりませんね。 わかる人にはわかってもらえると思う書き方ですいません。詳細な説明は省きます。ここの話がわからない方はサンプリング定理とかで調べてみて下さい。
でも、このキットは、1chしかありません。ホビーとしては良いのかもしれませんが、クロックと信号の関係を見るとか、2ch欲しいと思ったらちょっと残念な感じですね。 安いから我慢できるとは思いますけど。 でもキットということで、非常に興味があり、しばらく情報収集と調査をしてしまったという状況でした。というわけで、迷走して、時間をつぶした次第。
DSO138の2千円より高額の1万円位になっても良いから、もう少し性能が高いキットがないかな探しましたが、DSO138より性能の良いというようなキットはないようでした。残念。
というわけで、キットの購入はあきらめました。
そうすると、やっぱりちゃんとしたオシロでないとダメみたいだということになります。普通のオシロということになりますが、PICの工作の場合、8Mhzくらいのクロック動作させているので、100Mspsくらいの能力があると嬉しいかなと思いました。そして、2chあれば、ベスト。それだと、やはり数万円のコースになります。数万円も出すことも躊躇してしまっている状況が続いているわけです。
そんな状況で、心のもやもやが晴れないまま、先の4桁デジタルクロックを見つけて、STCのプログラミングという横道にさらに逸れてしまったわけでした。
そんなこんなありましたが、先日4桁LEDクロックのプログラム改造も完了し、GitHubを通して貢献もできたということで、一段落したというのが現在です。
PICのプログラム再開
前置きが長くなりましたが、時間もできたので、PICのプログラムの改善を開始します。
オシロは未だに手元にはありませんが、人様のプログラムから学んだことをPICのプログラムに生かすことを目論んでいます。稼働を中止していた5灯LEDランプがちゃんと使えるようになるとよいのですが。。。
まずは、久々ですが、MPLAB Xを起動からです。 かなり時間が空いてしまっていて、色々忘れています。MPLAB X自体もバージョンアップが必要でした。 昔のプログラムのことはすっかり忘れてしまっているので、どうせプログラムを見直さないと、理解できないならと、新規のプロジェクトを作るところから開始しました。 そして、昔のプログラムから必要な部分を必要な時に取込む方針で対応することにしました。
回路は、以前と変わっていません。後述する対策のため、パスコンを追加したくらいの違いです。
新規プロジェクトは、New Project→Standalone Project [Next>] Family=Mid-Range 8-bit MCUs (PIC 10/12/16/MCP), Device=PIC 12F1822 [Next>] そのまま [Next>] PICkit3 (持っていませんが、PICkit2だと赤なので) [Next>] XC8 (v1.45) (v 2.00が出ていますが、何か問題あったので) [Next>] 適当なプロジェクト名を設定、Encoding=Shift JIS [Finish]で作成しました。
この時点では、まだ、Source Fileも作られていません。
次に、プログラムの作成を開始しますが、PICの面倒な様々な設定を支援してもらえるMCCは、最大限利用します。 ゆえに、プログラムの作成の最初は、MCCを使っての設定からになります。 MCCもバージョンアップしているみたいで、以前より使い勝手が良い感じです。
と書き始めましたが、面倒なのでやめます。 まずは、以前プログラムと同等の状態に戻すことをリハビリを兼ねて作っただけなので、あまり参考にならないからです。 手抜きですいません。後で、最終形に関してレポートしたいと思います。
デバッグ
プログラムができたら、動作確認です。PICkit2と接続して、そこから電源供給して動作確認した所、以前と同様に動作しました。ここまでは、ほぼ以前と同様ですね。
でも、電池でのスタンドアローン動作させると、なぜか同じ挙動になりません。こういう状態だとデバッグしにくいですね。今回は頑張って解決を図りたいと思います。
おかしな動作というのは、LED消灯後、すぐに点灯するという状態になってしまうとか、反応が悪いとかです。デバッグのため点灯時間は、5秒に設定しています。しかし、PICkit2と接続した状態だとそのような動作にはなりません。
色々考えていたら、電源電圧の問題かもしれないかも思いつきました。 LEDが消灯した後に動作がおかしくなったのは、LED点灯時それなりに大きな電流を流している状態から、消灯時のほとんど動作電流を必要としない状態に戻るときに、電源電圧が局所的に変動してしまうことが原因だろうと思ったわけです。
部品点数を削減するためというか、なくても大丈夫だろうと、5灯LEDの回路にはパスコンはつけていませんでしたし。とりあえず、外付けでパスコン(0.01uF)付けてみたら、少し症状が和らぎました。そこで、さらに電解コンデンサ47uFを追加しましたが、あまり改善は見られないという状況で、不良原因としての推定は、当たらずとも遠からずということのようです。というわけで、上記の回路図には、0.1uFを追加してある訳です。
解析を続けます。ADCの参照電圧としてVDDを使っているので、VDDが変動すると、変換の結果が期待していないものになって、おかしく見える動作になっているはずではないかという仮説を立てました。
回路的には、焦電センサの出力をアンプで増幅した信号をPICに入力して、それをAD変換しているわけです。 説明するまでもないかもしれませんが、PIC12F1822のAD変換は、基準電圧を最大にして、0~基準電圧までを10ビットすなわち1024段階でデジタル化できます。今回の場合、VDDをADPREFというADCの参照電圧として使っているので、AD変換するセンサの信号を増幅した信号の電圧が変わらなくても、VDDが変化すると、ADCの結果が違ってくるわけです。
LED点灯により、VDD電圧が低下してしまい、その後、LED消灯で、VDDが元の電圧に戻るような動作になっていると想像しています。もし、センサの増幅後の電圧がみかけ上変化しなかったら、VDDが上がることで、ADCの結果は小さい数値になるでしょう。そうしたら、プログラムで設定したレベルを超えて、人を検知したという判定になってしまったのではないかというのが現在の推定です。
そんな中、PICのデータシートを眺めていたら、ADCの参照電圧は、外部のVDDのほかに内部生成の固定電圧FVRを使えることがわかりました。これなら、外部電圧の変動に影響を受けずにAD変換できそうです。と思いましたが、設定できるのは、4V/2V/1Vでの3種類で、かつ、VDD以下の電圧ということです。電池3本で構成されているので、4.5Vからだんだん電圧低下して、3Vくらいにはなると思われるので、4Vの設定で動かせるようにできても、それ以下の電圧では、従来通りVDDを参照電圧としてADCを行うことになるので、あまり良い解決策になりそうもありません。OPアンプは、VDDで動かしているので、2Vmaxというような設定は意味がなさそうですから。しかし、実験して試したのですけど、最終的に、素直にVDDを参照電圧にすることにしました。
やはり、信号がどういう動きになっているか何とか知る方法が必要です。何度も繰り返しますが、オシロがないことは上述しました。 ここで、ふと思いつきました。AD変換した結果をPIC内蔵のEEPROMに書き込んで、後で読み出したらよいかと。
12F1822は、256バイトのEEPROMがあります。たったこれしかないと言ってもよいかもしれないレベルです。そのため、一番最初にやろうと思いながら、あきらめたのです。 単純に10ビットのADCの結果を格納しようとすると、2バイトずつ消費するので、128個分のデータしか保持できません。さらに、特に何も制御せず無限ループを回していたので、AD変換は、その時のループ処理にかかる時間によって、一定の間隔で行われていたわけではなかったのです。そのため、データを取得する場合、時間軸のデータも必要だと思っていました。 例えば、時間データを2バイトで表現したら、1つのデータが4バイトになり、256バイトのメモリでは、たった64個のデータしか取得できないわけです。これだと、波形観察に対して役に立たないと思っていたわけです。
ここで、STCの4桁LEDクロックのプログラムで学んだことを活用するという話になります。このSTCのプログラムでは、無限ループを単純に回しているのではなく、100ms毎にループが回るようにgatingしていました。タイマ割り込みを使って、100ms経過しないと、ループを回さないというようなプログラムになっていました。
つまり、これを応用すると、無限ループを回すPICプログラムでも、ADCを100msごとに実行できるわけです。こんなテクニックは、普通のことなのかもしれませんが、私はようやくそこにたどり着いたというわけです。
こうすると、定期的にデータが取れることになり、時間データはなくても波形が書けるようになります。つまりデータだけ格納することで、2倍のデータが取れるようになります。100ms単位であれば、1データ2バイトで、12.8sとかなり長い時間のデータが取得できます。 こうなると、さらに工夫しようと思いつきます。 どうするかというと、ADCの10ビットのデータをそのまま格納せず、8ビットに切り詰めてしまうというアイデアです。どちらにせよ下位2ビットはノイズとかでゆらゆらしているはずですから、無視しても大して問題になかろうということです。 こうすると、さらに2倍の25.6sという長時間のデータが取れる計算になります。これだと測定に十分な長さです。
なんで今までこんなことを思いつかなかったのかなと思いましたが、思い立ったら吉日、さっそくプログラムしてみました。
256バイトのメモリはありますが、設定情報の格納エリアを確保する都合上、224バイト分をデータ記録エリアとしました。これでも、0.1s毎のサンプリングしたデータが22.4s分取得できます。
トリガとかは面倒なので、エンドレスにデータを取り込み、電源を切る直前までのデータが取れるようにしました。そして、取得してみたデータ224個をグラフ化したのが以下です。
電池3本で、4.6Vの電圧の時に測定したものです。横軸は、秒です。縦軸は、8ビットのデータを4倍にして、ADCの結果相当に戻しています。この波形で、ピコんと飛び出ている時間が、手をかざした時に当たります。それをプログラム的に検知しないといけないわけです。上記の場合だと、7秒付近と、15秒付近で検出したいわけです。
一方、同じ4.6VにPICkit2の電圧を設定して電圧供給して、測定した時のデータが以下となります。
8秒付近と、16秒付近がそれらしく見えますが、電池駆動の時に比べてデータにかなりノイズが乗っていてわかりにくい状態ですね。
どちらの波形も下位2ビットを無視した8ビットのデータですが、それなりなデータになっていることがわかります。ようやく、知りたかった波形が、オシロがなくても取得できたわけです。もちろん、オシロほどの性能があるわけではありません。たったの1ステップ0.1s、つまり10Hzでサンプリングした波形ですからね。
ここではっきりわかったのは、電池と、PICkit2からの電圧供給の2つに、こんなに違いがあることです。それなら、挙動が変わっても致し方ありません。今後、このハードでのデバッグは、電池の電源を使った状態でやらないといけないと思いました。
さて、データが取得できたら、どんなアルゴリズムで判定したらよいか考えるのは、簡単です。私は、Excel上で、色々な条件判定のロジックを考えました。
先ほどの示したデータを使って、判定してみた結果よさげなものが以下となります。
どういう判定をしたかというと、次のようにしました。黄色は、10個のデータを使った移動平均の線です。水色の領域は、移動平均に対してその時のデータが12.5%下回った領域、ピンクの領域は、移動平均に対し12.5%上回った部分を示しています。
同じアルゴリズムで、PICkit2から電圧を供給した場合のデータに適用しても、思ったようには判定できませんでした。
12.5%にしたのは、プログラムしやすいからです。12.5%=1/8で、3ビットシフトで計算できますからね。
これで、安定動作ができると思って、さらにデータを色々と取ってみると、必ずしも思った通りにならないケースも出てきてしまいました。 何ともアナログ信号の取り扱いは、難しいなと思いました。
電池の電圧は、自由にコントロールはできないので、様々な電圧状態の動作を調べられないという欠点がありますね。へたった電池に入れ替えてデータを取ったりしてみると、検出しにくい波形になっていたりしてました。
プログラム上、調整すべきパラメータは、3つですかね。移動平均を取る個数、移動平均からどの位上下したら判定するかと、上下の判定を両方か片方で行うかどうかというところでしょうかね。
何が最適か決めかねたので、今回は、移動平均は、10個分で計算し、計算しやすい12.5%移動平均より上回った時に人を検知したことにし、さらにボタンのチャタリング処理のように、2回以上連続して検知した場合に点灯するようにしました。下回った時にも判定した方が良いのかもしれませんが、ピークから戻るときにも判定されやすいデータだったので、上回った時だけを判定OKとしました。
例えば、以下の波形は、乾電池の電圧が4.4Vの時のものです。500付近で安定している状態から、人を感知した時の波形になります。電池で何も検出していない時は、結構安定しているのが、わかります。この時は、最初に上に振れて、その後下に下がるという波形になっていました。何本もピンクの縦線でしめしたところがありますが、2回連続判定OKとなったのは、最初に大きく振れた時だけでしたので、問題ないだろうと思いました。
また、もし、何度も判定されても、点灯後、30秒は点灯状態が継続するのが今回の動作なので、それが、数秒延びても問題ないだろうとも思いました。
この条件に基づき、再度プログラミング、運用って大袈裟ですが、使用開始しました。
大体良い感じですけど、取り付け位置が悪いのですかね。手をかざさないと反応しない時があります。玄関に置いていますが、このところ暑く、玄関は風通しもない状態なので、非常に暑いところでの動作となっているせいか、人の発する赤外線では反応しにくい状態になっているのかもしれません。
まだ、納得できるできになっているかどうかは、もうしばらく使ってから判断したいと思います。
ここから、今回作成したプログラムを最新のMPLABX+MCCでのプログラミングの例として書き始めようと思いましたが、長くなりそうなので、次回に回します。6/4のリニューアルを迎えれば、長さ制限が大幅に改善されるので、あまり悩まなくても済むかもしれません。
記事は、これから書きます。プログラムもゼロスクラッチで作りながら、記事にしようと思っているので、お楽しみに。そのため、すぐに記事をアップできないかもしれません。
では、また。
この記事へのコメント