Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

ST7066U 20x4 LCD problems(Solved)

Status
Not open for further replies.
And Mike - thinking out loud (interrupts and me have a very strained relationship) - why are we doing the freq limit compares in the ISR code instead of calling my existing inc/dec/compare routines from the ISR code? That would leave the freq 0 & 1 variables correctly set when the interrupt returns back to normal program flow instead of having to copy them across.
 
The reason everything is done in the ISR is so it is always completed and a compare or inc/dec isn't interrupted and the value changed half way through by the ISR. To use existing code would require lots of disabling and enabling of interrupts all over the code. As is, the interrupts only get disabled while the value is copied. It's also not a good idea to call subroutines in the ISR due to the limited stack size.

Mike.
Edit, note that I changed the ISR code above.
 
Just so it shows as unread and you're sure to see this I've added this new post.

I just spotted a couple of mistakes in the ISR code and have corrected them so if you're trying it now, recopy the code from the earlier post.

Mike.
 
One of the clrf clicks was in the wrong place so I've changed it again - sorry.

Mike.
 
Got the change, but my integration of this has completely conveyed the order of King Richard to it - it's had the dick.

I've set startup frequency to be 108, but it is displaying 573.4somethingMHz and the encoder is doing nada (using the 16x2 display until I sort the other problem) .

slashes delineate the where I have put the various bits of code.

Going to take the dog for a walk before I start throwing things, back in ~1/2 hour.


C:
;
; *******************************************************************************
; *    LCD test program V7                            *
; *    Version 0.01                                *
; *    March 2021                                *
; *    Author: T Mowles VK5TM                            *
; *******************************************************************************
;
;                                                                             
;    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----SPARE                   
;    LCD D5------RB1 |7       12| RB6----LCD_rs  (LCD Pin 4)         
;    LCD D6------RB2 |8       11| RB5----LCD_rw  (LCD Pin 5)           
;    LCD D7------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)
default_1 equ 0x2A        ; Most significant byte
default_0 equ 0x30        ; Least significant byte (108MHz)

control_1 equ b'11000101'    ; Control_1 data 11000101 (MSB)
control_0 equ b'11110101'    ; Control_0 data 11110101 (LSB)

    ORG    0x2100
;
;    startup frequency bytes must be next 4 bytes of EEPROM
    DATA    default_1    ; startup -> MSB
    DATA    default_0    ; startup -> LSB
;
; *******************************************************************************
; *    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
    LCD_char        ; Character being sent to the LCD
    timer1            ; Used in delay routines
    CounterA        ;   "
    CounterB        ;   "
    CounterC        ;   "
    CounterD        ;   "
    CounterE        ;   "
    count            ; loop counter  (gets reused)
    rs_value        ; The LCD rs line flag value
    NumH
    NumL
    hcomp
    lcomp
    TenK
    Thou
    Hund
    Tens
    Ones
    byte2send
    bit_count
    previous
    temp
    clicks
    freqHigh
    freqLow
    W_TEMP
    STATUS_TEMP
    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        ;

    ORG    0x0004        ;
    GOTO    ISR
;
enc_table
    addwf    PCL,f        ;index into table
    dt    0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0
;
; *******************************************************************************
; * Purpose:                                    *
; *    This is the start of the program                    *
; *                                        *
; *******************************************************************************
;
start
    clrf    PORTA
    clrf    PORTB
    movlw    0x07        ; Code to turn off the analog comparators
    movwf    CMCON        ; Turn off comparators

    banksel    TRISA        ; Switch to bank 1
    movlw    0xFF        ; Tristate PORTA (all Inputs)
    movwf    TRISA        ;
    clrf    TRISB        ; Set port B to all outputs
    banksel    PORTB        ; Switch back to bank 0
    clrf    PORTB

    movlw    control_1    ; send start sequence or control word 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

read_EEocs            ; Get the power on frequency
    banksel    EEADR        ; 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
    banksel    PORTB        ; Switch back to bank 0

;////////////////////////////////////////////////////////////////////////////////
    MOVFW    freq_0
    MOVWF    freqLow
    MOVFW    freq_1
    MOVWF    freqHigh
;////////////////////////////////////////////////////////////////////////////////

;
    call    bin2BCD        ; Convert it to BCD

    call    init_LCD    ; Initialize the LCD
    call    display_version

    call    show_freq    ; Display the frequency on the LCD
    call    wait_250

    movfw    PORTA
    movwf    previous

;////////////////////////////////////////////////////////////////////////////////
initTmr2
    ;using internal 4MHz clock = 1MHz instruction time
    ;prescaler = 4 = clocked at 250kHz
    ;PR2 = 249        will clock around every 250 cycles
    ;postscaler = 5 = clock every 250*4*5 = 5000 cycles = 5mS interrupt
    MOVLW    B'00100101'
    MOVWF    T2CON
    BSF    STATUS,RP0
    MOVLW    249
    MOVWF    PR2
    BSF    PIE1,TMR2IE
    BCF    STATUS,RP0
    BSF    STATUS,PEIE
    BSF    STATUS,GIE
;    RETURN
;////////////////////////////////////////////////////////////////////////////////
;
main
;////////////////////////////////////////////////////////////////////////////////
GETfreq
    BCF    STATUS,GIE
    MOVFW    freqLow
    MOVWF    freq_0
    MOVFW    freqHigh
    MOVWF    freq_1
;    BSF    STATUS,GIE
;    RETURN
;////////////////////////////////////////////////////////////////////////////////
;
;    Based on the knob direction, either increment or decrement the frequency,
;    update the LCD and SAA1057.
;
;down
;    clrf    clicks
;    call    dec_freq    ;
;    goto    update        ; Update LCD
;up
;    clrf    clicks
;    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
    BSF    STATUS,GIE
    goto    main        ; Continue main loop

;////////////////////////////////////////////////////////////////////////////////
;note W_TEMP and STATUS_TEMP need to be in the common area (above 0x70)
ISR
    MOVWF    W_TEMP        ; SAVE OFF CURRENT W REGISTER CONTENTS
    MOVF    STATUS,W    ; MOVE STATUS REGISTER INTO W REGISTER
    MOVWF    STATUS_TEMP    ; SAVE OFF CONTENTS OF STATUS REGISTER
    BCF    STATUS,RP0
    BCF    PIR1,TMR2IF
    RLF    previous,F
    RLF    previous,W
    ANDLW    0X0C        ;KEEP ONLY BITS 2 & 3
    BTFSS    PORTA,0        ;MOVE ENCODER BITS
    IORLW    1        ;TO BITS 0 & 1
    BTFSS    PORTA,1
    IORLW    2
    MOVWF    previous    ;KEEP FOR NEXT TIME
    CALL    enc_table
    ADDWF    clicks,F
    MOVLW    4
    XORWF    clicks,W
    BTFSS    STATUS,Z
    GOTO    CHECK_DOWN
    CLRF    clicks
    MOVLW    high 10800    ;test if frequency has reached 108MHz
    XORWF    freqHigh,W
    BTFSS    STATUS,Z
    GOTO    DOINC        ;high bytes don't match so do increment
    MOVLW    low 10800
    XORWF    freqLow,W
    BTFSC    STATUS,Z    ;low bytes don't match so do increment
    GOTO    EXIT        ;if it has, exit
DOINC
    INCF    freqHigh,F    ;if not then increment it
    INCFSZ    freqLow,F
    DECF    freqHigh,F
    GOTO    EXIT
CHECK_DOWN
    MOVLW    0XFC        ;-4
    XORWF    clicks,W
    BTFSC    STATUS,Z
    GOTO    EXIT
    CLRF    clicks
    MOVLW    high 8700
    XORWF    freqHigh,W
    BTFSC    STATUS,Z
    GOTO    DODEC
    MOVLW    low 8700
    XORWF    freqLow,W
    BTFSS    STATUS,Z
    GOTO    EXIT
DODEC
    MOVF    freqLow,F
    SKPNZ
    DECF    freqHigh,F
    DECF    freqLow,F
;    GOTO        EXIT
;         RESTORE CONTEXT BEFORE RETURNING FROM INTERRUPT
EXIT
    MOVF    STATUS_TEMP,W    ; RETRIEVE COPY OF STATUS REGISTER
    MOVWF    STATUS        ; RESTORE PRE-ISR STATUS REGISTER CONTENTS
    SWAPF    W_TEMP,F
    SWAPF    W_TEMP,W    ; RESTORE PRE-ISR W REGISTER CONTENTS
    RETFIE            ; RETURN FROM INTERRUPT
;////////////////////////////////////////////////////////////////////////////////
;;
;; *******************************************************************************
;; * 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    ;
    clrf    PORTB        ;
    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    not_zero    ; of an arithmetic or logical operation is zero

    movlw    ' '        ; TenK = 0, insert space
    call    data2LCD    ; Send byte in W to LCD
    goto    show_thou

not_zero
    call    process        ; TenK is not 0, insert number

show_thou
    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:                                    *
; *    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 (100mS)

;    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,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us

    movlw    0x03        ; LCD init instruction (Second)             
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set E high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us

    movlw    0x03        ; LCD init instruction (Third)               
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set E high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us    ; wait a while,

    movlw    0x02        ; 4-bit mode instruction                     
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set E high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us    ; wait a while,

    movlw    0x28        ; 1/16 duty cycle, 5x8 matrix
    call    cmnd2LCD    ; Send command in w to LCD

    call    wait_100us

;    movlw    0x08        ; Display off, cursor and blink off
;    movlw    0x0C        ; Display on, cursor and blink off
    movlw    0x0E        ; Display on, cursor on and blink off
;    movlw    0x0F        ; Display on, cursor and blink on
    call    cmnd2LCD    ; Send command to LCD

    call    wait_100us

    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

    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_100us

    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
    clrf    PORTB
    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
;
; ****************************************************************************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)

    nop

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:  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_250
    movlw    250

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'74'
    movwf    CounterE
loop1
    decfsz    CounterE,f
    goto    loop1
    decfsz    CounterD,f
    goto    loop1
    return

wait_100us    ;PIC Time Delay = 0.00009800 s with Osc = 4MHz
    movlw    D'31'
    movwf    CounterA
loop2
    decfsz    CounterA,1
    goto    loop2
    return
;       
; *****************************************************************************
;
    END
 
I guess you missed my little note,
;note W_TEMP and STATUS_TEMP need to be in the common area (above 0x70)

These not being in the common area will cause a random crash if an interrupt happens whilst in bank 1. Not very likely but a bug that will bite some time in the future.

In this bit of code,
Code:
;////////////////////////////////////////////////////////////////////////////////
GETfreq
    BCF    STATUS,GIE
    MOVFW    freqLow
    MOVWF    freq_0
    MOVFW    freqHigh
    MOVWF    freq_1
;    BSF    STATUS,GIE
;    RETURN
;////////////////////////////////////////////////////////////////////////////////
You've remmed out the line that re-enables interrupts therefore, no interrupts. However, you've re-enabled them lower down. This means that the interrupt can only happen during the goto main instruction which defeats the point of interrupts.

Other than that I can't see anything wrong.

What happens if you change GETfreq to
Code:
    MOVFW    freqLow
    MOVLW         0X30
    MOVWF    freq_0
    MOVFW    freqHigh
    MOVLW         0X2A
    MOVWF    freq_1
Does it display 108.00?

Mike.
Edit, it would be a good idea to have a start frequency between the two limits - say 100.00 (0x2710) as the limiting code may be stopping it working.
 
Last edited:
Can we try removing the limits on the frequency by changing the ISR code to,
Code:
ISR            MOVWF   W_TEMP            ; SAVE OFF CURRENT W REGISTER CONTENTS
                MOVF    STATUS,W          ; MOVE STATUS REGISTER INTO W REGISTER
                MOVWF   STATUS_TEMP       ; SAVE OFF CONTENTS OF STATUS REGISTER
                BCF            STATUS,RP0
                BCF             PIR1,TMR2IF
                RLF     previous,F
                RLF     previous,W
                ANDLW   0X0C                    ;KEEP ONLY BITS 2 & 3
                BTFSS   PORTA,0                ;MOVE ENCODER BITS
                IORLW   1                            ;TO BITS 0 & 1
                BTFSS   PORTA,1
                IORLW   2
                MOVWF   previous                ;KEEP FOR NEXT TIME
                CALL    ENC_TABLE
                ADDWF        clicks,F
                MOVLW        4
                XORWF        clicks,W
                BTFSS        STATUS,Z
                GOTO        CHECK_DOWN
                CLRF        clicks                    ;added this line
                INCF    freqHigh,F            ;if not then increment it
                INCFSZ  freqLow,F
                DECF    freqHigh,F
                GOTO        EXIT
CHECK_DOWN
                MOVLW        0XFC            ;-4
                XORWF        clicks,W
                BTFSC        STATUS,Z
                GOTO        EXIT
                CLRF        clicks                    ;added this line
                MOVF    freqLow,F
                SKPNZ
                DECF    freqHigh,F
                DECF    freqLow,F
                GOTO        EXIT
;         RESTORE CONTEXT BEFORE RETURNING FROM INTERRUPT
EXIT        MOVF    STATUS_TEMP,W     ; RETRIEVE COPY OF STATUS REGISTER
                MOVWF   STATUS            ; RESTORE PRE-ISR STATUS REGISTER CONTENTS
                SWAPF   W_TEMP,F
                SWAPF   W_TEMP,W          ; RESTORE PRE-ISR W REGISTER CONTENTS
                RETFIE                    ; RETURN FROM INTERRUPT
And, of course, remove the literal values from GETfreq.


Mike.
 
Just spotted a mistake, in
Code:
CHECK_DOWN
                MOVLW        0XFC            ;-4
                XORWF        clicks,W
                BTFSC        STATUS,Z
it should be BTFSS.

Mike.
 
OK, what I'm seeing is - there is a quick flash of 100MHz being displayed, quickly overwritten by the aforementioned 573 odd MHz.

And the encoder is still doing nothing.

I've been staring at the screen trying to work out where that 573 figure is coming from but I'm drawing a blank.
 
So they are, well spotted. They're also in a few places.

Mike.
Edit, can you post your current complete code?
 
Something is bugging me about the initTmr2 code but I can't quite put my finger on what it is.

Code:
;
; *******************************************************************************
; *    LCD test program V7                            *
; *    Version 0.01                                *
; *    March 2021                                *
; *    Author: T Mowles VK5TM                            *
; *******************************************************************************
;
;                                                                             
;    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----SPARE                   
;    LCD D5------RB1 |7       12| RB6----LCD_rs  (LCD Pin 4)         
;    LCD D6------RB2 |8       11| RB5----LCD_rw  (LCD Pin 5)           
;    LCD D7------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)
;default_1 equ 0x2A        ; Most significant byte
;default_0 equ 0x30        ; Least significant byte (108MHz)
default_1 equ 0x27        ; Most significant byte
default_0 equ 0x10        ; Least significant byte (100MHz)

control_1 equ b'11000101'    ; Control_1 data 11000101 (MSB)
control_0 equ b'11110101'    ; Control_0 data 11110101 (LSB)

    ORG    0x2100
;
;    startup frequency bytes must be next 4 bytes of EEPROM
    DATA    default_1    ; startup -> MSB
    DATA    default_0    ; startup -> LSB
;
; *******************************************************************************
; *    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
    LCD_char        ; Character being sent to the LCD
    timer1            ; Used in delay routines
    CounterA        ;   "
    CounterB        ;   "
    CounterC        ;   "
    CounterD        ;   "
    CounterE        ;   "
    count            ; loop counter  (gets reused)
    rs_value        ; The LCD rs line flag value
    NumH
    NumL
    hcomp
    lcomp
    TenK
    Thou
    Hund
    Tens
    Ones
    byte2send
    bit_count
    previous
    temp
    clicks
    freqHigh
    freqLow
    ENDC            ; End of Data Block

    CBLOCK  0x70
    freq_1            ; Use bank common locations - saves bank switching when
        freq_0            ; saving/retreiving to/from EEPROM
    W_TEMP
    STATUS_TEMP
    ENDC            ; End of Data Block


; *******************************************************************************
; * The 16F628 resets to 0x00                            *
; * The Interrupt vector is at 0x04                        *
; *******************************************************************************
;
    ORG    0x0000               
    goto    start        ;

    ORG    0x0004        ;
    GOTO    ISR
;
ENC_TABLE
    addwf    PCL,f        ;index into table
    dt    0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0
;
; *******************************************************************************
; * Purpose:                                    *
; *    This is the start of the program                    *
; *                                        *
; *******************************************************************************
;
start
    clrf    PORTA
    clrf    PORTB
    movlw    0x07        ; Code to turn off the analog comparators
    movwf    CMCON        ; Turn off comparators

    banksel    TRISA        ; Switch to bank 1
    movlw    0xFF        ; Tristate PORTA (all Inputs)
    movwf    TRISA        ;
    clrf    TRISB        ; Set port B to all outputs
    banksel    PORTB        ; Switch back to bank 0
    clrf    PORTB

    movlw    control_1    ; send start sequence or control word 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

read_EEocs            ; Get the power on frequency
    banksel    EEADR        ; 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
    banksel    PORTB        ; Switch back to bank 0

;////////////////////////////////////////////////////////////////////////////////
    MOVFW    freq_0
    MOVWF    freqLow
    MOVFW    freq_1
    MOVWF    freqHigh
;////////////////////////////////////////////////////////////////////////////////

;
    call    bin2BCD        ; Convert it to BCD

    call    init_LCD    ; Initialize the LCD
    call    display_version

    call    show_freq    ; Display the frequency on the LCD
    call    wait_250

    movfw    PORTA
    movwf    previous

;////////////////////////////////////////////////////////////////////////////////
initTmr2
    ;using internal 4MHz clock = 1MHz instruction time
    ;prescaler = 4 = clocked at 250kHz
    ;PR2 = 249        will clock around every 250 cycles
    ;postscaler = 5 = clock every 250*4*5 = 5000 cycles = 5mS interrupt
    MOVLW    B'00100101'
    MOVWF    T2CON
    BSF    STATUS,RP0
    MOVLW    249
    MOVWF    PR2
    BSF    PIE1,TMR2IE
    BCF    STATUS,RP0
    BSF    INTCON,PEIE
    BSF    INTCON,GIE
;    RETURN
;////////////////////////////////////////////////////////////////////////////////
;
main
;////////////////////////////////////////////////////////////////////////////////
GETfreq
    BCF    INTCON,GIE
    MOVFW    freqLow
    MOVWF    freq_0
    MOVFW    freqHigh
    MOVWF    freq_1
    BSF    INTCON,GIE
;    RETURN
;////////////////////////////////////////////////////////////////////////////////
;
;    Based on the knob direction, either increment or decrement the frequency,
;    update the LCD and SAA1057.
;
;down
;    clrf    clicks
;    call    dec_freq    ;
;    goto    update        ; Update LCD
;up
;    clrf    clicks
;    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
;    BSF    STATUS,GIE
    goto    main        ; Continue main loop

;////////////////////////////////////////////////////////////////////////////////
;note W_TEMP and STATUS_TEMP need to be in the common area (above 0x70)
ISR
    MOVWF    W_TEMP        ; SAVE OFF CURRENT W REGISTER CONTENTS
    MOVF    STATUS,W    ; MOVE STATUS REGISTER INTO W REGISTER
    MOVWF    STATUS_TEMP    ; SAVE OFF CONTENTS OF STATUS REGISTER
    BCF    STATUS,RP0
    BCF    PIR1,TMR2IF
    RLF    previous,F
    RLF    previous,W
    ANDLW    0X0C        ;KEEP ONLY BITS 2 & 3
    BTFSS    PORTA,0        ;MOVE ENCODER BITS
    IORLW    1        ;TO BITS 0 & 1
    BTFSS    PORTA,1
    IORLW    2
    MOVWF    previous    ;KEEP FOR NEXT TIME
    CALL    ENC_TABLE
    ADDWF    clicks,F
    MOVLW    4
    XORWF    clicks,W
    BTFSS    STATUS,Z
    GOTO    CHECK_DOWN
    CLRF    clicks        ;added this line
    INCF    freqHigh,F    ;if not then increment it
    INCFSZ    freqLow,F
    DECF    freqHigh,F
    GOTO    EXIT

CHECK_DOWN
    MOVLW    0XFC        ;-4
    XORWF    clicks,W
    BTFSS    STATUS,Z
    GOTO    EXIT
    CLRF    clicks        ;added this line
    MOVF    freqLow,F
    SKPNZ
    DECF    freqHigh,F
    DECF    freqLow,F
    GOTO    EXIT

;         RESTORE CONTEXT BEFORE RETURNING FROM INTERRUPT
EXIT
    MOVF    STATUS_TEMP,W    ; RETRIEVE COPY OF STATUS REGISTER
    MOVWF    STATUS        ; RESTORE PRE-ISR STATUS REGISTER CONTENTS
    SWAPF    W_TEMP,F
    SWAPF    W_TEMP,W    ; RESTORE PRE-ISR W REGISTER CONTENTS
    RETFIE            ; RETURN FROM INTERRUPT
;////////////////////////////////////////////////////////////////////////////////

;
; *******************************************************************************
; * 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    ;
    clrf    PORTB        ;
    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    not_zero    ; of an arithmetic or logical operation is zero

    movlw    ' '        ; TenK = 0, insert space
    call    data2LCD    ; Send byte in W to LCD
    goto    show_thou

not_zero
    call    process        ; TenK is not 0, insert number

show_thou
    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:                                    *
; *    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 (100mS)

;    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,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us

    movlw    0x03        ; LCD init instruction (Second)             
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set E high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us

    movlw    0x03        ; LCD init instruction (Third)               
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set E high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us    ; wait a while,

    movlw    0x02        ; 4-bit mode instruction                     
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set E high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us    ; wait a while,

    movlw    0x28        ; 1/16 duty cycle, 5x8 matrix
    call    cmnd2LCD    ; Send command in w to LCD

    call    wait_100us

;    movlw    0x08        ; Display off, cursor and blink off
;    movlw    0x0C        ; Display on, cursor and blink off
    movlw    0x0E        ; Display on, cursor on and blink off
;    movlw    0x0F        ; Display on, cursor and blink on
    call    cmnd2LCD    ; Send command to LCD

    call    wait_100us

    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

    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_100us

    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
    clrf    PORTB
    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
;
; ****************************************************************************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)

    nop

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:  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_250
    movlw    250

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'74'
    movwf    CounterE
loop1
    decfsz    CounterE,f
    goto    loop1
    decfsz    CounterD,f
    goto    loop1
    return

wait_100us    ;PIC Time Delay = 0.00009800 s with Osc = 4MHz
    movlw    D'31'
    movwf    CounterA
loop2
    decfsz    CounterA,1
    goto    loop2
    return
;       
; *****************************************************************************
;
    END
 
The initTimer2 looks fine to me.
Stripping out all the remmed lines gives,
Code:
    ;using internal 4MHz clock = 1MHz instruction time
    ;prescaler = 4 = clocked at 250kHz
    ;PR2 = 249        will clock around every 250 cycles
    ;postscaler = 5 = clock every 250*4*5 = 5000 cycles = 5mS interrupt
    MOVLW    B'00100101'
    MOVWF    T2CON
    BSF    STATUS,RP0
    MOVLW    249
    MOVWF    PR2
    BSF    PIE1,TMR2IE
    BCF    STATUS,RP0
    BSF    INTCON,PEIE
    BSF    INTCON,GIE
main
    BCF    INTCON,GIE
    MOVFW    freqLow
    MOVWF    freq_0
    MOVFW    freqHigh
    MOVWF    freq_1
    BSF    INTCON,GIE
    call    bin2BCD        ; Convert the frequency to BCD
    call    show_freq    ; Display the frequency on the LCD
    goto    main        ; Continue main loop
Do you have an LED connected that can be used for debugging? OR, can you set a breakpoint to see if it's getting into the ISR?

What is it doing now?

I'm thinking that it's been so long since I did assembler that there could be lots of dumb mistakes in there.

Mike.
 
I can fit a LED to any of the PORTA lines other than the encoder inputs or to PORTB,7.

Without slowing things down, as far as I can tell it is sitting there constantly refreshing the 100.00 bits of the Frequency line, which is what I would expect it to be doing at this stage.

Encoder still doesn't want know.
 
I think the thing that is bugging me about the initTmr2 code is 'possibly', Timer 2 doesn't like have it's pre & post scalers being set at the same time it is being turned on.

I have a vague recollection of that causing me a problem on a previous occasion, possibly with one of the other timers.

Edit: And that is the problem.
Changed code to below and encoder is now working
Code:
initTmr2
    ;using internal 4MHz clock = 1MHz instruction time
    ;prescaler = 4 = clocked at 250kHz
    ;PR2 = 249        will clock around every 250 cycles
    ;postscaler = 5 = clock every 250*4*5 = 5000 cycles = 5mS interrupt
    MOVLW    B'00100001' ;<-----------------
    MOVWF    T2CON
    BSF    STATUS,RP0
    MOVLW    249
    MOVWF    PR2
    BSF    PIE1,TMR2IE
    BCF    STATUS,RP0
    BSF    INTCON,PEIE
    BSF    INTCON,GIE
    BSF    T2CON,TMR2ON ;<------------------
 
Last edited:
I suspect the ISR code isn't being called at all but no idea why.

If the timer code worries you, change it to,
Code:
    MOVLW    B'00100001'
    MOVWF    T2CON
     BSF             T2CON,TMR2ON

Can you set breakpoints?

Mike.
 
Status
Not open for further replies.

Latest threads

Back
Top