我在汇编时遇到了程序问题。该计划应该执行以下操作:
说"欢迎" >等一秒>说"按2到(Str_roll_1)roll(Str_roll_2)" >如果按下2,则开始滚动骰子,直到键被释放为止>显示价值并存储它>回到"按2滚动" >重复
但出于某种原因,我无法绕过头脑,代码几乎跳过" roll_dice"部分并绕着循环显示"滚动......" > "价值:0" > "滚动..." > "价值:0" > ......等等
我使用arduino leonardo电路板,如果有任何帮助的话。我不知道这些信息是否足够,但如果您需要更多信息,请询问。谢谢:))
代码的主要部分:(我希望我所包含的子程序非常不言自明)
main:
PRINTSTRING Str_welcome
RCALL delay_1_s
RCALL lcd_clear_display
PRINTSTRING Str_roll_1
LDI RVAL, 0xC0
RCALL lcd_write_instr
PRINTSTRING Str_roll_2
loop:
CALL read_keyboard
LDI R25, 0x04
CP R25, RVAL
BREQ two
RJMP loop
two:
RCALL lcd_clear_display
PRINTSTRING Str_rolling
RCALL delay_1_s
RCALL roll_dice
RCALL store_stat
RCALL lcd_clear_display
PRINTSTRING Str_value
SUBI R24, -48
RCALL lcd_write_chr
RCALL delay_1_s
RJMP cont
cont:
RCALL lcd_clear_display
PRINTSTRING Str_roll_1
LDI RVAL, 0xC0
RCALL lcd_write_instr
PRINTSTRING Str_roll_2
RJMP loop
roll_dice:
LDI R16, 6
test:
NOP
NOP
RCALL read_keyboard
CPI RVAL, 0x04
BREQ roll
RET
roll:
DEC R16
BREQ roll_dice
RJMP test
键盘文件//////////
map_table: .DB "147*2580369#"
read_keyboard:
LDI R18, 0 ; reset counter
LDI ZH, high(map_table <<1) ;Initialize Z pointer
LDI ZL, low(map_table <<1)
ADD ZL, RVAL ;Add index
LDI RVAL, 0x00
ADC ZH, RVAL ;Add 0 to catch Carry, if present
LPM RVAL, Z
scan_key:
MOV R19, R18
LSL R19
LSL R19
LSL R19
LSL R19
OUT PORTB, R19 ; set column and row
在此处插入22条NOP线
SBIC PINE, 6
RJMP return_key_val
INC R18
CPI R18, 12
BRNE scan_key
LDI R18, NO_KEY ; no key was pressed!
return_key_val:
MOV RVAL, R18
RET
答案 0 :(得分:2)
您的问题很可能不是软件,而是硬件。我敢打赌,如果你把一个示波器放在钥匙上,你会看到它有接触反弹。开关将暂时关闭,但随后重新打开并重新关闭几次,然后才能变为稳定值。
这意味着,由于您在第一次反弹发生后立即离开延迟循环,它似乎永远不会发生(尽管非常短暂地)。如果您调用read_keyboard并打开一个引脚(或调试LED),如果键2处于活动状态,如果键2处于非活动状态,则将其关闭,您将看到后面的键2正在工作,但您赢了&#39;当它改变状态时,看到快速的眨眼。触点反弹通常在毫秒级,但在非常糟糕的开关上可能会更长。
通常,最好的解决方案是持续监控计时器中按钮的状态,并且只有在引脚稳定后才更新全局状态变量。然后,您的主要代码只会查看已正确过滤且稳定的状态。有硬件方法可以做到这一点,因此您选择的确切解决方案是一个工程问题,取决于整个系统设计
答案 1 :(得分:0)
通过做这样的事情,我发现开发过程要复杂得多,因为汇编可以很容易地演变成意大利面条代码。
; ============================================================================================
; This pair of complimentary routines controls function of watchdog timer.
; ENTER: R24 = Bits 5 & 2:0 deliniate prescaler value WDP3:0 (11-2 pg 55)
; --------------------------------------------------------------------------------------------
.equ WDT_Change_Enable = (1 << WDCE) | (1 << WDE)
WDT_Enable:
in R20, SREG ; So I flag bit 7 will be returned in original state.
; During this process, we do not want interrupts or an inadvertant timeout of WDT.
cli ; Disable interrupts
wdr ; To be sure we have at least 16ms to setup
WDT_Set:
lds R25, WDTCSR ; 11.9.2 pg 54 Control Register
sbr R25, WDT_Change_Enable
sts WDTCSR, R25 ; Begin timmed sequence
sts WDTCSR, R24 ; Write desired parameters
; A change to watchdog can happen anywhere, so if global interrupts are already
; disabled, we do not want to change the flags state.
out SREG, R20 ; In order to not modify "I" flag.
ret
; ---------------------------------------------------------------------------------------------
WDT_Disable:
in R20, SREG ; See comments @ WDT_Enable
cli
wdr
; See note a bottom of page 52 ATMEL 8271I-AVR-10/2014
in R25, MCUSR ; 7.3.1 pg 11
cbr R25, WDRF ; Clear watchdog reset bit
out MCUSR, R25
; Reset watchdog enable, but retain prescaler.
lds R24, WDTCSR
cbr R24, RSET ; Clear bit so watchdog will be disabled.
rjmp WDT_Set
这有两件事。 (1)它强化了一个概念,因为一旦你写了评论,仔细检查代码将做什么,(2)其他阅读不必猜测任何部分正在做什么和为什么。
Jester写道:
这对我没有任何意义。
我很确定他并不是故意暗示你的代码是荒谬的,而是对你来说直观的不是我们。我愿意打赌,如果你花费更多的时间记录,问题就会突然出现在你面前,如果没有,那么对于那些你要求帮助的人来说,理解你的逻辑就会容易得多。 / p>
你可能是对的,但我也发现了,假设你没有包含的东西没有问题,可以放肆。