2016-07-29 17:00 | カテゴリ:PIC応用回路
気候センサーやLCD表示器をi2cで通信するプロジェクトとして、最終的には市販の工作時計キットに組み込みました。

時刻合わせの為に、スイッチ(時間のカウントアップと分のカウントアップを兼ねたスイッチ:黄色)と時報と共に時分秒を合わせるボタン(黒)を取り付けて、その部分のソフトを組み入れました。
長期間使用して、秒がずれてきた場合でも、ワンタッチで修正できます。

SW.jpg

続きはこちらで、、、



完成後に、リビングのTVの横に置いて、使用しています。



パラメータの表示を切り替える際の一瞬の消灯は、取り除きました。(目がちかちかするので)
10秒毎に表示を切り替えています。
0-4秒は時分を表示、5-6秒は気温、7-8秒は湿度、9-10秒は気圧です。
家内曰く、「時間を知るのに待たなければならない!」という問題もありそうですが、当面はこれで行こうかと思います。



さて、完成したところで、一つ今回苦労した点をご紹介して、皆様のご参考になればと、、、、



----------
 時計を考える
----------

以前、PICでアセンブラを使用してデジタル時計を作りました。

高精度なクリスタル発信器を使用し組み上げて、車で使用していました。
誤差はほとんど気になりません。
今回もデジタル時計を「XC8」で組んでみようと思いました。

アセンブラと違って、C言語では簡単にカウントアップしていけば問題ないプログラムです。
しかし、ちょっと注意しなければならない点があります。
それは、いかに正確に秒数をカウントするかという事です。

PICには、いくつかの内蔵タイマーが備わっています。

PIC.png

よって適当な発振周波数のクリスタルを接続して、プリスケーラとタイマーカウントで、1秒、あるいは、1msecなどを作ればよいわけです。
しかし、精度を求めていくと、タイマー割り込みのレジスタに所定のカウント値を書き込むというちょっとした動作(0.数マイクロ秒)でも、積算されて計時の誤差になってしまいます。

例えば、TMR0で320マイクロ秒毎に割り込みを発生させて、その都度、レジスターにカウント値をセットする命令(ロードとストアに各4クロック、計8クロック(0.05マイクロ秒x8=0.4マイクロ秒)で考えると、1秒で、1.25ミリ秒の誤差になって、実用にはなりません。

つまり、内蔵タイマーは、8ビット、あるいは16ビットタイマーにかかわらず、値を毎回プリセットしてカウントUPさせるのではなく、フリーランで走らせて、カウンターがオーバーフローして発生する割り込みを使用しなければならないという事です。
また、計時のプログラム部分は、割り込みの周期の中でちゃんと終了させるように、処理時間を考えて組まねばなりません。
でないと、処理が遅れて、計時の誤差が積算されて、計時の誤差につながります。

では、どうやればこれらの条件を満たせるのか?見ていきます。

まず、PICの16F87Xの内蔵タイマーの動作を確認します。
これは、各タイマーによって動作がどの様に異なるのかという事を、自分なりにまとめたものです。

タイマー割り込み図

TMR0は、1/256のプリスケーラと256カウントのタイマーから成り立っています。
クリスタルの周波数を12.8MHzと仮定して、命令実行時間は、周波数の4クロック分です。
プリスケーラを1/4に、タイマーカウントをフル256で計算すると
1÷12.8×4(4クロック)×4(プリスケーラ)×256=320マイクロ秒
これを、3125回繰り返すと、1秒になります。

タイマーカウントをフリーラン(256カウント)で使用する条件では、これくらいしかなさそうです。


TMR1は、TMR0と似ていますが、タイマーカウントが16ビット(65536カウント)になる代わりに、プリスケーラが少なくなります。
しかし、16ビットTMR1レジスターをフリーランで使用すると、1秒カウントを得ることができません。

TMR2には、PWMに使用している「比較器」を使用する方法があります。
TMR2が所定の数字に等しくなると、一致パルスが出て、カウンターが自動でリセットされます。
また、このリセットされた回数によって、割り込み信号も出されます。
これらの一連の動作は、ハードでなされますので、PICの時間遅れには影響ありません。
例えば、

1÷12.8×4×16×(250)×256×16=20msec

これを50回カウントすれば1秒になります。
ここで、(250)は、PR2レジスタに設定して、TMR2レジスタのカウント値がこの値と等しくなる回数をカウントして、20msecを作り出します。

PICの計時処理のプログラムが、割り込み処理時間内に収まれば。上記の、TMR0の方法か、TMR2の方法かいづれかで実現できそうです。

PICの命令実行時間は、1命令で、4クロックサイクル分です。
しかし、アセンブラなら何とか計算できますが、XC8のコンパイル前では、見当もつきません。
そこで、MPLABXのXC8コンパイラ内に備わっている、「ストップウォッチ」機能で、割り込み処理などにどれくらいの時間がかかっているのか調べてみました。

まず、TMR0のタイマー割り込み処理部分の検証です。
プログラムはこんな感じです。

Timer0.jpg

このタイマー処理プログラムの実行時間は、11.25マイクロ秒でした。

TMR0_time.jpg

また、タイマー割り込みが発生する時間間隔は、320マイクロ秒毎でした。

TMR0_Freq.jpg

次に、TMR1ですが、先にも述べましたように、TMR1のカウンターをフリーカウントアップで使用することを前提にすると、ちょうど1秒をカウントする、プリスケーラ、ポストスケーラの組み合わせが見つかりません。
という事は、TMR1は、使用できないという事になります。

TMR2は、PWMの為に比較回路を備えています。
カウント値が目的の値になると、パルスが出て、カウントが(ハードで)リセットされます。
このリセットされた回数をカウントすれば目的の時間を計測できます。
TMR2の割り込み処理部分のプログラムは、こちらです。

TMR2001.jpg

このタイマー処理プログラムの実行時間は、12.5マイクロ秒でした。

TMR2-1.jpg

また、タイマー割り込みが発生する時間間隔は、20ミリ秒毎でした。

TMR2_2.jpg

テストの結果、上記の二方法ならば、計時可能と判断されます。
今回は、TMR2を使用しています。

実は、割り込み処理の頻度が多いと、メインプログラムの進行に影響が出そうなのと、i2c通信の間に、割込みが入った時の処理が未確認(たぶんOKと思ったのですが)だったので、そうしました。
事実、最初にTMR0で動作確認していた際に、原因不明で何度かプログラムが止まったことがありました。

というわけで、何かのご参考になれば幸いです。


次は、何をするか??
検討します。



管理者のみに表示する