第9回 ストップウォッチのカウンタ部設計

■9.1 LCD 制御ライブラリ
 LCD は文字等を表示するデバイスであるが,多彩な表示制御機能が搭載されている.
 LCD を利用する場合,LCD に対して制御命令表示データ等の書き込みが頻繁に行うことになるが,それらをサブルーチンとして利用することによって効率の良いプログラムを作製することができる.
 ただし,それらのサブルーチンの作成には,LCD のハードウェアおよびソフトウェア仕様を十分把握している必要があり,短時間での作成は困難である.

 本実習では,PIC16F84A で利用できる,SC1602BS*B 用の各種サブルーチンをまとめ,以下に示すライブラリファイル(LCD 制御ライブラリ:LCDctrl.inc)として提供する.各サブルーチンは,ライブラリファイルをインクルード命令によりプログラム中に定義することで利用できる.

LCDctrl.inc

 LCD 制御ライブラリに含まれるサブルーチンを以下に示す.

LCD_RESET リセットシーケンス
LCD_INST 制御命令出力
LCD_DATA 表示データ出力
LCD_BUSY 内部動作終了待ち
LCD_INIT リセット専用命令出力
T1ms 1 ms 時間待ち
T100ms 100 ms 時間待ち

 以下に,各サブルーチンの詳細および使用条件を示す.

◆9.1.1 使用条件
 LCD 制御用サブルーチン“LCDctrl.inc”を利用するために必要な条件,および設定を示す.

▼ハードウェア接続
 SC1602BS*B と PIC16F84A とは,以下に示すインターフェイス仕様を満たすように接続されていること.

信号種別 SC1602BS*B PIC16F84A
データ信号
(データバス)
DB7-DB0 PORTB の全ポート(初期値:任意)
制御信号 E(STB),R/W,RS(D/1) PORTA の任意のポート(初期値:0

▼定数および変数設定
 LCD 制御ライブラリのインクルード宣言より先に,以下に示す定数および変数が定義されていること.

定数 E E 端子に接続した PIC16F84A の PORTA のポート番号
RW RW 端子に接続した PIC16F84A の PORTA のポート番号
RS 接続した PIC16F84A の PORTA のポート番号
BF 7(SC1602BS*B の Busy フラグビット)
変数 cnt_1ms T1ms サブルーチン用カウンタ
cnt_1hms T100ms サブルーチン用カウンタ

◆9.1.2 LCD_RESET(リセットシーケンス) ≪LCD_INIT,T1ms,T100ms 含む≫
 ソフトウェアにより SC1602BS*B を初期化するサブルーチン.

入力 なし
使用法 通信用ポートである PORTA および PORTB の設定完了後,直ちに CALL する.

;LCD reset ----------------------------
        CALL    LCD_RESET

 なお,LCD_RESET の実行には,LCD_INIT,LCD_INST,T1ms,T100ms の各サブブルーチンが必要である.それらの中で,LCD_INIT,T1ms,T100ms の各サブブルーチンは LCD_RESET 以外では利用しないため,ここで合わせて示す.

 以下に,LCD 表示仕様を満たす,2 行,5x7 文字,カーソル表示オフ,カーソル点滅オフ,カーソルインクリメント,表示シフトオフ設定となるリセットシーケンスのフローチャートとソースコードを示す.
 各待ち時間は大幅に余裕を持たせて設定している.
 また,初期の 8 bit モード設定時には,リセットシーケンス専用の制御命令書き込み用サブルーチンである LCD_INIT を利用する.LCD_INIT は,後に示す LCD_INST より Busy 解除待ちを除いたものであるため,詳細は LCD_INST を参考とすること.

フローチャート ソースコード
;----------------------------------------------
;  LCD reset sequence
;----------------------------------------------
LCD_RESET
        CALL    T100ms          ;wait >15ms
        MOVLW   030H            ;8bit mode set
        CALL    LCD_INIT
        CALL    T100ms          ;wait >4.1ms
        MOVLW   030H            ;8bit mode set
        CALL    LCD_INIT
        CALL    T1ms            ;wait >100us
        MOVLW   030H            ;8bit mode set
        CALL    LCD_INST
        MOVLW   030H            ;interface mode set
        CALL    LCD_INST
        MOVLW   038H            ;function set
        CALL    LCD_INST
        MOVLW   008H            ;display off
        CALL    LCD_INST
        MOVLW   001H            ;display clear
        CALL    LCD_INST
        MOVLW   006H            ;entry mode set
        CALL    LCD_INST
        RETURN
;
;----------------------------------------------
;  LCD initialize code set [input:Wreg]
;----------------------------------------------LCD_INIT
        MOVWF   PORTB
        BCF     PORTA,RS        ;RS=0
        BCF     PORTA,RW        ;R/W=0
        BSF     PORTA,E         ;E=1
        BCF     PORTA,E         ;E=0
        RETURN
;
;----------------------------------------------
;  1ms timer (1cycle=1us) 1001cycle(inc CALL)
;----------------------------------------------
T1ms
        MOVLW   0F9H            ;1cycle 249
        MOVWF   cnt_1ms         ;1cycle
L_T1ms
        NOP                     ;1cycle
        DECFSZ  cnt_1ms,F       ;1(2atSkip)cycle
        GOTO    L_T1ms          ;2cycle
        RETURN
;
;----------------------------------------------
;  100ms timer (1sycle=1us) 100405cycle(inc CALL)
;----------------------------------------------
T100ms
        MOVLW   064H            ;1cycle 100
        MOVWF   cnt_1hms        ;1cycle
L_T100ms
        CALL    T1ms            ;1001cycle
        DECFSZ  cnt_1hms,F      ;1(2atSkip)cycle
        GOTO    L_T100ms        ;2cycle
        RETURN
;

◆9.1.3 LCD_BUSY(内部動作終了待ち)
 SC1602BS*B の内部動作が終了するまで復帰しないサブルーチン.なお LCD_BUSYは,LCD_INIT,LCD_INST,LCD_DATA より呼び出されるサブルーチンであり,通常はユーザが直接 CALL する必要はない.

 SC1602BS*B では,制御命令や表示データの入力に対する内部動作に 40 us〜1.64 ms 程度の処理時間を要し,この間は次の命令を受け付けることができない
 したがって,何らかの方法で内部動作が完了したことを知る必要があるが,内部動作の状態は“Busy フラグ/アドレス読み出し命令“によってBusy フラグ(BF ビット)を読み出すことによって知ることができる.

 SC1602BS*B より Busy フラグを入力する場合のタイミングチャートを以下に示す.

注)  PIC16F84A の命令クロックは最高でも 20/4=5 MHz であるため,1 サイクルは 200 ns 以上である.
 したがって,信号を切り替える順番さえ守れば必然的に書き込みのタイミング条件を満たすことになる.

 PIC16F84A のデータバス(PORTB)を一時的に入力モードに設定し,RS,R/W,E 信号を規定のタイミングで操作することにより,Busy フラグを読み出すことができる.なお,Busy フラグは DB7 ビットに割り当てられている
 SC1602BS*B の内部動作状態とBusyフラグとの関係を以下に示す.

内部動作状態 動作中 動作完了
Busy フラグ 1 0

 タイミングチャートに基づき,内部動作完了まで(Busy フラグ(BF)が’0’になるまで)復帰しないよう作成した LCD_BUSY のフローチャートとソースコードを示す.

フローチャート ソースコード
;----------------------------------------------
;  LCD Busy clear wait
;----------------------------------------------
LCD_BUSY
;data bus(PORTB) all input set ---------
        BSF     STATUS,RP0      ;set Bank1
        MOVLW   0FFH
        MOVWF   TRISB
        BCF     STATUS,RP0
;
;BUSY check ----------------------------
        BCF     PORTA,RS        ;RS=0
        BSF     PORTA,RW        ;R/W=1
L_BUSY
        BSF     PORTA,E         ;E=1
        BCF     PORTA,E         ;E=0
        BTFSC   PORTB,BF
        GOTO    L_BUSY
;
;data bus(PORTB) all output set --------
        BSF     STATUS,RP0      ;set Bank1
        CLRF    TRISB
        BCF     STATUS,RP0
        RETURN
;

◆9.1.4 LCD_INST(制御命令出力)
 SC1602BS*B へ制御命令を出力するサブルーチン.

入力 Wreg
使用法 Wreg に制御命令コードを格納後に CALL する.

        MOVLW   008H            ;display off
        CALL    LCD_INST

 なお,LCD_INST の実行には,LCD_BUSY サブブルーチンが必要である.

 SC1602BS*B へ制御命令を出力する場合のタイミングチャートを以下に示す.



 データを DB0-7 へ設定後,RS,R/W,E 信号を規定のタイミングで操作することにより,制御命令を書き込むことができる.

 タイミングチャートに基づき作成した LCD_INST のフローチャートとソースコードを示す.
 なお,命令出力後は Busy 状態をが解除されるまで待って復帰する.

フローチャート ソースコード
;----------------------------------------------
;  LCD instruction code set [input:Wreg]
;----------------------------------------------
LCD_INST
        MOVWF   PORTB
        BCF     PORTA,RS        ;RS=0
        BCF     PORTA,RW        ;R/W=0
        BSF     PORTA,E         ;E=1
        BCF     PORTA,E         ;E=0
        CALL    LCD_BUSY        ;busy clear wait
        RETURN
;

◆9.1.5 LCD_DATA(表示データ出力)
 SC1602BS*B へ表示データを出力するサブルーチン.

入力 Wreg
使用法 Wreg に表示データコードを格納後に CALL する.

        MOVLW   031H            ;'1'
        CALL    LCD_DATA

 なお,LCD_DATA の実行には,LCD_BUSY サブブルーチンが必要である.

 SC1602BS*B へ表示データを出力する場合のタイミングチャートを以下に示す.



 データを DB0-7 へ設定後,RS,R/W,E 信号を規定のタイミングで操作することにより,表示データを書き込むことができる.

 タイミングチャートに基づき作成した LCD_DATA のフローチャートとソースコードを示す.
 なお,命令出力後は Busy 状態をが解除されるまで待って復帰する.

フローチャート ソースコード
;----------------------------------------------
;  LCD display data code set [in:Wreg]
;----------------------------------------------
LCD_DATA
        MOVWF   PORTB
        BSF     PORTA,RS        ;RS=1
        BCF     PORTA,RW        ;R/W=0
        BSF     PORTA,E         ;E=1
        BCF     PORTA,E         ;E=0
        CALL    LCD_BUSY        ;busy clear wait
RETURN
;

◆9.1.6 利用例
 LCD 制御ライブラリ(LCDctrl.inc)を利用した簡単な LCD 表示プログラム例を示す.



ソースコード
;***********************************************************
;       step09 program for PIC16F84A
;       step09.asm, H. OSADA, Jan. 2005
;***********************************************************
;
;=================================================
;  definitions
;=================================================
;- hardware -----------------------------------
        LIST    P=PIC16F84A
        #INCLUDE "P16F84A.INC"
;
        __CONFIG _HS_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF
;
;- constant label -----------------------------
E           EQU     000H    ;LCD E pin
RW          EQU     001H    ;LCD R/W pin
RS          EQU     002H    ;LCD RS pin
BF          EQU     007H    ;LCD Busy flag bit
;
;- file register ------------------------------
        CBLOCK  0CH
            cnt_1ms         ;1ms counter
            cnt_1hms        ;100ms counter
        ENDC
;
;=================================================
;  run start
;=================================================
;- reset start --------------------------------
        ORG     0
        GOTO    INIT
;
;- interrupt start ----------------------------
        ORG     4
        GOTO    ISR
;
;- initialize ---------------------------------
INIT
        BSF     STATUS,RP0      ;set Bank1
        MOVLW   018H            ;RA0-2:out, RA3-4:in
        MOVWF   TRISA
        CLRF    TRISB           ;RB0-7:out
        BCF     STATUS,RP0      ;set Bank0
;
        CALL    LCD_RESET       ;LCD reset
        MOVLW   00CH            ;disp on, cursor off, blink off
        CALL    LCD_INST
;
;=================================================
; main routine
;=================================================
MAIN
        MOVLW   080H            ;pos line:1st,column:1st
        CALL    LCD_INST
;
        MOVLW   'S'             ;print 'S'
        CALL    LCD_DATA
        MOVLW   't'             ;print 't'
        CALL    LCD_DATA
        MOVLW   'e'             ;print 'e'
        CALL    LCD_DATA
        MOVLW   'p'             ;print 'p'
        CALL    LCD_DATA
        MOVLW   '0'             ;print '0'
        CALL    LCD_DATA
        MOVLW   039H            ;print '9'
        CALL    LCD_DATA
;
LOOP
        GOTO    LOOP
;
;=================================================
;  interrupt service routine
;=================================================
ISR
;** procedure
;
;=================================================
;  subroutine
;=================================================
        #INCLUDE "LCDctrl.inc"
;
;***********************************************************
        END
 
■9.2 カウンタ動作アルゴリズム
 「基本分解能で動作するカウンタ部」を設計する.
 ストップウォッチのカウンタ部に関する仕様を抜粋して以下に示す.

分解能 1/100秒(10 ms)
計測範囲 00時間00分00秒00(初期表示)〜99時間59分59秒99(次のクロックで初期表示に戻る)

 10 msの分解能で動作する 8 桁のカウンタ部のアルゴリズム例を以下に示す.

初期設定 ・以下に示す 8 個のカウンタ(変数)を定義し,初期値を設定する.

 
cnt_msL 1/100 秒下位桁用カウンタ 初期値:0,最大値:9
cnt_msH 1/100 秒上位桁用カウンタ 初期値:0,最大値:9
cnt_sL 下位桁用カウンタ 初期値:0,最大値:9
cnt_sH 上位桁用カウンタ 初期値:0,最大値:5
cnt_mL 下位桁用カウンタ 初期値:0,最大値:9
cnt_mH 上位桁用カウン 初期値:0,最大値:5
cnt_hL 時間下位桁用カウンタ 初期値:0,最大値:9
cnt_hH 時間上位桁用カウンタ 初期値:0,最大値:9
  

・10 ms のインターバルタイマを設定する.
メインルーチン ・無限ループのみを定義する.
割り込みルーチン ・以下のルールに従いカウンタをインクリメントする.
  
cnt_msL インターバルタイマルーチン実行ごとにインクリメントする.
10(オーバーフロー)になったら上位桁(cnt_msH)をインクリメントし初期値(0)に戻る.
cnt_msH 下位桁(cnt_msL)がオーバーフローした場合にインクリメントする.
10(オーバーフロー)になったら上位桁(cnt_sL)をインクリメントし初期値(0)に戻る.
cnt_sL 下位桁(cnt_msH)がオーバーフローした場合にインクリメントする.
10(オーバーフロー)になったら上位桁(cnt_sH)をインクリメントし初期値(0)に戻る.
cnt_sH 下位桁(cnt_sL)がオーバーフローした場合にインクリメントする.
6(オーバーフロー)になったら上位桁(cnt_mL)をインクリメントし初期値(0)に戻る.
cnt_mL 下位桁(cnt_sH)がオーバーフローした場合にインクリメントする.
10(オーバーフロー)になったら上位桁(cnt_mH)をインクリメントし初期値(0)に戻る.
cnt_mH 下位桁(cnt_mL)がオーバーフローした場合にインクリメントする.
6(オーバーフロー)になったら上位桁(cnt_hL)をインクリメントし初期値(0)に戻る.
cnt_hL 下位桁(cnt_mH)がオーバーフローした場合にインクリメントする.
10
(オーバーフロー)になったら上位桁(cnt_hH)をインクリメントし初期値(0)に戻る.
cnt_hH 下位桁(cnt_hL)がオーバーフローした場合にインクリメントする.
10(オーバーフロー)になったら初期値(0)に戻る.
サブルーチン なし
 
■9.3 カウンタ表示仕様
 ストップウォッチの表示部に関する仕様を抜粋して以下に示す.

計測範囲 00時間00分00秒00(初期表示)〜99時間59分59秒99(次のクロックで初期表示に戻る)

 上記の仕様に基づいた LCD 表示仕様を以下に示す.

LCD 制御
表示行数 表示フォント カーソル表示 カーソル点滅 カーソル移動方向 表示シフト
2 行 5 x 7 オフ オフ インクリメント(右) オフ
表示 ・2行6桁目より表示を開始する.

  
カウンタ対応
表示 0 1 h 2 3 m 4 5 s 6 7
カウンタ  cnt_hH cnt_hL cnt_mH cnt_mL cnt_sH cnt_sL cnt_msH cnt_msL

 インターバルタイマルーチン内において,「基本分解能で動作するカウンタ部」に続けて「LCDによるカウンタ値の表示部」をコーディングすることにより,カウンタ値を表示できる.
 
■課題
 以下に示す内容のプログラムを作成し,その「フローチャート」と「ソースコード」を示しなさい.
 ただし,LCD制御ライブラリの「フローチャート」と「ソースコード」は示さなくてよい.

プロジェクト名 step09
内容 「基本分解能で動作するカウンタ部」および「LCDによるカウンタ値の表示部」
正解例オブジェクトコード step09.hex

 レポートは,下記のWordファイルを使用して作成すること.なるべく簡潔にまとめることが望ましい.
 Form09.docx

 WebClassより期限内に提出すること.