いけず言葉しりとり

今更ながらPIC16F84Aを使ってサーボを動かすプログラムの勉強を始めました。

サーボを動かすためにマイクロ秒単位のタイマーを作らなければならないのでそのためにサンプル的に以下の様なプログラムを作ってみました。
アセンブリ言語とPA.EXEという古い環境ですが・・・

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include 16f84.h

.osc hs
.wdt off
.protect off

org 0ch

tm1 ds 1
tm2 ds 1

org 0
goto start
org 4
goto start

start
clr ra
clr rb
mov !ra,#00000b
mov !rb,#00000000b

ntl
mov rb,#00000001b ;
call wait10

mov rb,#00000000b
call wait10
goto ntl


wait10
movlw 50 ;①
movwf tm1

wait10_1 
movlw 128 ;②
movwf tm2

wait10_2 
nop
decfsz tm2,1
goto wait10_2
decfsz tm1,1
goto wait10_1
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
プログラムをコピペしたら変になったので一応画像も添付しております。


使用するクロックは10Mのセラロックです。

①、②の値を変えればラベルwait10_2内のnop命令の繰り返し回数が変化し、ラベルntlでのポートRB0からの出力時間を変化させられると思います。
この時間を10マイクロ秒にするには①、②の値(もしくは①×②の値?)をどのようにすれば良いのでしょうか?
また、現在は仮に①=50 ②=128としていますが、この値のままでラベルwait10の行からwait10_2までを実行し終わった時にかかる時間の計算はどのようにすれば良いのでしょうか?

10マイクロ秒のタイマーの作り方が分かれば後はそれを応用して簡単なサーボコントローラーに応用していきたいと思います。
よろしくお願い致します。

「PICマイコンのプログラムについて教えて」の質問画像

A 回答 (3件)

ひとつ注意点として、


恐らく10マイクロ秒固定の時間待ち関数が目的ではなく、10マイクロ秒単位で任意の時間を待つ関数を作るつもりだと思いますが、
これを10マイクロ秒待ちをループで繰り返すように作ると、ループ処理の部分に掛かる時間の分だけずれます。
例えばループ処理に1.2マイクロ秒掛かるなら8.8マイクロ秒待ちの処理を作る必要がありますのでご注意ください。

処理にかかる時間の計算ですが、
PICは本来、非常に処理時間を計算しやすいマイコンです。
すべての命令が4クロックの倍数で動くので、4クロックを「1サイクル」と称します。
ほとんどの命令は、実行に1サイクル(4クロック)掛かります。
GOTO・RETURN・「addwf PCL」などの分岐命令は2サイクルです。
スキップ系命令(BTFSS・INCFSZなど)は考え方が2通りあり、
「条件が満たされた場合は次の命令をスキップして2サイクル、条件が満たされない場合は次の命令をスキップせず1サイクル」と見るか、
「常に1サイクルで実行し、条件が満たされた場合は次の命令の代わりにNOPを実行する」と見るかで、表現に差があるので資料を見る時はご注意ください。

しかし問題はPA.EXEの独自表記で、アセンブラ命令でない「mov !rb,#00000000b」などものはどれだけ時間が掛かるか分かりません。
PA.EXEの説明書を見るか、ビルドした結果を見るなどしてください。
また、PA.EXEをやめてMPLABを使えばシミュレータで実行サイクル数を確かめられます。PA.EXEの独自書式は使えなくなりますが、純粋なアセンブラ部分は変わりませんのでさほど移行に障害はないでしょう。
    • good
    • 0

> この時間を10マイクロ秒にするには①、②の値(もしくは①×②の値?)をどのようにすれば良いのでしょうか?


このプログラムでは遅延部分が二重ループになっているのであまり短い周期のタイマーは作れません。
2つのパラメーター(現在128と50)を共に1にした場合、ポート出力が1(High)になる時間がたぶん16クロック、0(Low)の時間がたぶん18クロックになるはず。クロック発振が10MHzならば命令1個の実行時間は0.4μ秒ですから1周期は約13.6μ秒になるはずです。これが最短周期です。このままではこれより短い周期にはできません。
もっと短い周期にするにはループを一重にすればよいのです。例えば

wait10   movlw   ▼
       movwf   tm2
wait10_2 decfsz   tm2,1
      goto    wait10_2
      ret

これで最短処理時間は6サイクルのはず。親ルーチンのCALL等を含めると9サイクル前後のはずですからクロック発振が10MHzならば最短周期が7~8μ秒のパルスが出せるはずです。
▼の値は必要なパルス幅に応じて変えてください。値を1増すと出力パルスの周期は2.4μ秒長くなります。


> 現在は仮に①=50 ②=128としていますが、この値のままでラベルwait10の行からwait10_2までを実行し終わった時にかかる時間の計算はどのようにすれば良いのでしょうか?
主ループはNOPからの3命令。命令の実行時間はNOPとDECFSZは1サイクル、GOTOは2サイクルなので合計4サイクル。
これを 128×50 回繰り返すので25600サイクル要します。
クロック発振が10MHzならば1サイクルが0.4μ秒ですからこのサブルーチンでの遅延時間は10.24m秒になります。
この計算式は 0.4μ秒 × 4サイクル × 128 × 50 = 10.24m秒
したがって出力周波数は  1 ÷ ( 10.24m秒 × 2 ) = 48.8Hz
以上は概算です。この計算にはMOVLWやRETを含んでいないので実際にはもう少し低い周波数になります。

PIC16F84Aが持つタイマーはオーバーフロー型のタイマーです。割込が掛けられるだけでハードウェアでは出力されていないので短周期のパルスは作れません。
PICの一部の品種ではタイマーに初期設定するだけでソフトの負担なしで高速パルスを出すことができます。例えばPIC16F178xシリーズなど。200KHzぐらいまでは出したことがありますが最高で8MHzまで出るはず。タイマーへの設定値を N(8bit) として、 発振周波数 ÷ N の周波数が取り出せます。Duty比も変えられPWM機能もあります。
    • good
    • 0

PICで正確な単位のタイマーを作るにはタイマー0を使った割り込み以外無いと思いますがクロックがセラロックというのは矛盾があると思います。

この精度は±0.5%です。最大1%の狂いがあるので例えば1秒パルスを作ったら1%=10msずれが発生するとなり、100カウントすると1秒ずれることになります。なのでセラロックではマイクロ秒単位のタイマーは作れません。PA.EXEの資料が見つからないのでタイマー0を使った割り込みが使えるかどうか不明です。

この質問のデバッグ方法は30年以上前のZ80全盛時代の自作ホビーストがやっていた方法で古過ぎます。PICはICSPが出来るのでPICKIT3を買ってきてやった方が早いです。デバッグもMPLABという無償のプログラマで出来るのでプログラムを見ながらステップ動作やレジストリ内のモニタは自由に出来ます。

PA.EXEを調べていたとき偶然に貴方の過去の質問を見ました。日付は2007年でした。そんなに苦労しているならC言語を勧めます。こちらのほうが記述が簡単でわかりやすいと思います。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報