scanning keypad and displaying to leds using avr assembly with atmega32a

110 Views Asked by At

Using an atmega32a, scan 4x4 multiplexed keypad and display this value to the leds. i have come up with code for this but it does not work. it keeps running all the way through to the end and displaying the last masking value as the key pressed. the code is presented below:

; ****************************************************
; EEET2256 - Laboratory 3B (2023) Template
; Author: Dr. Glenn Matthews
; Last Updated:  21/08/2023 11:34:04 AM
; lab3b_template.asm
;*****************************************************
; Define variables.
.def  temp  = R16
.def  temp_2 = R17
.def  ts = r20
.equ SP = 0xDF

; Reset Vector.
reset:
   rjmp start

;***********************************************************
; This program reads a single number from the keypad.
;***********************************************************
; Program starts here after Reset
start:
    LDI  TEMP,  SP      ; Init Stack pointer
    OUT  0x3D,  TEMP

    CALL Init           ; Initialise the system.

loop:       
    ; Get a single key from the keypad and return it in R16 (temp)
    CALL ReadKey      

    ; Once the key has been recieved, put it on the PORTB leds.             
    CALL Display
    
    RJMP     loop           ; Do all again - You don't need to reinitialize

;************************************************************************
;
Init:
    PUSH TEMP  ; Save TEMP on the stack

    ; Configure the lower 4 bits of Port C as inputs for the keypad.
    LDI TEMP, 0x0F
    OUT DDRC, TEMP

    LDI TEMP, 0xFF
    OUT PORTC, TEMP

    ; Set all pins in Port B as outputs for the LEDs.
    OUT DDRB, TEMP

    POP TEMP  ; Restore TEMP from the stack
    RET 
;************************************************************************
;
; ReadKey - Read a single digit from the keypad and store in TEMP
; Uses:  R16 (Temp)
; Returns: Temp
;
 ReadKey:
    ldi ts, 0x01
    clr temp
    LDI TEMP, 0xFF
    OUT PORTC, TEMP
    NOP
    IN TEMP_2, PINC
    CPI TEMP_2, 0XFF
    BREQ ReadKey
    CALL Delay
    RCALL ReadKP            ; Read one number from keypad and return in Temp (R16)
    
    RET                     ; Exit back to calling routine

ReadKP:
    LDI TEMP_2, 0xEF
    OUT PORTC, TEMP_2
    NOP
    IN TEMP, PINC
    CPSE TEMP_2,TEMP
    CALL COL1

    LDI TEMP_2, 0xDF
    OUT PORTC, TEMP_2
    NOP
    IN TEMP, PINC
    CPSE TEMP_2,TEMP
    CALL COL2

    LDI TEMP_2, 0xBF
    OUT PORTC, TEMP_2
    NOP
    IN TEMP, PINC
    CPSE TEMP_2,TEMP
    CALL COL3

    LDI TEMP_2, 0x7F
    OUT PORTC, TEMP_2
    NOP
    IN TEMP, PINC
    CPSE TEMP_2,TEMP
    CALL COL4

    RET

;************************************************************************
;
; Takes whatever is in the Temp register and outputs it to the LEDs
Display:
        OUT PortB, temp
        RET
;*************************************
;
; Delay routine
;
; this has an inner loop and an outer loop. The delay is approximately
; equal to 256*256*number of inner loop instruction cycles.
; You can vary this by changing the initial values in the accumulator.
; If you need a much longer delay change one of the loop counters
; to a 16-bit register such as X or Y.
;
;*************************************
Delay:
    PUSH R16            ; Save R16 and 17 as we're going to use them
    PUSH R17            ; as loop counters
    LDI R16, 10
L1: 
    LDI R17, 250
L2: 
    DEC R17
    BRNE L2
    DEC R16
    BRNE L1
    POP R17
    POP R16
    RET

COL1:
    ; Check 1st column for button press, load KEYCOL1 << 1 into ZH:ZL
    LDI ZH, HIGH(KEYCOL1 << 1) ; High byte of key values
    LDI ZL, LOW(KEYCOL1 << 1)  ; Low byte of key values
    CALL findKey
    RET                         ; Return from this subroutine

COL2:
    ; Check 2nd column for button press, load KEYCOL2 << 1 into ZH:ZL
    LDI ZH, HIGH(KEYCOL2 << 1) ; High byte of key values
    LDI ZL, LOW(KEYCOL2 << 1)  ; Low byte of key values
    CALL findKey
    RET                         ; Return from this subroutine

COL3:
    ; Check 3rd column for button press, load KEYCOL3 << 1 into ZH:ZL
    LDI ZH, HIGH(KEYCOL3 << 1) ; High byte of key values
    LDI ZL, LOW(KEYCOL3 << 1)  ; Low byte of key values
    CALL findKey
    RET                         ; Return from this subroutine

COL4:
    ; Check 3rd column for button press, load KEYCOL3 << 1 into ZH:ZL
    LDI ZH, HIGH(KEYCOL4 << 1) ; High byte of key values
    LDI ZL, LOW(KEYCOL4 << 1)  ; Low byte of key values
    CALL findKey
    RET                         ; Return from this subroutine

findKey:
    ; Find the correct key in the column by matching the row value
    CLR TEMP_2
    INC TEMP_2         ; Increment TEMP_2 (row counter)
    LSR TEMP        ; Left-shift TEMP
    BRCS findKey    ; Branch if carry set (indicates matching row)
    SUBI TEMP_2, 0x01  ; Subtract 1 from TEMP_2
    ADD ZL, TEMP_2     ; Add TEMP_2 to ZL (address in memory)
    LPM TEMP, Z     ; Load the key value from memory to TEMP
    RET

KEYCOL1:        .DB 0x00, 0x04, 0x08, 0x0C  ; Define characters for column 1 keys
KEYCOL2:        .DB 0x01, 0x05, 0x09, 0x0D  ; Define characters for column 2 keys
KEYCOL3:        .DB 0x02, 0x06, 0x0A, 0x0E ; Define characters for column 3 keys
KEYCOL4:        .DB 0x03, 0x07, 0x0B, 0x0F ; Define characters for column 3 keys

im expecting the key that is pressed to be displayed to the leds

1

There are 1 best solutions below

2
Ganapathy On

I doubt you get any output at all

In AVR microcontrollers Pin is set as Output when DDRC set to 1 else Input when cleared, based on this followinh statement, you are setting upper 4 bits as inputs and lower 4 bits as output

; Configure the lower 4 bits of Port C as inputs for the keypad.
LDI TEMP, 0x0F
OUT DDRC, TEMP

As result your are actually disabling pull-ups in input pins instead of sending Low in output pins in following places

LDI TEMP_2, 0xEF
LDI TEMP_2, 0xDF
LDI TEMP_2, 0xBF
LDI TEMP_2, 0x7F

Function ReadKey never call ReadKP because, you send 0xFF to PORTC, which upper 4-bits pull up enabled and lower 4 bits output HIGH, when you read PINC, you get same 0xFF and BREQ ReadKey becomes true and always jumps back to ReadKey and continues in loop forever

Even somehow code executes ReadKP function, PINC will be 0xFF for pressed Key as I said you are disabling pull-up not sending Low, based on your last reply you have pull-up resistors on ROW (based on your comments I assume that's on bit 7 - 4) the external pull-up would pull the line HIGH, as result the PINC is always 0xFF.

FindKey function loops till zero found in TEMP which is PINC value, but the this value is 0xFF so it loops 8 times to get zero and gets the last value from the table and send it to output