PIC−USBIO using BASIC
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
USBインターフェースを内蔵したPICを使ってWindowsパソコンで外部回路を制御するための各種I/O基板の製作記事です。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
[第80回]
●PICUSBIO−03(29)Timer1(11)CAPTUREモード(2)カウント値の誤差?
前回の終わりのところに書きましたようにCAPTUREモードは入力パルスの周期をカウントするモードのようです。
するとその機能をテストするためにはCCP1端子に正確なパルスを入れる必要があります。
そこで思いついたのがTimer0の割り込みを利用した方形波出力です([第69回]参照)。
PICUSBIO−03を2台使って#30のボードから方形波を出力してそれを#31で受けてCAPTUREモードでカウントすればよいはずです。
下の画像はそのように考えて作ったテストプログラムです。
左側のコマンドプロンプトではPICUSBIO−03 #30をUSB接続し、PICUSBIO用BASICインタプリタが起動しています。
ロードしたプログラムは[第69回]で作ったプログラムです。
20行でT0CONに$85を設定しています。
プリスケーラは1:64です。
T0CONについては[第64回]を参照してください。
30行で割り込みを許可しています。
T0CONの設定でTimer0は16ビットカウンタとして働きますから65536カウントごとにオーバーフロー割り込みが発生します。
その間隔を計算してみます。
システムクロック(48MHz)の1/4クロックをプリスケーラで1:64にしますからTimer0の入力クロックは
12000(KHz)/64=187.5KHzです。
187500/65536=2.861(Hz)のサイクルで割り込みが発生します。
その逆数1/2.861=0.3495(Sec)が割り込みの発生する間隔です。
割り込みごとに反転するパルスがRC4から出力されます([第69回]参照)。
349.5msecごとに反転する出力ですからそのパルスの1周期は699msecです。
このパルスをPICUSBIO−03 #31のCCP1端子に入力してCAPTUREモードでカウントします。
上の画面の右側のコマンドプロンプトではPICUSBIO−03 #31をUSB接続し、PICUSBIO用BASICインタプリタが起動しています。
プログラムの説明です。
10行でTimer1の設定をしています。
T1CONレジスタに$81を設定しています。
T1CONについては[第70回]を参照してください。
プリスケーラは使わずシステムクロックの1/4(12MHz)をカウントします。
20行でT3CONに0を設定しています。
CAPTUREモードのTimerとしてTimer1を使う設定です([第78回]参照)。
30行でCCP1CONレジスタに$04を設定しています。
CCP1端子から入力される信号の下がりエッジでCCP1IFフラグがセットされます。
CCP1CONについては[第78回]を参照してください。
40行でCCP1IFフラグをクリアしています。
CCP1IFはPIR1レジスタのビット2です。
PIR1レジスタについては[第73回]を参照してください。
本来はPIR1レジスタのビット2のみをクリアすべきところですがプログラムを簡単にするためにPIR1の全ビットをクリアしています。
10行を実行するとTimer1はカウントを開始します(カウントはエンドレスです)。
20行と30行を実行するとCAPTUREモードが開始されます。
50行ではCCP1IFをチェックしています。
CCP1IFがセットされたら次の行(60行)を実行します。
60行でTMR1L、TMR1H、CCPR1L、CCPR1Hの値を読み込みます。
CCPR1レジスタの値は入力信号の次の下がりエッジが来るまでラッチされています。
プログラムとしてはCCPR1レジスタの値を読むだけでよいのですがTimer1が作動していることを確認するためにTMR1レジスタの値も読んでいます。
70行ではCCPR1H、CCPR1L、PIR1、TMR1H、TMR1Lの各値を表示します。
PIR1以外は16進数表示です。
PIR1はCCP1IFの状態を念のため確認するために入力し表示しています。
80行で40行に戻って繰り返します。
CCP1はRC5(PORTCのbit5)と端子を共用しています。
CAPTUREモードではCCP1から信号を入力しますからRC5を入力に設定する必要があります。
PORTCはリセットによって入力に設定されますから今回のプログラムではTRISCの設定はしていません。
左側のコマンドプロンプトで実行するTimer0の割り込みプログラムではRC4(PORTCのbit4)からパルスを出力します。
その信号を右側のコマンドプロンプトのプログラムではRC5から入力します。
そこで今回のテストでは2台のPICUSBIO−03の入出力用コネクタを16pinフラットケーブルで接続しそのケーブルを改造して左側(PICUSBIO−03 #30)のRC4と右側(PICUSBIO−03 #31)のRC5を結線しました。
そのように準備したうえでプログラムを実行しました。
右側に表示されている数値は前からCCPR1H、CCPR1L、PIR1、TMR1H、TMR1Lです。
CCPR1の値とTMR1の値が全く合っていません。
どういうことでしょうか。
Timer1の1カウントは1/12=0.083μsecです。
CCPR1レジスタはラッチされますがTMR1レジスタはカウントを続けています。
USB接続(HID型)は低速なので各レジスタにアクセスするごとに最低2msecはかかってしまいます。
その間にTimer1は2000/0.083≒24000カウントも進んでしまいます。
CCPR1の値とTMR1の値が全く合っていないのはおそらくそのためだと考えられます。
しかしCCPR1の値も毎回異なっています。
左側のPICの出力パルスは割り込みプログラムによって送出されていますし画面からわかるようにBASICプログラムはRUNコマンド実行後はすぐに終了しています。
あとはPICの割り込みプログラムのみが実行されていてUSB通信によるアクセスも行なわれていません。
ということは左側のPICから送出されるパルスはかなり正確な周期のパルスのはずです。
一方右側のBASICプログラムは常時USB通信でPICのレジスタにアクセスしてその値を表示しますから上に書きましたようにTMR1レジスタの値はランダムに見えるほど変動しています。
しかしCCPR1レジスタは入力の立下りエッジでTMR1レジスタの値をラッチしますからこちらは変動しない、はずです。
なぜなら左側のPICからの出力パルスは上の方で行なった計算の順序を入れ換えると12000KHz/65536/64/2の周波数でその逆数が周期65536*64*2/12000=699msecになるのに対して右側のPICも65536/12000の周期でオーバーフローしますから上のケースではCCPR1の値はTimer1が128回転するごとの同じ値になるはずだからです(うまく説明できません。のちほど別のプログラムを使って検証します。とにかくそういうことのはずです)。
ところがCCPR1も少しずつですが表示される値が変動しています。
どのくらい変動しているか念のため計算してみたところランダムな変動ではなくて一定の傾向があることがわかりました。
下は前の値と次の値との差を計算した結果です。
2686
278A 104
288D 103
2991 104
2A95 104
2B98 103
16進数表示で104か103ですから10進数で示すと260カウントか259カウントずつずれていっているようです。
ただの誤差ではなくてなんとなく意味がありそうな数字です。
誤差にしては大きすぎるようですしUSBアクセスに起因する遅延にしては小さすぎる値です。
本当に何なんでしょう。
念のために左側のPICUSBIO−03からの出力パルスの周波数を変えてみました。
さきほどはT0CONに$85を設定していましたが今度は$84を設定しました。
$85はプリスケーラが1:64ですから上の方で計算しましたように出力パルスの1周期は699msecです。
今回は$84にしましたからプリスケーラは1:32です。
出力パルスの1周期はさきほどの1/2の349.5msecになります。
さきほどと同じように前の値と次の値との差を計算してみました。
A7A8
A82B 83
A8AE 83
A931 83
A9B4 83
AA37 83
16進数表示で83(10進数では131)ですからこちらもさきほどの1/2です。
どうやらパルスの周期(カウント回数)に比例しているようです。
ひょっとすると。
これはあれではないか。
ひとつ思いついたことがあります。
その線でいろいろ試していくことで思いついた通りだったことがわかったのですが、そこに行き着くまでの過程でちょいと納得がいかない現象に出くわしてしまったりしたものですからあれやこれやでたっぷり2日ほど悩んでしまいました。
そのあたりを含めて謎を残したまま次回に続きます。
PIC−USBIO using BASIC[第80回]
2022.10.22upload
前へ
次へ
ホームページトップへ戻る