assembly 为什么在Proteus中会出现此错误:“在PC=0x002A上的操作码0xFFFF无效”

u7up0aaq  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(351)

我用汇编语言为avr atmega328P编写了这段代码。它使用按钮来打开和关闭LED,但在Proteus中我得到了以下错误:
PC=0x002A上的操作码0xFFFF无效
这是我的代码:

.INCLUDE "M328Pdef.inc"

ldi r16,HIGH(RAMEND)
out SPH, R16
ldi r16,LOW(RAMEND)
out SPL, R16

start:
ldi r16,0xFF
out DDRB,r16
ldi r17,0x00
out DDRD,r17
ldi r21,0x00
ldi r23,0x01

Forever:
in r20,PIND
cp r20,r21
BREQ ledon
cp r20,r23
BREQ ledoff
rjmp Forever

ledon:
ldi r22,0x01
out PORTB,r22 
ret

ledoff:
ldi r24,0x00
out PORTB,r24
ret

有没有人能解决这个问题?

gupuwyp2

gupuwyp21#

问题就在这里:

BREQ ledon  ; branch
cp r20,r23
BREQ ledoff ; branch
rjmp Forever

ledon:
ldi r22,0x01
out PORTB,r22 
ret ; return from subroutine, but never used [R]CALL.

ledoff:
ldi r24,0x00
out PORTB,r24
ret ; return from subroutine, but never used [R]CALL.

你分别分支到ledonledoff,这只是一个条件跳转,但是在各个块的末尾,你使用的是ret,就好像你通过[r]call调用代码一样。
ret将从堆栈中弹出2个字节,并将这些字节用作要返回的字地址。代码目标很可能具有未初始化的闪存,该闪存保存0xff,并且两个0xff是0xffff,这不是法律的的AVR操作码。0x002a是发出非法跳转的最后一个ret的字节地址。
要解决这个问题,您可以使用rjmp Forever而不是ret,但这取决于您希望使用代码实现什么。

相关问题