LCDキャラクターディスプレイ / LPM命令を使って文字列を書き込む

p.402
これまでは1文字ずつ指定していたが、ここでは文字列で指定できるようにする。
f:id:ti-nspire:20200612070859p:plain:h300 f:id:ti-nspire:20200612071027j:plain:h300

.EQU RS = PD0
.EQU EN = PD2

; スタックポインタの初期化マクロ
.MACRO INITSTACK
    LDI R16, HIGH(RAMEND)
    OUT SPH, R16
    LDI R16, LOW(RAMEND)
    OUT SPL, R16
.ENDMACRO

INITSTACK

; PD7:4をLCDのD7:4に接続して命令とデータとを書き込むことにする。
; PD0からRS信号を、PD2からEN信号を出すことにする。
LDI R16, 0xF0 | (1 << RS) | (1 << EN)
OUT DDRD, R16

LDI R16, 0b00110011
CALL COMMAND_W
CALL DELAY_2ms

LDI R16, 0b00110010
CALL COMMAND_W
CALL DELAY_2ms

LDI R16, 0b00101000
CALL COMMAND_W
CALL DELAY_2ms

LDI R16, 0b1111
CALL COMMAND_W

LDI R16, 0b0001
CALL COMMAND_W
CALL DELAY_2ms

LDI R16, 0b0110
CALL COMMAND_W

MESSAGE:
    .DB "June 12th, 2020 " ; 文字数は偶数にする。

LDI ZH, HIGH(MESSAGE << 1) ; ZHはR31。
LDI ZL, LOW(MESSAGE << 1)  ; ZLはR30。
CALL COMMAND_W
LOOP:
    LPM R16, Z+ ; LPMはLoad Program Memory。Z+の+はpost incremented。
    CPI R16, 0  ; null文字であったら、(CPIはCompare with Immediate)
    BREQ MAIN   ; ループを抜ける。(BREQはBranch if Equal)
    CALL DATA_W
    RJMP LOOP

MAIN:
    RJMP MAIN

; 上位ニブルを書き込むためのサブルーチン
HI_NIBBLE_W:
    ANDI R27, 0xF0
    IN R26, PORTD    ; ポートDの下位ニブル(制御線)に触りたくないので一旦全部取り込んで、
    ANDI R26, 0x0F
    OR R26, R27      ; 下位ニブルは変えないまま、
    OUT PORTD, R26   ; またポートDに書き込んで、
    SBI PORTD, EN
    CALL SHORT_DELAY
    CBI PORTD, EN    ; そのままLCDへ書き込む。
    CALL DELAY_100us
    RET

; 1バイトを書き込むためのサブルーチン
BYTE_W:
    MOV R27, R16
    CALL HI_NIBBLE_W
    MOV R27, R16
    SWAP R27
    CALL HI_NIBBLE_W
    RET

; 命令を書き込むためのサブルーチン
COMMAND_W:
    CBI PORTD, RS
    CALL BYTE_W
    RET

; データを書き込むためのサブルーチン
DATA_W:
    SBI PORTD, RS
    CALL BYTE_W
    RET

SHORT_DELAY:
    RET ; 4

DELAY_100us:
    PUSH R17          ; 2
    LDI R17 , 200     ; 1
DR0:
    RCALL SHORT_DELAY ; 3
    DEC R17           ; 1W
    BRNE DR0          ; falseで1, trueで2
    POP R17           ; 2
    RET               ; 4

DELAY_2ms:
    PUSH R17          ; 2 
    LDI R17, 20       ; 1
LDR0:
    RCALL DELAY_100us ; 3
    DEC R17           ; 1
    BRNE LDR0         ; falseで1, trueで2
    POP R17           ; 2
    RET               ; 4