assembly 为什么我的AVR ATmega32汇编代码的键盘功能不工作

9fkzdhlc  于 4个月前  发布在  其他
关注(0)|答案(1)|浏览(48)

首先,我非常抱歉,如果我不知道如何正确提出一个问题。这是我第一次使用这个论坛的指导!我必须转换一个4x 4键盘矩阵AVR汇编代码到4x 3,这必须通过中断来完成。到目前为止,这是我所做的:

.INCLUDE  "M32DEF.INC"

.org  0x00
jmp main

.org 0x50
main:

.EQU  KEY_PORT  =  PORTC
.EQU  KEY_PIN  =  PINC
.EQU  KEY_DDR  =  DDRC

.EQU  LCD_DPRT  =  PORTA
.EQU  LCD_DDDR  =  DDRA
.EQU  LCD_DPIN  =  PINA
.EQU  LCD_CPRT  =  PORTB
.EQU  LCD_CDDR  =  DDRB
.EQU  LCD_CPIN  =  PINB
.EQU  LCD_RS  =  0
.EQU  LCD_RW  =  1
.EQU  LCD_EN  =  2

LDI  R20,  HIGH  (RAMEND) 
OUT  SPH,R20
LDI  R20,  LOW  (RAMEND) 
OUT  SPL,R20
;  ascii  code  for  keypressed  displayed  on  PORTD 
LDI  R21,  0xFF
OUT  DDRA,R21  ; port a output to lcd
;  PC0  – PC3  rows
;  PC4  – PC6  columns
LDI  R20,  0xF0  //portc  0-3  input  pins 
OUT  KEY_DDR,  R20

GroundAllColumns:
LDI  R20,  0b00001110  //  portc  0-3  display  111 
OUT  KEY_PORT,  R20

LDI  R21,0xFF;
OUT  LCD_DDDR,  R21  ;LCD  data  port  is  output 
OUT  LCD_CDDR,  R21 ;  A,B  PORT  AS  OUTPUT 
CBI  LCD_CPRT,LCD_EN
CALL  DELAY_2ms  ;wait  for  power  on 
LDI  R16,0x38  ;  FOR  7X5  DISPLAY
CALL  CMNDWRT  ;call  command  function 
CALL  DELAY_2ms  ;wait  2  ms
LDI  R16,0x0E  ;display  on,  cursor  on 
CALL  CMNDWRT  ;call  command  function 
LDI  R16,0x01  ;clear  LCD
CALL CMNDWRT 
CALL DELAY_2ms
LDI  R16,0x06  ;  INCREMENT  CURSOR 
CALL CMNDWRT
LDI  R16,0x84  ;  INCREMENT  CURSOR  IST  LINE  4TH  COLUMN 
CALL CMNDWRT

LDI  R16,  'F' 
CALL DATAWRT 
LDI  R16,  'A' 
CALL DATAWRT

LDI  R16,  'S' 
CALL DATAWRT 
LDI  R16,  'T' 
CALL DATAWRT

LDI  R16,0xC3  ;  INCREMENT  CURSOR  2ND  LINE  3RD  COLUMN 
CALL CMNDWRT
LDI  R16,  '0' 
CALL DATAWRT

here: rjmp here

KPD_ISR:
LDI  R21,  0b01111111 
OUT  KEY_PORT,R21 
NOP
IN  R21,KEY_PIN

ANDI  R21,0x0F 
CPI  R21,0x0F 
BRNE COL1

LDI  R21,  0b10111111 
OUT  KEY_PORT,  R21 
NOP
IN  R21,  KEY_PIN 
ANDI  R21,0x0F 
CPI  R21,0x0F 
BRNE COL2

LDI  R21,  0b11011111 
OUT  KEY_PORT,  R21 
NOP
IN  R21,  KEY_PIN 
ANDI  R21,0x0F 
CPI  R21,0x0F 
BRNE COL3

COL1:
LDI  R30,  LOW(KCODE0<<1) 
LDI  R31,  HIGH(KCODE0<<1)
RJMP  Find 
COL2:
LDI  R30,  LOW(KCODE1<<1) 
LDI  R31,  HIGH(KCODE1<<1)
RJMP  Find 
COL3:
LDI  R30,  LOW(KCODE2<<1) 
LDI  R31,  HIGH(KCODE2<<1)
RJMP  Find 

Find:
LSR R21
BRCC  Match 
LPM  R20,  Z+
RJMP  Find MATCH:
LPM  R20,  Z

ldi  r17,0x0f 
in  r16,pinc 
andi  r16,0x0f 
cp  r16,r17 
breq  kpd_isr

OUT  PORTA,  R20
mov  r16,r20
call  datawrt  ;  here call  BDELAY

rjmp  KPD_ISR

.ORG  0x300
KCODE0: .DB  '7',  '8',  '9' ;col1
KCODE1: .DB  '4',  '5',  '6'
KCODE2: .DB  '1',  '2',  '3'
KCODE3: .DB  'c',  '0',  '='

字符串
在Proteus模拟中,我在LCD上得到了初始化的输出,但是每当我按下键盘上的任何东西时,它都不会在LCD上注册。我可以从我的模拟中看到,引脚p4-p6的列被设置,我不确定应该是这样:My proteus simulation:
我调整了手册中提供的代码,但随着我的学习,我完全不确定我错在哪里。此外,我记得中断服务例程需要一个向量表(IVT),你可以从IVT中指定的内存位置调用它们。在我提供的代码中,有一个ISR用于按下键盘按钮,但没有设置IVT。这可能是问题所在吗?

q9yhzks0

q9yhzks01#

您的代码不包含任何ISR函数。ISR函数由中断激活。您没有启用任何中断,也没有设置到相关ISR函数的跳转。
KPD_ISR不是ISR,也不是函数。该函数由CALL指令调用,必须以RET指令结束。ISR函数由中断调用,必须以RETI指令结束。为了使激活的中断调用ISR函数,必须在IVT中的适当位置跳转到ISR。
还有一件更重要的事情,ISR在完成后不能对处理器的状态造成任何改变,所以它必须负责保存和恢复所有使用过的寄存器,包括SREG。
对于下一个ISR,它应该尽可能短。在任何情况下,它都不应该包含一个持久的代码,在你的代码中显示。
请阅读一些教程,例如here

相关问题