2015.11.5
前へ
次へ
ホームページトップへ戻る

新製品の紹介(プチ連載です)
周波数カウンタ組立キット

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
たまにはちょいと息抜きで小品も作ってみたいものです。
簡単にチョイチョイと…。
でも、なかなかそうは簡単にはいかなくて、いつものごとく回を重ねてしまうことになるのかも…。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜


[第45回]


●計算が合いません?

[第43回]のプログラムの説明のところで、カウントデータの表示は65秒ごとに更新する、と書きました。
プログラムを書いたときにはそのつもりだったのです。
ところが実際に動作を確認してみると、それよりも長いのですよね。
まさか気のせいかと思って計ってみましたら、80秒ほどで更新しています。
え?
狐につままれたとはまさにこのことです。
なぜだ?

プログラムリストを再確認してみましたが、そんなに長くかかるわけはありません。
2ms×8×4096ですから65536ms。
何回計算してみても80秒なんてことにはなりません。
2msのサブルーチンに間違いは?と思ってそれも確認してみたのですが、どこにも間違いはありません。
むむ。
面妖な…。
さては、妖怪のいたずらか?

んなわけはないのですよね。
やっと思い当たりました。

そうだ。
割込みのせいだったんだ。
74HC590からキャリーが出たときに割込みプログラムが実行されます。
その割込みプログラムの実行時間を計算に入れていませんでした。
しかし。
割込みプログラムに15秒も余分にかかるのか?

ちょいと疑問に感じたのであらためて計算をしてみました。
すると意外にも割込みプログラムの実行にかなりの時間がかかってしまうことがわかりました。

割り込みが発生するのは入力パルスを74HC590が256カウントしたとき毎です。
今回の入力パルスは12.8MHzですから、その256カウントの時間は1/50000秒(20μs)です。
なんと20μs毎に割込みプログラムが実行されてしまいます。
これは思ってもみなかった頻度です。

それでは割込みプログラムの実行時間はどれほどでしょうか。
これは命令のクロックを数えることで計算できます。
これができるのがアセンブラの強みです。
PICの命令はほとんど1クロックで実行されます。
ただしCALL、GOTO、RETFIEなどは2クロックかかります。
また条件付分岐命令BITFSSなどは条件が成立したときは2クロック、不成立なら1クロックになります。
参考までに割込みプログラム(INT)の命令のクロック数はプログラムリストに書き込んであります。
割込みプログラム自体は14クロックですが、割込みが受け付けられる時点で2クロック余分にかかります(下のタイミングチャートのDummy Cycle)。


[出典]Microchip社 PIC16F883 Data Sheet

ですのでそれを加算するとトータルでは16クロックになります。

うっかりしていました。
上で引用したData Sheetを見ていて気が付きました。
実行クロックの計算に落ちがありました。
割り込みが受け付けられるとアドレス0004の命令が実行されます。
0004には割込みプログラムINTへのGOTO命令が書いてあります。
このGOTOのクロックを加算するのを忘れていました。
その分の2クロックを加算すると18クロックになります。

CPUクロックが20MHzのとき、1命令クロックはその1/4の0.2μsです。
すると割込みプログラムの実行時間は0.2×18=3.6μsになります。
この実行時間そのものはわずかな時間ですが、それが20μsごとに実行されるとなると、無視できない時間になります。
割込みがなければ20μsで実行されていたものが、割込みが入ると23.6μsかかってしまいます。
18%余計に時間がかかることになります。

そこで65.5×1.18=77.29と計算しました(ここが考え違いでした)。
うーん、少しだけどなんだか短いような?
80秒のはずなのに、2.7秒短い?
なぜなのか?
どこがおかしいのか?
全く謎でありました。

たかが2.7秒なのですけれど、とにかくアセンブラ(マシン語)は1クロックまで正確に計算できてしまうだけに、気になってしまいます。
どんなに雑に計算したってそんなに狂ってしまうことはちょっと考えられません。
さては80秒というのがいい加減なのか?
で、それもストップウォッチで計ってみたのですが、ほとんど80秒ジャストという値に間違いありませんでした。

ひょっとすると割り込みが無い場合の65.5秒というのが間違っていて、7セグメント表示ルーチンなどで時間が余計にかかっているのかもしれないとも考えました(そんなにかかるはずはないのですけれどねえ)。
ただ、この時点ではまだ117の時報を利用した測定を継続中でしたので、割込みを停止させるわけにはいきませんでした。
したがってここから先に進むこともできず、何回もプログラムリストを見直してクロック数を計算してみては、ため息をつくばかりという非常に精神衛生上よろしくない時間を過ごすことになりました。

このままではどうにも落ち着きませんので、こればっかりの目的でもなかったのですけれど、我慢できずに[第42回]に書きましたように、VM39S5Gをもう1個購入してしまいました。
現在測定に使用中の周波数カウンタのほかにも試作用の周波数カウンタがありますので、それと新しく購入したVM39S5Gを使って、65.5秒VS80秒問題について解明を試みようとした、ちょうどそのとき。

[第42回]に書きましたように、なんと、原因不明なのですが突然カウントデータが狂ってしまい、測定を打ち切らざるを得なくなってしまいました。
こんなくらいなら、VM39S5Gを追加購入するのをもう少し待っていればよかったのです。
9日間もの間なにごともなく連続でカウントを続けておりましたのに、よりによってこのタイミングですものねえ。

まるで漫画です。
ええ、ええ。
わかっておりますよ。
毎度のことなのですから、魔物か妖怪のしわざなのですよ。

ま、今更文句を言ったってはじまりませんから、あきらめて割り込みが無いときには本当に65.5秒なのかどうかを計ってみることにしました。
しかし割込みが無いときは表示が変わりませんから65.5秒を計ることはできません。
そこで65.5秒のもととなる2msを計ってみることにしました。
具体的には7セグメントLEDのダイナミックドライブのために2msごとに出力される表示桁指定信号の周波数を測って、そこから実行時間を逆算してみることにしました。
ダイナミックドライブのための信号はPIC16F883のRA0〜RA2から出力されて74LS145のpin15〜pin13に入力されます。
そのpin15を測定しました。

こちらは割込み無しの場合の周波数です。
248Hzです。


こちらは12.8MHz測定中(割込み有り)の周波数です。
203Hzです。


PIC16F883のRA0出力はHが2msでLが2msのパルス出力ですから、上記の測定周波数は倍の周期4msのパルスを測定したことになります。
割込み無しの場合は1000/248/2=2.016msです。
2.016×8×4096=66060ms
計算した値にほぼ一致しますから、ここは問題はないようです。

さて、割込み有りの場合は1000/203/2=2.463msです。
2.463×8×4096=80707ms
うーん。
やっぱり80秒ですねえ。

すると、上で求めた65.5×1.18=77.29という計算が間違っているのかも。
あ。
66×1.18=77.88かも。
それでもちょっと違っているようですねえ。

どうにも納得がいかなかったのでありますが。
一晩寝て翌朝になりましたら、突然ひらめいてしまいました。
ああ、そういうことだったか。
やっぱり計算が違っておりました。
おばかでありました。

時間がなくなってしまいました。
次回に続きます。

[2015.11.6追記]
割込みサブルーチンのクロックの計算にミスがありました。
正しい値に直したため関係する部分も書き改めました。
詳細については次回[第46回]をご参照ください。

周波数カウンタ組立キット[第45回]
2015.11.5upload
2015.11.6追記

前へ
次へ
ホームページトップへ戻る