現在私のお気に入りマイコン開発環境はST社のSTM32シリーズをEclipseによるリモートデバッグなんですが今回はPIC16F84Aです。
何を今さらPIC16F84Aなのかという程に古くて使いにくいマイコンなんですが、PIC16F84Aは1990年頃に諸事情で入手。
先日、無線の電信用にエレクトリックキーヤーをPIC16F84Aで作ったりしましたがまだ少し残ってるので可能なら何かに使ってしまいたい。
そういえば、このPICマイコンでタイマー割り込みをやった事がありません。
今回はタイマー割り込みを使ってどの程度正確に一定間隔でパルスを出すことが可能なのかの実機確認をやります。
このマイコンの諸設定は設定用のレジスタファイルというI/Oメモリーで行います。
タイマー割り込み設定はレジスタファイル0x0B番と0x81番で行います。
タイマーはレジスタファイル0x01番の数値を1命令サイクル毎に1つ加算していきます。
そしてレジスタファイル0x01番が0xFFから0x00になった瞬間、オーバーフロー割り込みが発生します。
ここで1命令サイクルは4システムクロック。
例えば4MHzのXTALで動作の場合は1命令サイクルは1μsecになります。
ちょっとわかりずらいのがレジスタファイル0x81です。
0x81番へのアクセスは0x03番の5ビット目と6ビット目を使ってバンク1番に切替えてから0x01番にアクセスしたらそこが0x81番です。
添付のプログラムソースの28行目から43行目がタイマー割り込みの設定個所になります。
試しに、レジスタファイル0x01番を完全に無視してタイマー割り込みをやってみます。
用意した回路図はこれです。
タイマー動作はレジスタファイル0x01番が0x00から0xFFを延々繰り返し、1μsec x 256回 = 256μsecに1回 割り込みが発生します。
割り込み処理として、ポートAの0ビット目にHigh--->Lowのパルスを出力させた時の波形がこれです。(電圧1/10プローブで測定)
256μsecの逆数で3906.25Hzのバルスを計測してますので計算通りです。
では、25KHz(40μsec)で割り込ませる為にレジスタファイル0x01番に40命令サイクルに一回の設定をします。
レジスタファイル0x01番が0xFFから0x00になるまで40サイクルにするには256-40=216を設定すれば良い計算なんですが実は割り込みが発生してから割り込みルーチンに入るまでに8命令サイクル必要な様です。
なので8サイクル少ない32サイクルの設定を割り込みルーチンの最初に行います。
こうすることで正確に40サイクルで再割り込みが入ります。
こうやって25KHzを作った出力波形がこれ。(電圧1/10プローブで測定)
きっちり25KHzになってます。
波形を見る限り、パルスのズレもなく綺麗です。
また、マイコン動作中表示としてのLED点滅もさせており、チカチカ点灯しつつパルスが出ています。
もうしばらく動作確認を行い、結果良好ならHF無線機内蔵用マーカーにしてしまおうかなと考えてます。
(マーカーならロジック回路で作れば正確なのに何でマイコンというツッコミは当然あると思ってます)
※
動作ブログラムは整数型C言語です。
興味のある方はここにあるpic_cc-0.4.tar.gzをご参照ください。
今回作ったC言語のソースを下記に張り付けておきますので参考まで。
(C言語の中にアセンブラを混ぜてます)
---------------------------- ここから -----------------------------------
#include "io.c"
#include "stdio.h"
/* 割り込み処理ルーチン・・・・・ タイマ割り込み、ここに到達までに8カウント消費済 */
#asm
interrupt
mov 01h,#224 ;count 40(256-40+8カウント=224) set for 25KHz by4MHz (=1000000/25000)
bcf 0bh,7 ;Disable interrupt
bsf 05h,0 ;pulse out to H
bcf 05h,0 ;pulse out to L
bcf 0bh,2 ;next interrupt ok.....TMR0
bsf 0bh,7 ;Enable interrupt
retfie ;Return interrupt
#endasm
main(){
int i;
/* TMR0 オーバーフロー割り込み設定 */
#asm
mov 0bh,#00100000b ;TIM int set
bcf 0bh,7 ;Disable interrupt
bsf 03h,5 ;bank1
bcf 01h,5 ;TMR0のソースはCLKOUT
bsf 01h,3 ;プリスケーラはWDTに
bsf 01h,0 ;プリスケーラ(001=1:4)
bcf 03h,5 ;bank0
mov 01h,#0 ;count 0 for start!!
#endasm
SetP_A(0xf8); /* Port A Set 0,1,2 :OUT */
SetP_B(0xfe); /* Port B Set 0: OUT 1-7 :IN */
#asm
bsf 0bh,7 ;Enable interrupt
#endasm
/* 無限ループ */
while(1){
#asm
clrwdt ;ウオッチドッグ
bsf 06h,0 ;LED out H
#endasm
for(i=0;i<255;i++){
}
#asm
clrwdt ;ウオッチドッグ
bcf 06h,0 ;LED out L
#endasm
for(i=0;i<255;i++){
}
}
}