プログラム作成実習

  1. プログラムの内容
    1. 内容
      ここでは、スイッチから読み込んだ4ビットを、左方向に回転しながら、表示するプログラムを作成します。回転が速いと、すべてが半点灯状態になってしまいまから、途中で時間稼ぎ(暇つぶし)をします。

    2. 回路
       「ポートと入出力」と同じ回路を利用します。


    3. 指示命令
      アセンブラは先頭で指示命令により、アセンブルする条件を設定します。LIST,__CONFIG,INCLUDE は指示命令です。

      __CONFIG は 構成ビットの設定です。内部発振と電源オン時のリセットを指定しています。

      INCLUDE <P16F628A.INC> は、16F628A 関連のレジスタや定数の設定ファイルを読み込む指示です。

    4. 宣言命令
      アセンブラの記述の中には、機械語にならない「命令」があります。これを宣言(擬似)命令と呼びます。
      ; があると、それ以後は 注釈として無視されます。
      EQU 命令は、ラベルとその番地を指定します。

      org はプログラムの開始とその番地を指定します。end はプログラムの終了を意味します。

    5. 使用する命令

      movlw 0x07 :wレジスタに定数 x07 を設定します。xは16進数です。
      movwf CMCON :wの値を CMCON に設定します。CMCON はハードウエア設定用レジスタです。

      bsf STATUS, RP0: STATUSのRP0ビットを1にします、これで、以下のメモリアクセスはバンク1(64-127番地)となります。
      bcf STATUS, RP: STATUSのRP0ビットを0にします

      movwf TRISA  :ポートAの各ビットの入力/出力を設定します。0で出力、1で入力です。
      movwf TRISB

      rlf SHIFTDT, F: 指定したメモリの内容を左シフトします。一番右のビットにはCフラグがの値が入り、一番左のビットはCフラグに移ります。

      ここでは、4ビットのシフトを行うため、シフトする前に、予め右から4番目のビットの値でCフラグをセットします。

      bcf STATUS, C :STATUSレジスタのCフラグを0にする。
      btfsc SHIFTDT, 3:SHIFTDTの第3ビットを調べ、0なら次の命令をスキップする。
      bsf STATUS, C :STATUSレジスタのCフラグを1にする。

      call TIMER3:TIMER3 を呼び出します。RETRUN命令で call した次の命令に戻ることができます。

      DECFSZ CNT3, F ;CNT3番地の値を1つ減らし0になったら次の命令をスキップします。

    6. プログラム
       rlf 命令は、Cフラグを利用した、9ビットの回転を行います。ここでは、4ビットの回転を行いたいので、SHIFTDT の第3ビットをチェックし、これが1なら予めキャリーフラグをセットしておきます。これで、回転命令を実行すれば、4ビットの回転が可能です。
       TIMER3は、「時間つぶし」を行います。TIMER3はTIMER2を、TIMER2はTIMER1を呼び出して、3重の繰り返しで、0.5秒の「時間つぶしを行っています。繰り返しの回数は、命令の実行時間に依存しますから、使用するクロックの数で変化します。
      ;*********************************************
      ;   PIC16F628A
      ;   4bitデータシフトプログラム
      ;   「ディジタル回路」実験用教材
      ;   yokoie    2005.06.16作製
      ;*********************************************
      
      ;入出力ピン対応表
      ;   RA0,1,2,3   SW入力
      ;   RB0,1,2,3   LED出力
      
      LIST P=16F628, ST=OFF, R=DEC, F=INHX8M
      INCLUDE <P16F628A.INC>
      
      __CONFIG _LVP_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT 
      
      ; 変数の定義
      
      ;  メインルーチン
      CNT1     EQU     20h ;TIMER1用カウンタ
      CNT2     EQU     21h ;TIMER2用カウンタ
      CNT3     EQU     22h ;0.5秒カウント用カウンタ
      SHIFTDT  EQU     23h ;シフトするデータを格納するレジス
      
      ; プログラム開始番地
              org    0                ;Reset Start
      MAIN        
       ;ポート設定
              movlw   0x07
              movwf   CMCON                   ;PORTAをIOとして使用する
      
              bsf     STATUS, RP0             ;BANK1にする
              movlw   B'00001111'
              movwf   TRISA                   ;RA3,2,1,0を入力に
              
              movlw   B'11110000'
              movwf   TRISB                   ;RB0,1,2,3を出力に
      
              bcf     STATUS, RP0             ;BANK0に戻す
      
      ;ポートAから入力
      LOOP
              movf    PORTA, W         ;PORTA -> W
              movwf   SHIFTDT         ;W -> SHIFTDT
      
      ;SHIFTDTの値をシフトしてPORTBへ出力する
      DTOUT   movf    SHIFTDT, W      ;SHIFTDT -> W
              movwf   PORTB           ;W -> PORTB
              call    TIMER3          ;約0.5秒待機
              
              bcf     STATUS, C       ;Cフラグをクリア
              btfsc   SHIFTDT, 3      ;SHIFTDTの第3ビットがLなら次をスキップ
              bsf     STATUS, C       ;CフラグをHに
              
              rlf     SHIFTDT, F      ;SHIFTDTを1ビット左へシフト
              goto    DTOUT           ;DTOUTへ戻りシフトを繰り返す
      
      
      ;***** 約0.5秒のタイマー(@4MHz) *****
      TIMER3  MOVLW   d'10'           ;10 ->W
              MOVWF   CNT3            ;W -> CNT3
      TIMLP3  CALL    TIMER1          ;50m秒待機
              DECFSZ  CNT3, F         ;CNT3を減らし0なら次をスキップ
              GOTO    TIMLP3          ;CNT3がゼロになるまで繰り返す
              RETURN                  ;戻る
      
      ; ***** 約50m秒のタイマ(@4MHz) *****
      TIMER1  MOVLW   d'99'           ;TIMER2を99回実行する
              MOVWF   CNT1            ;CNT1 = 99
              NOP                     ;何もしない命令で時間調整
              NOP
      TIMLP1  CALL    TIMER2
              DECFSZ  CNT1, F         ;CNT1を減らし、ゼロなら次をスキップ
              GOTO    TIMLP1
              RETURN
      
      ; ***** 約500μ秒のタイマ(@4MHz) *****
      TIMER2  MOVLW   d'165'          ;
              MOVWF   CNT2            ;CNT1 = 165
              NOP                     ;
              NOP                     ;NOPを2回入れることで、正確に500回となる。
      TIMLP2  DECFSZ  CNT2, F         ;CNT1を減らしゼロなら次をスキップ
              GOTO    TIMLP2
              RETURN
      
              end                     ;プログラム終了

  2. プロジェクトの作成

    1. プロジェクト
      MPLABを立ち上げ、Projectメニューから projectWizard を選択します。Device を選択し(16F628A)、language tool suite を選択(MicroChip MPASM、他も既定値)、プロジェクトの名前と場所(フォルダ)を選択します。フォルダは、work フォルダ内に作成者の番号のフォルダを作成して下さい。
       step Four はプロジェクタに追加するファイルを指定します。ここでは何も追加しません。

    2. ソースプログラム
       ファイルメニューのFileメニューの new でソースファイルを作成し、save as でプロジェクトを作成したフォルダに保存します。Projectメニューの add file で、ソースファイルをプロジェクトに追加します。

    3. アセンブル
       ProjectメニューのMake でアセンブルします。エラーがあったら修正します。結果はリストファイルで見ることが出来ます。Fileメニューのopen で、ファイルの種類を list として開きます。0000 3007 は0番地の命令は 3007 となったことを示します。00032はリストの行数です。

      0000 3007 00032 movlw 0x07
      0001 009F 00033 movwf CMCON ;PORTAをIOとして使用する
      00034
      0002 1683 00035 bsf STATUS, RP0 ;BANK1にする

    4. デバッグ
       このままシミュレーションすると、TIMER部分の繰返しが多く、時間がかかります。各TIMERの先頭の数値を、1または2に変更します。
      Viewメニューのwatchを選択し、addSFR でWとPORTA、APORTB、Add Synbol で、CNT1,CNT2,CNT3 を追加します。
       Debuggerメニューの Stimulas で、Pin:RA0を Action:High に Enable:Fire します。これで、RA0が1になります。他のビットも設定できます。

       F7キーを押すと1命令づつ実行されます。Debuggerメニューのreset で0番地に戻ります。