標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第186回]

●PIC16F88の内部発振クロックの確認

前回は、ハイパーターミナルを使って、RS232Cでテストプログラムを「つくるCPU」試作基板に送信したところ、エラーが発生してしまった、というお話をしました。

エラーの原因について、あれこれ考えたところ、RS232C受信を担当している、PIC16F88の発振クロックがおかしいのでは、という疑いが浮上してきました。
PIC16F88は、外付けの水晶によるクロック発振をしなくても、設定により、内部発振回路によって動作させることができます。
水晶発振なら、かなりの精度が期待できますが、内部発振回路がいったいどの程度のものなのか、一旦疑いだすと、これはかなり怪しいような気になってきます。
腕を組んで、あれこれ考えていても、始まりません。
とにかく行動してみることです。

PIC16F88が一体どの程度の精度で動作しているのか、確認してみることにしました。

●最終的なPIC16F88付近の回路図です

どうしたら、PIC16F88の動作クロックを確認することができるでしょうか?
前回も少し説明した、PICからのエラー出力信号が利用できそうです。
PIC16F88とCPUとの間のデータの受け渡しをする回路は、[第129回]にあります。
このときの回路では、PIC16F88に未使用端子が1つ残っていました。
RB3(pin9)です。
この端子は、同じ回の下の方で、CPUからPICにデータを送るための、74HC373のOEの制御に使う予定だ、と書きました。
しかし、その後に、前回書きましたように、エラー発生時のインジケータとして利用するように変更しました。
さらに、エラー発生時にはLED表示を行うだけではなく、CPUにも知らせるようにしておいた方がよい、と考えました。
そこで、最終的に、下の回路図のように回路を変更しました。



PIC16F88のRB3(pin9)からの出力は、I/Oアドレス98のビット2入力につながっています。

●今度はPICのお勉強です

じつはこの端子はエラー出力のほかに、もうひとつ別の働きをします。
PICを今回のような目的で使うと、232C信号が入ってこないときには、スタンバイ状態なので、本当に動作するのか、それとも起動に失敗してこけているのか、あるいは、そもそもちゃんとプログラムが書き込まれているのか、全くわかりません。
まあ、それでも、232Cの送信を受けて、ちゃんとデータをCPUに渡してくれればよいのですけれど、うんともすんとも言ってくれなかったりすると、途端に不安になってしまいます。

そこで、リセット時に特定の制御線をアクティブにしたら、ちゃんと生きているしるしとして、LEDを点滅させるようにプログラムしてあるのです。
点滅周期は約0.5秒です。0.25秒点灯して0.25秒消灯する、の繰り返しです。

これを利用すれば、PIC16F88のクロックがどの程度正確なのかを調べることができそうです。
最初は、ストップウォッチで計りながら、LEDの点滅回数をカウントしようと思いました、が。
もっといい方法があるじゃ、ありませんか。
ほら、LEDの出力は、I/Oアドレス98のビット2の入力として、CPUでカウントすることができます!
おお、それだ、それだ。それがいい。

●まずは、PIC16F88のプログラムです

リセットからスタートして、LED表示の点滅を繰り返すところのプログラムです。

サブルーチンtm250msをCALLしています。
そこで、tm250msです。


簡単に説明をします。
btfsc portb,1 は、portbのbit1がc(クリア)されていたら、次の命令をスキップせよ、という命令です。
btfscは、Bit Test f,Skip if Clearの意味からつけられたニーモニックです。
PICでは、メモリ、I/Oポートを示すのに、”f”という記号を使います。
”,”のうしろの数はビット位置を示します。
リセット後にI/OポートPORTBのbit1をチェックして、1ならば232CREADルーチンへ行きます(goto rdck)。0ならばgoto rdckをスキップします(読み飛ばします)。

次はcall tm250ms です。250msecタイマールーチンをCALLします。
CALLは8080のニーモニックと同じですから、わかりますよね。

movlw 08 は、wレジスタに08を入れる命令です。8080なら、MVI A,08に相当します。
movlwは、Move Literal to Wの意味からつけられたニーモニックです。
PICには、ワークレジスタは1つしかありません。”w”で示します。

xorwf portb,f は、wレジスタとPORTBとのXORを計算して、その結果をPORTBに出力する命令です。
xorwfはExclusiveOR W with fの意味からつけられたニーモニックです。
”,”のうしろの”f”は、結果をf(メモリまたはI/O)に渡す、という意味です。
8080では演算の結果はAレジスタにしか入れられませんが、PICでは第2パラメタで”f”を指定することで、結果をメモリまたはI/Oに渡すことができます。
8080と同じようにwレジスタに結果を渡すには、第2パラメタで”w”を指定します。

wレジスタには08が入っていますから、PORTBのビット3の出力が反転します(XORは特定のビットを反転させる目的で使われます)。

上のプログラムリストで、各命令の後ろに書いてある数字は命令の実行クロック数です。
発振クロックが4MHzのとき、1命令クロックは1μsです。

次は、タイマールーチンtm250msの説明です。
movwf cntr2 はwレジスタの値(0FA、十進では250)を変数cntr2に入れる、という命令です。
Move W to fの意味からつけられたニーモニックです。これはわかりますよね。

call tm1msで、tm1ms(1msecタイマールーチン)をCALLします。

decfsz cntr2,f は、cntr2を−1して、結果がz(ゼロ)ならば、次の命令をスキップせよ、という命令です。
結果がゼロでないときは、goto tm250ms_2 が実行されます。
decfszはDecrement f,Skip if Zeroの意味からつけられたニーモニックです。

cntr2を250回ダウンカウントしたあと、returnします。この間1msecタイマールーチンを250回CALLしますから、このルーチンは250msecのタイマールーチンになります。

tm1msの説明です。
ここでも、cntr1にFA(250)がセットされています(さきほどのcntr2とは無関係です。たまたま同じ値をセットすることになりました)。
clrwdtはウォッチドッグタイマーをクリアする命令です。
Clear Watchdog Timerの意味からつけられたニーモニックです。

ここで実行クロックを計算してみます。
このルーチンは、clrwdtとdecfsz cntr1,fとgoto tm1_2を250回繰り返します。
decfszのクロック数は、Z(ゼロ)でないときは1、ゼロになったときだけ2です。
そこで、このサブルーチン全体の総クロック数を計算すると、こうなります。
1+1+(1+1+2)×250−1+2=1003
1命令クロックが1μsですから、このサブルーチンの実行時間は1003μsになります。
上の式の−1は、結果がゼロになったときだけ、decfszのクロックが2になる代わりに、gotoがスキップされることで生じる差の調整です。

次にtm250msルーチンの正確な実行時間を計算してみます。
call tm1ms は、call命令で2クロックかかります。
そこで、さきほどのtm1msルーチンと同じように、call命令の中身の1003μs以外の部分の実行クロック数をまず求めてみます。
1+1+(2+1+2)×250−1+2=1253
1253μsです。ここに1003μs×250を加えると、tm250msルーチンの実行時間が求まります。
1253+1003×250=252003μsになります。

さて、最後の仕上げです。
最初のtestの部分です。
テストパルスを連続出力するように、CPUからPICのPORTBのbit1への出力は、ずっと0にしたままにします。
ですから、ここのbtfscは必ず次のgoto rdckをスキップします。このときのbtfscのクロック数は2になります。
そのあと、call、movlw、xorwf、gotoの順に実行されて、またtestに戻ります。
このように1回実行される毎に、PORTBのbit3出力が反転します。
この部分のクロック数を計算します。
2+2+1+1+2=8
実行時間は8μsです。このときtm250msが1回CALLされますから、PORTBのbit3出力が反転するのにかかる時間は、
8+252003=252011μsになります。

●CPUのカウントルーチンです

やっと、いつもの8080プログラムに戻ってきました。
PIC16F88のPORTBbit3の出力は、I/Oアドレス98のビット2に入力されます。
そこで、このビット2入力が反転する毎に、BCレジスタをインクリメントするようなプログラムを実行させると、BCレジスタには、その反転の回数が表示されることになります。



さっそくストップウォッチをスタートさせて、プログラムを実行させてみました。
え?
8080のプログラムの実行時間は計算しなくてよいのか、ですか?
今回は、8080の命令の実行時間は関係ありません。
なぜでしょう?
それは、皆さんで考えてみてください。

●カウント中の写真です



Bレジスタは20、CレジスタはBFを表示しています。
20BFを十進数に直すと、8379になります。
ストップウォッチは35’00”です。秒に直すと、2100秒です。
では、計算してみましょう。
BCレジスタが+1されるのにかかる時間は、PICのプログラムの計算から、0.252秒です。
0.252×8379=2111.5秒

うーん。少し、ストップウォッチと差がありますね。
どのくらいの差でしょうか?
11.5/2100=0.0055
わずか0.55%です。

もう一枚写真を撮りましたのでそちらも計算してみましょう。



Bレジスタは2E、CレジスタはC1を表示しています。
2EC1を十進数に直すと、11969になります。
ストップウォッチは50’00”です。秒に直すと、3000秒です。
では、計算してみましょう。
0.252×11969=3016.2秒

どのくらいの差でしょうか?
16.2/3000=0.0054
さきほどとほぼ同じ結果になりました。

水晶発振に比べれば精度は落ちるというものの、実用上は問題ない程度の精度はあります。
なかなか立派なもんじゃありませんか。

うわあ。感心してる場合ではありませんでした。
そうすると、こいつもシロになってしまったじゃありませんか。
じゃあ、一体ホンボシはどこに?
2009.3.17upload
2009.3.18PICプログラムのところでPIC命令の簡単な説明を追加

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