fl

{
   3-wire Driver for an HD44780 based LCD Character based display
    PropForth 4.0/4.0a compatible
    2011/3/25

     3-wire LCD curcuit   Propeller
     data                 P3   0x3
     latch                P4   0x4
     clk                  P5   0x5
}

\ j ( -- n1 ) the second most current loop counter
: j _rsptr COG@ 5 + COG@ ;
: variable lockdict create $C_a_dovarl w, 0 l, forthentry freedict ; 

\  Edit 3 constant below to match your hardware
3 constant _data
4 constant _latch
5 constant _clk

wvariable char           \ character number for LCD:x           
wvariable line           \ line number for LCD:y
wvariable cur_line       \ current line number

1 _data lshift constant _datam
1 _latch lshift constant _latchm 
1 _clk lshift constant _clkm

: _data_out_l _datam _maskoutlo ;
: _data_out_h _datam _maskouthi ;
: _latch_out_l _latchm _maskoutlo ;
: _latch_out_h _latchm _maskouthi ;
: _clk_out_l _clkm _maskoutlo ;
: _clk_out_h _clkm _maskouthi ;

: serial_send
8 0 do
     dup 1 7 i - lshift and  
     0> if _data_out_h else _data_out_l then
     _clk_out_h _clk_out_l                      
     loop
     drop
     _data_out_l
     1 delms
;

\ lcd_com - send command to HD44780   (n -- )
: lcd_com
serial_send
_latch_out_h _latch_out_l
2 delms      
;

\ setup propeller pins and initialize HD44780
: lcd_init
\ set from P**(_data) to P**(_clk) to output
_data 3 0 do dup pinout 1+ loop drop

\ 8bit mode
32 delms       \ wait 50msec
30 serial_send _latch_out_h _latch_out_l
5 delms 
_latch_out_h _latch_out_l
1 delms
_latch_out_h _latch_out_l
5 delms

38 serial_send _latch_out_h _latch_out_l
8 serial_send _latch_out_h _latch_out_l
1 serial_send  _latch_out_h _latch_out_l
6 serial_send _latch_out_h _latch_out_l
c serial_send _latch_out_h _latch_out_l
10 char W! 2 line W!          \ defsult setting is 16Charcters & 2Lines
;

\ setup of display construction  (x y -- )
: lcd_setup line W! char W! ;
\ display character 
: lcd_char
serial_send _data_out_h _latch_out_h _latch_out_l _data_out_l
2 delms      
;

\ display string  ( cstr -- )
: lcd_str C@++ dup if bounds do i C@ lcd_char loop else 2drop then ;
\ clear lcd
: lcd_clear 1 lcd_com ;

{
x -- horizontal pos  : 0x1 to 0x28 (decimal: 1 to 40Characters)
y -- line number     : 0x1 to 0x4  (decimal: 1 to 4Lines)
( x y -- )
}
: lcd_pos
2 u/mod swap 0= 
if 1 =     \ line is even?
     if 40 else char W@ 10 = if 50 else 54 then then
else 0=
     if 0 else char W@ 10 = if 10 else  14 then then 
then
\ 1- + dup . 80 or lcd_com
1- + 80 or lcd_com
;

\ output cr
: LCD_cr cur_line W@ 1+ dup line W@ > if drop 1 1 lcd_pos 1 cur_line W! else dup 1 swap lcd_pos cur_line W! then ;

\ display decimal number to covert hex (n -- )  n:hex-value
variable tmp
wvariable result     
: lcd_dec
0 result W! 3b9aca00 tmp L!
dup 80000000 and if invert 1+ 2d lcd_char then         \ check minus?  
a 0 do dup tmp L@ >= if tmp L@ u/mod 30 + lcd_char 1 result W! 
                     else result W@ tmp L@ 1 = or if 30 lcd_char then
                     then
                     tmp L@ a u/ tmp L! 
    loop
drop
;

\ display hex number  (n1 n2 -- ) n1:hex-value  n2:digits(1 to 8)
: lcd_hex
dup rot2 8 swap - 2 lshift lshift swap
0 do dup f0000000 and 1c rshift dup a < if 30 + else 37 + then lcd_char 4 lshift loop
drop
;
\ display binary number (n1 n2 -- ) n1:hex-value  n2:digits(1 to 10)
: lcd_bin
dup rot2 20 swap - lshift swap  
0 do dup 80000000 and if 31 else 30 then lcd_char 1 lshift loop 
drop
;

\ output spaces  ( n -- ) n:space's number output to LCD 
: lcd_blank dup if 0 do bl lcd_char loop else drop then ;


: set_bar_graph
20 40
6 0 do              \ set 6 charcters
       8 0 do       \ set 8 lines for 1 character
              dup lcd_com     \ command for character to CG-RAM
              swap dup lcd_char swap    \ write data
              1+    
           loop
           f8 and   
       swap dup 1 rshift or swap
    loop
2drop
;

: demo
lcd_init
 10 4 lcd_setup      \ 16characters 4line

\ display char-code [0x20 - 0x7f] & [0xa0 - 0xff]
20
line W@ 2 = if 7 0 else 3 0 then
do
        line W@ 2 = if i 3 = if 4 seti drop a0 then 
                       2 0 
                    else 4 0 
                    then
        do line W@ 4 = if j 1 = if i 2 = if 20 + then then then 
           1 i 1+ lcd_pos 10 0 do dup lcd_char 100 delms 1+ loop loop
    loop  
drop
lcd_clear 
\ display binary, hex, decimal
c" 0x1+0x6 = b" lcd_str 1 6 + 4 lcd_bin

1 2 lcd_pos
c" 0xACE+0xF=0x" lcd_str ace f + 4 lcd_hex
5 delsec

lcd_clear  1 cur_line W!
c" 0x12+0xe0=" lcd_str
12 e0 + lcd_dec c" (D)" lcd_str
LCD_cr

c" 0x0-0x12=" lcd_str
0 12 - lcd_dec c" (D)" lcd_str
5 delsec

set_bar_graph
lcd_clear
c" Bar Graph" lcd_str 
1    \ x-position 
char W@ 0
do 
  0 
  6 0 do dup lcd_char 1+ 64 delms swap dup 2 lcd_pos swap loop drop
  1+ dup 2 lcd_pos       \ increment x-position 
loop
drop

char W@ 2 lcd_pos
char W@
char W@ 0
do
  5
  6 0 do dup lcd_char 1- 64 delms swap dup 2 lcd_pos swap loop drop
  1- dup 2 lcd_pos 
loop
drop

lcd_clear
c" Demo Finished" lcd_str
1 2 lcd_pos
b3 c4 de b6 d8 b1 20 c6 b7 b5 b5 b 0 do lcd_char loop
;


: set_bar_graph2
40
8 0 do              \ set 8 charcters
      8 0 do        \ set 8 lines for 1 character
            dup lcd_com     \ command for character to CG-RAM 
            7 j - i <
            if 1f else 0 then lcd_char     \ write data
            1+ 
          loop
          f8 and
    loop
drop
;

variable tmp1
: demo2
lcd_init
 10 4 lcd_setup      \ 16characters 4line
set_bar_graph2
lcd_clear
c" Wave" lcd_str
1 2 lcd_pos
1 tmp L! 1 tmp1 L!
0
100 0 do
     dup char W@ 0 do dup lcd_char dup 7 = tmp L@ 1 = and 
                                             if drop ff
                                             else dup ff = if drop 7 -1 tmp L!    
                                                            else dup 0 = if 1+ 1 tmp L!
                                                                         else tmp L@ + 
                                                                         then
                                                            then
                                             then
         loop
     drop
     1 2 lcd_pos
     dup 7 = tmp1 L@ 1 = and 
               if drop ff
               else dup ff = if drop 7 -1 tmp1 L!
                             else dup 0 = if 1+ 1 tmp1 L!
                                          else tmp1 L@ +
                                          then
                             then             
               then
              
loop
drop                           
;                                        
     
: demo3
lcd_init
 10 4 lcd_setup      \ 16characters 4line
lcd_clear
c" PropForth4.0a" lcd_str
1 2 lcd_pos
100 0 do
     c" PropForth4.0a" lcd_str
     1 2 lcd_pos
     d lcd_blank
     1 2 lcd_pos
loop
c" PropForth4.0a" lcd_str     
;

: time cnt COG@ 41 lcd_char cnt COG@ swap - . ;