[PIC] もっと簡単にウェイト ループ

Posted by
ぴろり
Posted at
2015/01/13 16:56
Trackbacks
関連記事 (0)
Post Comment
コメントできます
Category
開発メモ カテゴリ 電子工作 カテゴリ
カバーイメージ

 PIC で長時間のウェイトを実現するために、8 ビットカウンタのループを複数段で構成して、むしろ問題を複雑に考えすぎていました。そもそも難しく考えず、「16 ビット以上のカウンタ変数を利用できるループを作る」と考えればよく、そうすれば問題は単なる一次方程式の問題で終わります。年が明けてから気が付いた覚書き。

この記事を Delicious に追加する   このエントリーをはてなブックマークに追加  

 国民機起動音発生装置 PiPo*1のソースコードを読んでいて発見しました。いや、ホント、なんでこんな難しく考えていたのかなぁgawk.gif…という感じです。*2

1 段構成

 1 段構成のループで実現できるのは高々 1000 サイクル、400 μ秒程度。9 行目に NOP を追加して多少の時間延長は可能ですが、ループカウンタ cnt がどう頑張っても 8 ビットしかないので短時間のウェイト向きです。キャリー フラグ(Carry Flag)を利用してループ脱出を判断しているため、cnt で指定した回数に加えて、余分に 1 回ループが回ります。

    call    LOOP        ; 2c
; ...
LOOP:
    ; 0x4F + 1 = 80 回ループする
    movlw   0x4F        ; 1c
    movwf   cnt         ; 1c, 0x4F → W → cnt
    movlw   d'1'        ; 1c, 1 → W
LOOP_MAIN:
                        ; 必要に応じてここに NOP を放り込むことも可能
    subwf   cnt, F      ; 1c, cnt - W → cnt
    btfsc   STATUS, C   ; 1c, cnt が 0x00 → 0xFF でキャリー発生(0 → C)
    goto    LOOP_MAIN   ; 2c
    return              ; 2c

decf ではなく、わざわざワーキング レジスタを使って subwf を使うのは、decf ではキャリー フラグが変化しないため、と思う。ゼロ フラグだけでループを組めれば、ワーキング レジスタは不要になるかもしれないが、そのパズルには挑戦していません。

2 段構成

 cntHcntL を用いて、ループ カウンタを 16 ビット幅にしたものです。ウェイト処理が二重になっていますが、各段ごとにウェイト数を計算するとかヤヤコシイことを考えずとも、希望のループ回数を cntHcntL に WORD 値で直接指定すればよいだけなので簡単。

    call    LOOP        ; 2c
; ...
LOOP:
    ; 0x4FFF + 1 = 20,480 回ループする
    movlw   0x4F        ; 1c
    movwf   cntH        ; 1c, 0x4F → W → cntH
    movlw   0xFF        ; 1c
    movwf   cntL        ; 1c, 0xFF → W → cntL
    movlw   d'1'        ; 1c, 1 → W
LOOP_MAIN:
    subwf   cntL, F     ; 1c, cntL - W → cntL
    btfss   STATUS, C   ; 1c, cntL が 0x00 → 0xFF でキャリー発生(0 → C)
    subwf   cntH, F     ; 1c, cntH - W → cntH
    btfsc   STATUS, C   ; 1c, cntH が 0x00 → 0xFF でキャリー発生(0 → C)
    goto    LOOP_MAIN   ; 2c
    return

更なる多段構成

 更に長時間のウェイトが必要であれば、同じ考え方でカウンタ変数とキャリー発生の条件分岐(13~18行目)を増やせば多段構成が可能ですが、もうここまで来ると、省電力動作*3のためにもウォッチドッグタイマなど別の方法が良いと思います。

    call    LOOP        ; 2c
; ...
LOOP:
    ; 0x4FFFFF + 1 = 5,242,880 回ループする
    movlw   0x4F        ; 1c
    movwf   cntX        ; 1c, 0x4F → W → cntX
    movlw   0xFF        ; 1c
    movwf   cntH        ; 1c, 0xFF → W → cntH
    movlw   0xFF        ; 1c
    movwf   cntL        ; 1c, 0xFF → W → cntL
    movlw   d'1'        ; 1c, 1 → W
LOOP_MAIN:
    subwf   cntL, F     ; 1c, cntL - W → cntL
    btfss   STATUS, C   ; 1c, cntL が 0x00 → 0xFF でキャリー発生(0 → C)
    subwf   cntH, F     ; 1c, cntH - W → cntH
    btfss   STATUS, C   ; 1c, cntH が 0x00 → 0xFF でキャリー発生(0 → C)
    subwf   cntX, F     ; 1c, cntX - W → cntX
    btfsc   STATUS, C   ; 1c, cntX が 0x00 → 0xFF でキャリー発生(0 → C)
    goto    LOOP_MAIN   ; 2c
    return
この記事を Delicious に追加する   このエントリーをはてなブックマークに追加  

  1. *1 昔懐かしの国民機 NEC の PC-98 の起動音を再現する電子回路
  2. *2 わざわざ Excel シートまで作って完全に無駄だった模様
  3. *3 カウンタを数えまくっている間にも、プログラムとしてはフル回転しているわけで、その間、電力を消費しています

この記事を読んだ人はこんな記事も読んでいます記事リコメンデーションについて

カバー画像:PIC ことはじめ ~ ウォッチドッグタイマ

関連記事/トラックバック

関連記事/トラックバックはまだありません

この記事にトラックバックを送るには?

コメントを投稿する

 
 (必須, 匿名可, 公開, トリップが使えます)
 (必須, 匿名可, 非公開, Gravatar に対応しています)
 (必須)
スパム コメント防止のため「投稿確認」欄に ランダムな数字 CAPTCHAについて を入力してから送信してください。お手数ですがご協力のほど宜しくお願いいたします。