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
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
As result your are actually disabling pull-ups in input pins instead of sending Low in output pins in following places
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