lcd.frt

\ HD44780 LCD interface library

marker _lcd_

PORTD 2 portpin: rs
PORTD 3 portpin: rw
PORTD 4 portpin: e

PORTB 0 portpin: db4
PORTB 1 portpin: db5
PORTB 2 portpin: db6
PORTB 3 portpin: db7

variable 4bitmode
16 constant lcd.width

: lcd.initpins
    rw pin_output
    rs pin_output
    e pin_output

    db7 pin_output
    db6 pin_output
    db5 pin_output
    db4 pin_output
    
    db7 low
    db6 low
    db5 low
    db4 low
    
    rw high
    rs high
    e  low
;

\ Pulses the E line for approx. 1ms.
: lcd.epulse
    e high 1ms e low 1ms
;

: lcd.command ( cmd -- )
    rw low                      ( write mode)
    e low                       ( clock is based on high pulses, but sampled on downward slope)

    4bitmode @ 1 = if
        dup                     ( make a copy of the cmd byte, we'll need it twice)
        $f0 and 4 rshift        ( shift down high nibble)
        PORTB c! lcd.epulse     ( shift out the high nibble)
        $0f and                 ( zero out high nibble)
        PORTB c! lcd.epulse     ( shift out the low nibble)
    else
        PORTB c! lcd.epulse     ( shift out the whole byte)
    then
    
    rw high                     ( read mode)
    
    \ According to the datasheet, DB7 indicates a busy flag.  Checking it wasn't
    \ working for me, so this is disabled for now.
    \ db7 pin_input
    \ db7 low
    \ begin
    \    lcd.epulse
    \    lcd.epulse
    \    db7 pin_low?
    \ until
;

\ Send a command byte to the LCD.
: lcd.sendcmd ( c -- )
    rs low
    lcd.command
;

\ Emit a character to the LCD, based on the current DDRAM address.
: lcd.emit ( c -- )
    rs high
    lcd.command
;

\ Print a string to the LCD.  String is placed on stack via s" " word.
\ If string is longer than lcd.width characters, only lcd.width characters are printed.
: lcd.print ( addr u x y -- )
    dup 1 > if abort" Y > 1" then   ( ensure Y address is within range (0 or 1))
    1 = if $40 + then               ( if Y==1, add 2nd line offset of $40 )
    $80 +                           ( add command to offset)
    lcd.command                     ( set DDRAM address)
    lcd.width min                   ( truncate string if necessary)
    0 do                            ( for each character in string -- consumes count)
        dup                         ( make a copy of the address of the string)
        c@                          ( fetch character (consumes address))
        lcd.emit                    ( emit this character)
        1+                          ( increment address)
    loop
    drop                            ( drop the string address)
;

\ Initialize a HD44780 LCD.  Right now this assumes 4 bit mode.
: lcd.init ( -- )
    lcd.initpins
    $20 lcd.command ( set 4 bit mode)
    1 4bitmode !
    $28 lcd.command ( set 4 bit mode, 2 line display)
    $0F lcd.command ( display on, cursor underline and blinking)
    $06 lcd.command ( entry mode set, shift cursor right and increment)
    s" Hello world" 0 0 lcd.print
;



Generated by GNU enscript 1.6.4.