augustinetez
Active Member
I'm in the process of writing a program that works fine on an HD44780 2x16 LCD but transferring it to a ST7066U based 20x4 LCD is driving me nuts.
There's two problems but I will deal with one here and start another thread for the other once this one is sorted.
To explain the program first, it is a very simple controller for an SAA1057 based transmitter (old school stuff).
The first line on the LCD just displays the title and the second line displays "Freq: 87.00MHz" and the numbers increment/decrement as you turn a rotary encoder and sends the control data to the chip.
As I said above, works fine on a 2x16 LCD, but on the 20x4 LCD (after finally getting the inialisation sequence right), it will display the text, but the numbers remain static instead of incrementing/decrementing when the encoder is turned.
I'm 99.9% sure it is just a timing problem but for the life of me just can't see it, so hopefully a fresh set of eyes can help pinpoint it.
There is a Busy Check routine in the code below commented out as that is the second problem and I'm just using software delays at the moment.
There's two problems but I will deal with one here and start another thread for the other once this one is sorted.
To explain the program first, it is a very simple controller for an SAA1057 based transmitter (old school stuff).
The first line on the LCD just displays the title and the second line displays "Freq: 87.00MHz" and the numbers increment/decrement as you turn a rotary encoder and sends the control data to the chip.
As I said above, works fine on a 2x16 LCD, but on the 20x4 LCD (after finally getting the inialisation sequence right), it will display the text, but the numbers remain static instead of incrementing/decrementing when the encoder is turned.
I'm 99.9% sure it is just a timing problem but for the life of me just can't see it, so hopefully a fresh set of eyes can help pinpoint it.
There is a Busy Check routine in the code below commented out as that is the second problem and I'm just using software delays at the moment.
Code:
;
; *******************************************************************************
; * SAA1057 Tx controller 20x4 LCD *
; * Version 0.01 *
; * February 2021 *
; * Author: T Mowles VK5TM *
; * Copyright 2021 All Rights reserved. *
; *******************************************************************************
;
; *******************************************************************************
; * Description: *
; * SAA1057 FM transmitter controller software *
; *******************************************************************************
;
; Target Controller - PIC16F628A
; __________
; SPARE----------------RA2 |1 18| RA1----ENCODER A
; SPARE----------------RA3 |2 17| RA0----ENCODER B
; SPARE----------------RA4 |3 16| RA7----SPARE
; SPARE----------------RA5 |4 15| RA6----SPARE
; Ground---------------Vss |5 14| VDD----+5 V
; LCD D4---------------RB0 |6 13| RB7----SAA1057 DLEN
; LCD D5---------------RB1 |7 12| RB6----LCD_rs (LCD Pin 4)
; LCD D6/1057_CLK------RB2 |8 11| RB5----LCD_rw (LCD Pin 5)
; LCD D7/1057_DATA-----RB3 |9 10| RB4----LCD_e (LCD Pin 6)
; ----------
;
; *******************************************************************************
; * Device type and options. *
; *******************************************************************************
;
processor 16F628A
radix dec
errorlevel -302 ; Skip out of bank nuisance messages
;
; *******************************************************************************
; * Configuration fuse information for 16F628A: *
; *******************************************************************************
include <P16F628A.INC>
__config _CP_OFF&_LVP_OFF&_BODEN_OFF&_MCLRE_OFF&_PWRTE_ON&_WDT_OFF& _INTOSC_OSC_NOCLKOUT
;
; *******************************************************************************
; Info for power-up display
MCODE_REV_0 equ 'V' ;
MCODE_REV_1 equ '0' ;
MCODE_REV_2 equ '.' ;
MCODE_REV_3 equ '0' ;
MCODE_REV_4 equ '1' ;
MCODE_REV_5 equ ' ' ;
MCODE_REV_6 equ ' ' ;
MCODE_REV_7 equ ' ' ;
;
; *******************************************************************************
; * General equates *
; *******************************************************************************
;
; default 0 & 1 contains the default startup frequency as a 16 bit integer.
; control 0 & 1 contains the control word data as a 16 bit integer.
;
default_1 equ 0x21 ; Most significant byte
default_0 equ 0xFC ; Least significant byte (87MHz)
control_1 equ b'11000101' ; Control_1 data 11000101 (MSB)
control_0 equ b'11110101' ; Control_0 data 11110101 (LSB)
;
; *******************************************************************************
; * Setup the initial constants *
; *******************************************************************************
;
ORG 0x2100
;
; startup frequency bytes must be next 4 bytes of EEPROM
DATA default_1 ; startup -> MSB
DATA default_0 ; startup -> LSB
;
; Clear unused EEPROM bytes (128 bytes for 16F628)
;
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;
; *******************************************************************************
; * Assign names to IO pins *
; *******************************************************************************
;
; B register bits:
;
CLK equ 0x02 ; SAA1057 write clock
DAT equ 0x03 ; SAA1057 serial data input
LCD_busy equ 0x03 ; LCD busy bit
LCD_e equ 0x04 ; 0=disable, 1=enable
LCD_rw equ 0x05 ; 0=write, 1=read
LCD_rs equ 0x06 ; 0=instruction, 1=data
DLEN equ 0x07 ; SAA1057 Data load control pin - high to load data
;
; *******************************************************************************
; * Allocate variables in general purpose register space *
; *******************************************************************************
;
CBLOCK 0x20 ; Start Data Block
bit_count ;
byte2send ;
LCD_char ; Character being sent to the LCD
timer1 ; Used in delay routines
CounterA ; "
CounterB ; "
CounterC ; "
CounterD ; "
CounterE ; "
ren_new ; New value of encoder pins A and B
ren_old ; Old value of encoder pins A and B
ren_read ; Encoder pins A and B and switch pin
dir ; Indicates last direction of encoder
next_dir ; Indicates expected direction
count ; loop counter (gets reused)
enc_counter ; Divide by 4 counter for mechanical encoder
rs_value ; The LCD rs line flag value
hcomp
lcomp
NumH
NumL
TenK
Thou
Hund
Tens
Ones
ENDC ; End of Data Block
CBLOCK 0x70
freq_1 ; Use bank common locations - saves bank switching when
freq_0 ; saving/retreiving to/from EEPROM
ENDC ; End of Data Block
;
; *******************************************************************************
; * The 16F628 resets to 0x00 *
; * The Interrupt vector is at 0x04 *
; *******************************************************************************
;
ORG 0x0000
goto start ; Jump around the band table to main program
ORG 0x0004 ;
goto start
;
; *******************************************************************************
; * Purpose: *
; * This is the start of the program *
; * *
; *******************************************************************************
;
start
movlw 0x07 ; Code to turn off the analog comparitors
movwf CMCON ; Turn off comparators
clrf PORTA
clrf PORTB
bsf STATUS,RP0 ; Switch to bank 1
bsf OPTION_REG,7 ; Disable weak pullups
movlw 0xFF ; Tristate PORTA (all Inputs)
movwf TRISA ;
clrf TRISB ; Set port B to all outputs
bcf STATUS,RP0 ; Switch back to bank 0
bcf PORTB,DLEN ; Hold DLEN low
movlw control_1 ; send start sequence or control word (twice) to SAA1057
movwf freq_1
movlw control_0
movwf freq_0
call send_word ; Send it to the SAA1057
call send_word ; twice to initialise chip
;
call init_LCD ; Initialize the LCD
call display_version ; Display title and version
;
; Set the power on frequency to the defined value
;
read_EEocs
call LINE2
bsf STATUS,RP0 ; Switch to bank 1
clrf EEADR ; Reset the EEPROM read address
call read_EEPROM ; Read EEPROM
movf EEDATA,w ; Get the first default freq byte
movwf freq_1 ; Save it
call read_EEPROM ; Read EEPROM
movf EEDATA,w ; Get the next freq byte
movwf freq_0 ; Save it
bcf STATUS,RP0 ; Back to bank 0
; Display the power on frequency
;
call bin2BCD ; Convert it to BCD
call show_freq ; Display it
;
call send_word ; Send the power-on frequency to the
; SAA1057 in serial mode
;
; Get the power on encoder value
;
movf PORTA,w ; Read port A
movwf ren_read ; Save it in ren_read
movlw 0x03 ; Get encoder mask (RA0 and RA1)
andwf ren_read,w ; Get encoder bits
movwf ren_old ; Save in ren_old
;
clrf dir ; Clear the knob direction indicator
;
; Fall into the Main Program Loop
;
; *******************************************************************************
; * Purpose: *
; * This is the Main Program Loop. The program's main loop *
; * calls poll_encoder, which continuously polls the rotary shaft *
; * encoder. When the shaft encoder has changed, the direction *
; * it moved is determined and stored in last_dir. The subroutine *
; * then returns to main. *
; * *
; *******************************************************************************
;
main
call poll_encoder ; Check for knob movement (wait there!)
; Return here when encoder change detected
;
; Based on the knob direction, either increment or decrement the frequency,
; update the LCD and SAA1057.
;
btfsc dir,1 ; Is the knob going up?
goto up ; Yes, then increase frequency
down
call dec_freq ;
goto update ; Update LCD and DDS
up
call inc_freq ;
update
call bin2BCD ; Convert the frequency to BCD
call show_freq ; Display the frequency on the LCD
call send_word ; Send the control word to the chip
goto main ; Continue main loop
;
; *****************************************************************************
; * *
; * Purpose: This routine does the following: *
; * *
; * Reads the encoder bits until a change is detected, then *
; * determines the direction the knob was moved. *
; * *
; * Input: Knob input read from port A *
; * ren_old -> the last encoder bits read *
; * last_dir -> the last direction moved *
; * *
; * Output: ren_new -> the current encoder bits *
; * last_dir -> the last direction (0 = down, 2 = up) *
; * *
; *****************************************************************************
;
poll_encoder
no_inc ;
movf PORTA,w ; Get the current encoder value
movwf ren_read ; Save it
;!!!--- DETENT_ENCODER --- ADDED CODE FOR MECHANICAL ENCODER ----- !!!
call wait_1ms ; debounce time
movf PORTA,w ; read the port again
xorwf ren_read,w ; Compare with previous value
btfss STATUS,Z ; Are they equal?
goto poll_encoder ; Poll again if not
;!!! ------------------------------------------------------------- !!!
movlw 0x03 ; Get encoder mask (to isolate RA0 and RA1)
andwf ren_read,w ; Isolated encoder bits into W
movwf ren_new ; Save new value
xorwf ren_old,w ; Has it changed?
btfsc STATUS,Z ; Check zero-flag (zero if no change)
goto poll_encoder ; No change, keep looking until it changes
; ; Zero-flag is not set, so continue on
bcf STATUS,C ; Clear the carry bit to prepare for rotate
rlf ren_old,f ; Rotate old bits left to align "Right-Bit"
movf ren_new,w ; Set up new bits in W
xorwf ren_old,f ; XOR old (left shifted) with new bits
movf ren_old,w ; Put XOR results into W also
andlw 0x02 ; Mask to look at only "Left-Bit" of pair
movwf next_dir ; Save result (in W) as direction (bit=UP)
xorwf dir,w ; See if direction is same as before
pe_continue
clrf dir ; Clear last_dir (default is DN)
btfsc ren_old,1 ; Are we going UP?
goto up2 ; No, exit3
;!!! --- DETENT_ENCODER --- ADDED CODE FOR MECHANICAL ENCODER ----- !!!
movf ren_new,w ; Get the current encoder bits
movwf ren_old ; Save them in ren_old for the next time
decf enc_counter,f ; decrement the inter-detent counter
btfsc enc_counter,0 ; Check if bit 0 is cleared
goto poll_encoder ; If not, then poll some more
btfsc enc_counter,1 ; Else, check if bit 1 is cleared
goto poll_encoder ; If not, then poll some more
; Else, assume the encoder is on a detent
;!!! -------------------------------------------------------------- !!!
goto exit3
up2
movlw 0x02 ; Get UP value
movwf dir ; and set in last_dir
;!!! --- DETENT_ENCODER --- ADDED CODE FOR MECHANICAL ENCODER ----- !!!
movf ren_new,w ; Get the current encoder bits
movwf ren_old ; Save them in ren_old for the next time
incf enc_counter,f ; Increment the encoder counter
btfsc enc_counter,0 ; Return only on modulo 4 counts
goto poll_encoder ;
btfsc enc_counter,1
goto poll_encoder ; Loop again if not modulo 4
;!!! -------------------------------------------------------------- !!!
exit3
movf ren_new,w ; Get the current encoder bits
movwf ren_old ; Save them in ren_old for the next time
return ; Return to the caller
;
; *******************************************************************************
; * Purpose: *
; * Increment frequency 16 bit inc/dec From Scott Dattalo *
; * *
; *******************************************************************************
;
inc_freq
incf freq_1,f
incfsz freq_0,f
decf freq_1,f
MOVLW low 10800 ; Initialize a 16 bit value
MOVWF lcomp
MOVLW high 10800
MOVWF hcomp
call COMP ; Test if frequency is above 108MHz
addlw 0x00 ; Test if 'w'is 0 or 1
btfsc STATUS,Z ; The Z or Zero bit is set to "1" when the result
return ; of an arithmetic or logical operation is zero
MOVLW low 10800 ; Initialize a 16 bit value
MOVWF freq_0
MOVLW high 10800
MOVWF freq_1
return
;
; *******************************************************************************
; * Purpose: *
; * Decrement the freq, checking that it does not go below lowest freq *
; * *
; *******************************************************************************
;
dec_freq
movf freq_0,f
skpnz
decf freq_1,f
decf freq_0,f
MOVLW low 8700 ; Initialize a 16 bit value
MOVWF lcomp
MOVLW high 8700
MOVWF hcomp
call COMP ; Test if frequency is below 87MHz
addlw 0x00 ; Test if 'w'is 0 or 1
btfss STATUS,Z ; The Z or Zero bit is set to "1" when the result
return ; of an arithmetic or logical operation is zero
MOVLW low 8700 ; Initialize a 16 bit value
MOVWF freq_0
MOVLW high 8700
MOVWF freq_1
return
;
; *******************************************************************************
; * Purpose: *
; * Check if freq exceeds upper or lower limit *
; * *
; * A not too optimised 16 bit compare routine for 16bit absolute values, *
; * ie 0 -> 65536. Antonio L Benci (PIClist) *
; * Compare WORD to COMP (a word value). *
; * If WORD = COMP return with 00 *
; * If WORD > COMP return with 01 *
; * If WORD < COMP return with 00 *
; *******************************************************************************
;
COMP
movfw hcomp ; get high byte of comp value
subwf freq_1,w ; subtract values
btfsc STATUS,Z ; first check if result is 0
goto COMPL ; if zero compare low bytes
btfsc STATUS,C ; else test carry bit
retlw 0x01 ; if WORD > COMP, return with 01h
retlw 0x00 ; if WORD < COMP, return with 00h
COMPL
movfw lcomp ; get low byte of comp value
subwf freq_0,w ; subtract values
btfsc STATUS,Z ; first check if result is 0
retlw 0x00 ; if result is 0, return with 00
btfsc STATUS,C ; if c set then WORD > COMP
retlw 0x01 ; if WORD > COMP, return with 01h
retlw 0x00 ; if WORD < COMP, return with 00h
;
; *******************************************************************************
; * Purpose: *
; * This routine sends data to the SAA1057 using serial data transfer mode *
; * *
; * To send data:- *
; * Set Clock low *
; * *
; * Set DLEN high *
; * *
; * Set Data low *
; * *
; * Send clock bit ->high->low *
; * *
; * 1 Get Data bit from file *
; * *
; * Send clock bit ->high->low *
; * *
; * Repeat from 1 for remaining bits *
; * *
; * Set DLEN low *
; * *
; * Send clock bit ->high->low *
; * *
; * End of sequence *
; * *
; *******************************************************************************
;
send_word
bcf PORTB,CLK ; Set clock low
NOP
bsf PORTB,DLEN ; Set data load high
NOP
bcf PORTB,DAT ; Set Data low
NOP
bsf PORTB,CLK ; Toggle write clock
NOP
bcf PORTB,CLK ;
movlw freq_1 ; Point FSR at most Significant Byte
movwf FSR ;
next_byte
movf INDF,w ;
movwf byte2send ;
movlw 0x08 ; Set counter to 8
movwf bit_count ;
next_bit
rlf byte2send,f ; Test if next bit is 1 or 0
btfss STATUS,C ; Was it zero?
goto send0 ; Yes, send zero
bsf PORTB,DAT ; No, send one
goto break ;
send0
bcf PORTB,DAT ; Send zero
NOP
break
bsf PORTB,CLK ; Toggle write clock
NOP
bcf PORTB,CLK ;
decfsz bit_count,f ; Has the whole byte been sent?
goto next_bit ; No, keep going
incf FSR,f ; Start the next byte unless finished
movlw freq_0+1 ; Next byte (past the end)
subwf FSR,w ;
btfss STATUS,C ;
goto next_byte ;
bcf PORTB,DLEN ; Send load signal to the SAA1057
NOP
bsf PORTB,CLK ; Toggle write clock
NOP
bcf PORTB,CLK ;
return
;
; *******************************************************************************
; * Purpose: *
; * Power on initialization of Liquid Crystal Display *
; * The LCD controller chip must be equivalent to an Hitachi 44780 *
; * *
; *******************************************************************************
;
init_LCD
movlw 100
call wait ; Wait for LCD to power up
; call wait_1ms
; Put 4-bit command in RB3..RB0
; PIC's RB3..RB0 lines connect to LCD's DB7..DB4 (pins 14-11)
movlw 0x03 ; LCD init instruction (First)
movwf PORTB ; Send to LCD via RB3..RB0
bsf PORTB,LCD_e ; Set the LCD E line high,
call wait_1ms
bcf PORTB,LCD_e ; and then Clear E
movlw 100
call wait ; wait a "long" time,
movlw 0x03 ; LCD init instruction (Second)
movwf PORTB ; Send to LCD via RB3..RB0
bsf PORTB,LCD_e ; Set E high,
call wait_1ms
bcf PORTB,LCD_e ; and then Clear E
movlw 32
call wait ; wait a while,
movlw 0x03 ; LCD init instruction (Third)
movwf PORTB ; Send to LCD via RB3..RB0
bsf PORTB,LCD_e ; Set E high,
call wait_1ms
bcf PORTB,LCD_e ; and then Clear E
movlw 32
call wait ; wait a while,
movlw 0x02 ; 4-bit mode instruction
movwf PORTB ; Send to LCD via RB3..RB0
bsf PORTB,LCD_e ; Set E high,
call wait_1ms
bcf PORTB,LCD_e ; and then Clear E
movlw 16
call wait ; wait a while,
movlw 0x28 ; 1/16 duty cycle, 5x8 matrix
call cmnd2LCD ; Send command in w to LCD
call wait_1ms
movlw 0x08 ; Display off, cursor and blink off
call cmnd2LCD ; Send command to LCD
call wait_1ms
movlw 0x01 ; Clear and reset cursor
call cmnd2LCD ; Send command in w to LCD
movlw 2
call wait ; wait a while,
movlw 0x06 ; Set cursor to move right, no shift
call cmnd2LCD ; Send command in w to LCD
call wait_1ms
movlw 0x0C ; Display on, cursor and blink off
call cmnd2LCD ; Send command in w to LCD
return ;
;
; ****************************************************************************P
; * P
; * Purpose: Display version and other info on LCD for 2 seconds P
; * upon power-up P
; * P
; * Input: MCODE_REV_0 through MCODE_REV_4 set up P
; * P
; * Output: LCD displays debug info P
; * P
; ****************************************************************************P
;
display_version
movlw 0x80 ; Point LCD at digit 1
call cmnd2LCD ;
movlw 'S' ; digit 1
call data2LCD ;
movlw 'A' ; digit 2
call data2LCD ;
movlw 'A' ; digit 3
call data2LCD ;
movlw '1' ; digit 4
call data2LCD ;
movlw '0' ; digit 5
call data2LCD ;
movlw '5' ; digit 6
call data2LCD ;
movlw '7' ; digit 7
call data2LCD ;
movlw ' ' ; digit 8
call data2LCD ;
movlw MCODE_REV_0 ; Get mcode rev byte
call data2LCD ; and display it (digit 9)
movlw MCODE_REV_1 ; Get mcode rev byte
call data2LCD ; and display it (digit 10)
movlw MCODE_REV_2 ; Get mcode rev byte
call data2LCD ; and display it (digit 11)
movlw MCODE_REV_3 ; Get mcode rev byte
call data2LCD ; and display it (digit 12)
movlw MCODE_REV_4 ; Get mcode rev byte
call data2LCD ; and display it (digit 13)
movlw MCODE_REV_5 ; Get mcode rev byte
call data2LCD ; and display it (digit 14)
movlw MCODE_REV_6 ; Get mcode rev byte
call data2LCD ; and display it (digit 15)
movlw MCODE_REV_7 ; Get mcode rev byte
call data2LCD ; and display it (digit 16)
call wait_a_sec ; Wait one second
LINE2
movlw 0xC0 ; Point LCD at digit 1 of second line
call cmnd2LCD ;
movlw 'F' ; digit 1
call data2LCD ;
movlw 'R' ; digit 2
call data2LCD ;
movlw 'E' ; digit 3
call data2LCD ;
movlw 'Q' ; digit 4
call data2LCD ;
movlw ':' ; digit 5
call data2LCD ;
movlw ' ' ; digit 6 0xC5
call data2LCD ;
movlw ' ' ; digit 7
call data2LCD ;
movlw ' ' ; digit 8
call data2LCD ;
movlw ' ' ; digit 9
call data2LCD ;
movlw ' ' ; digit 10
call data2LCD ;
movlw ' ' ; digit 11
call data2LCD ;
movlw 'M' ; digit 12
call data2LCD ;
movlw 'H' ; digit 13
call data2LCD ;
movlw 'z' ; digit 14
call data2LCD ;
movlw ' ' ; digit 15
call data2LCD ;
movlw ' ' ; digit 16
call data2LCD ;
return
; *******************************************************************************
; * Purpose: *
; * This subroutine converts a 16 bit binary number to decimal in *
; * TenK, Thou, Hund, Tens, Ones *
; * Written by John Payson. *
; *******************************************************************************
;
bin2BCD ; Takes number in freq_1:freq_0 returns decimal in TenK:Thou:Hund:Tens:Ones
movfw freq_1
movwf NumH
movfw freq_0
movwf NumL
swapf NumH,w
IORLW 0xF0
movwf Thou
addwf Thou,f
addlw 0xE2
movwf Hund
addlw 0x32
movwf Ones
movf NumH,w
andlw 0x0F
addwf Hund,f
addwf Hund,f
addwf Ones,f
addlw 0xE9
movwf Tens
addwf Tens,f
addwf Tens,f
swapf NumL,w
andlw 0x0F
addwf Tens,f
addwf Ones,f
rlf Tens,f
rlf Ones,f
comf Ones,f
rlf Ones,f
movf NumL,w
andlw 0x0F
addwf Ones,f
rlf Thou,f
movlw 0x07
movwf TenK
; At this point, the original number is equal to TenK*10000+Thou*1000+Hund*100+Tens*10+Ones
; if those entities are regarded as two's compliment binary.
; To be precise, all of them are negative except TenK.
; Now the number needs to be normalized, but this can all be done with simple byte arithmetic.
movlw 0x0A ; Ten
Lb1:
addwf Ones,f
decf Tens,f
btfss STATUS,C
goto Lb1
Lb2:
addwf Tens,f
decf Hund,f
btfss STATUS,C
goto Lb2
Lb3:
addwf Hund,f
decf Thou,f
btfss STATUS,C
goto Lb3
Lb4:
addwf Thou,f
decf TenK,f
btfss STATUS,C
goto Lb4
return
;
; *******************************************************************************
; * Purpose: *
; * Display the frequency on the LCD. *
; * *
; *******************************************************************************
;
show_freq
movlw 0xC5 ; Point the LCD to digit location
call cmnd2LCD ; Send digit location to LCD
;
movfw TenK
addlw 0x00 ; Test if 'w'is 0 or 1
btfss STATUS,Z ; The Z or Zero bit is set to "1" when the result
goto $+4 ; of an arithmetic or logical operation is zero
movlw ' ' ; TenK = 0, insert space
call data2LCD ; Send byte in W to LCD
goto $+2
; movfw TenK ; TenK is not 0, insert number
call process ;
movfw Thou
call process ;
movfw Hund
call process ;
movlw '.' ; insert seperator
call data2LCD ; Send byte in W to LCD
movfw Tens
call process ;
movfw Ones
call process ;
return
process
addlw 0x30
call data2LCD
return
;
; *******************************************************************************
; * Purpose: *
; * Send Command or Data byte to the LCD *
; * Entry point cmnd2LCD: Send a Command to the LCD *
; * Entry Point data2LCD: Send a Data byte to the LCD *
; * *
; *******************************************************************************
;
cmnd2LCD ; ****** Entry point ******
clrf rs_value ; Remember to clear RS (clear rs_value)
goto write2LCD ; Go to common code
data2LCD ; ****** Entry point ********
bsf rs_value,0 ; Remember to set RS (set bit 0 of rs_value)
write2LCD
movwf LCD_char ; Save byte to write to LCD
; call busy_check ; Check to see if LCD is ready for new data
call wait_1ms
MOVLW 2 ;
MOVWF count ; SET UP LOOP COUNTER
write_again
SWAPF LCD_char,F ; SWAP MS & LS NIBBLES
MOVF LCD_char,W
ANDLW 15 ; MAKE TOP 4 BITS OF W 0
MOVWF PORTB ; SEND MS NIBBLE
bcf PORTB,LCD_rs ; Guess RS should be clear - command mode
btfsc rs_value,0 ; Should RS be clear? (is bit 0 == 0?)
bsf PORTB,LCD_rs ; No, set RS - data mode
NOP
BSF PORTB,LCD_e ; SET E HIGH
NOP
BCF PORTB,LCD_e ; SET E LOW
DECFSZ count,F
GOTO write_again ; GO BACK AND SEND LS NIBBLE
return
;
; *******************************************************************************
; * Purpose: *
; * Check if LCD is done with the last operation. *
; * This subroutine polls the LCD busy flag to determine if previous *
; * operations are completed. *
; * *
; *******************************************************************************
;
;busy_check
; clrf PORTB ; Clear all outputs on PORTB
; banksel TRISB ; Switch to bank for Tris operation
; movlw b'00001000' ; Set RB3 input, others outputs
; movwf TRISB ;
;
; banksel PORTB
; bcf PORTB,LCD_rs ; Set up LCD for Read Busy Flag (RS = 0)
; nop
; bsf PORTB,LCD_rw ; Set up LCD for Read (RW = 1)
; nop ;
; bsf PORTB,LCD_e ; Set E high
; nop
; bcf PORTB,LCD_e ; Drop E again
;
;LCD_is_busy
; call wait_100us ;
; bsf PORTB,LCD_e ; Set E high
; nop
; bcf PORTB,LCD_e ; Drop E again
;
; btfss PORTB,LCD_busy ; Is Busy Flag (RB3) clear?
; goto not_busy ; Yes - exit
; nop ; No
; nop ; Wait a while
;
; bsf PORTB,LCD_e ; Pulse E high (dummy read of lower nibble),
; nop ; wait,
; bcf PORTB,LCD_e ; and drop E again
;
; goto LCD_is_busy ; If not, it is busy so jump back
;
;not_busy
; banksel TRISB ; Switch to bank 1 for Tristate operation
; clrf TRISB ; All pins (RB7..RB0) are back to outputs
; banksel PORTB ; Switch to bank 0
; clrf PORTB ; Clear all of Port B (inputs and outputs)
; return
;
; *****************************************************************************
; * *
; * Purpose: Read a byte of EEPROM data at address EEADR into EEDATA. *
; * *
; * Input: The address EEADR. *
; * *
; * Output: The value in EEDATA. *
; * *
; * NOTE: All in BANK 1 *
; *****************************************************************************
;
read_EEPROM
bsf EECON1,RD ; Request the read
movf EEDATA,W ; Get the data
incf EEADR,f ; Increment the read address
return ; Return to the caller
;
; *******************************************************************************
; * *
; * Purpose: Delay routines *
; * *
; *******************************************************************************
;
wait_a_sec ;PIC Time Delay = 0.99999900 s with Osc = 4000000 Hz
movlw D'6'
movwf CounterC
movlw D'19'
movwf CounterB
movlw D'172'
movwf CounterA
loop
decfsz CounterA,f
goto loop
decfsz CounterB,f
goto loop
decfsz CounterC,f
goto loop
return
wait
movwf timer1 ; Set up counter
call wait_1ms ; Go to wait loops
decfsz timer1,f
goto $-2
return
wait_1ms ;PIC Time Delay = 0.00099800 s with Osc = 4MHz
movlw D'2'
movwf CounterD
movlw D'73'
movwf CounterE
loop1
decfsz CounterE,f
goto loop1
decfsz CounterD,f
goto loop1
return
wait_100us ;PIC Time Delay = 0.00009800 s with Osc = 4000000 Hz
movlw D'31'
movwf CounterA
loop2
decfsz CounterA,1
goto loop2
return
;
; *****************************************************************************
;
END