我正在使用Atmega2560
微控制器开发一个简单的按钮导向项目。我的按钮有问题。当我点击按钮时,主循环停止工作,只要按下按钮,按钮功能就会保持无限次运行。按下按钮时,主循环不应停止。按钮功能只能运行一次。我怎么能这样做?
.def LEDS = R16
.def LED_DATA = R21
.org 0
rjmp MAIN
MAIN:
ldi LEDS, 0xFF ; 0xFF = 1111 1111
ldi LED_DATA, 0x01
out DDRC, LEDS ; PORTC
sbi PORTB, 0
sbi PORTB, 1
LOOP_MAIN:
sbis PINB, 0 ; If PORTB-0's pin = 1, skip next
rjmp BUTTON_CLICK_H
sbis PINB, 1
rjmp BUTTON_CLICK_Y
call DELAY
out PORTC, LED_DATA
lsl LED_DATA
brcc SHIFT_0_IN ;if carry not set, the MSB was not set, so skip setting the LSB
ori LED_DATA, 1
SHIFT_0_IN: ; keep LSB as 0 -> do nothing, just continue
rjmp LOOP_MAIN
END:
rjmp LOOP_MAIN
BUTTON_CLICK_H:
lsl LED_DATA
cpi LED_DARA, 0x40
breq SPEED_RESET
rjmp SPEED_END
SPEED_RESET:
ldi LED_SPEED, 0x04
SPEED_END:
rjmp LOOP_MAIN
编辑:(11/26/2017)
我写了一个简单的按钮控制器。该控制器的目的是检查按钮是否被按下或按下。按钮代码应该只工作一次。但是当我按下按钮时它不起作用。我在哪里犯错误?
.def BTN_STATE_FIRST = R23
.def BTN_STATE_CHANGED = R24
.def BTN_STATE_PINB = R25
.def BTN_STATE_TEMP = R26
LOOP_MAIN:
out PORTC, LED_DATA
call LOOP_BUTTON
call DELAY
; ...Codes
rjmp LOOP_MAIN
LOOP_BUTTON:
; (Is the button pressed, not pressed or kept pressed?) Controller
in BTN_STATE_PINB, PINB ; Read PINB data and put it current state in BTN_STATE_PINB
mov BTN_STATE_TEMP, BTN_STATE_PINB ; Move it to BTN_STATE_TEMP
eor BTN_STATE_PINB, BTN_STATE_FIRST ; XOR BTN_STATE_PINB and BTN_STATE_FIRST. And write result to the BTN_STATE_PINB
mov BTN_STATE_FIRST, BTN_STATE_TEMP ; Move it the BTN_STATE_FIRST
breq BUTTON_PRESSED
brne BUTTON_NOTPRESSED
BUTTON_PRESSED:
cpi BTN_STATE_PINB, 0x01 ; 1st button 0x01, 2nd button 0x02, 3rd button 0x04
breq BUTTON_CHANGED
rjmp BUTTON_NOTPRESSED
BUTTON_CHANGED:
cpi BTN_STATE_CHANGED, 0x01 ; When pressed and held, have been processed before ? 0x01 true, 0x00 false
breq BUTTON_UP ; If yes, branch to BUTTON_UP
brne BUTTON_DOWN ; Otherwise, branch to BUTTON_DOWN
BUTTON_UP:
dec BTN_STATE_CHANGED ; Decrement the BTN_STATE_CHANGED to 0x00
ldi LED_DATA, 0x40
rjmp BUTTON_END
BUTTON_DOWN:
inc BTN_STATE_CHANGED ; Increment the BTN_STATE_CHANGED to 0x01
ldi LED_DATA, 0x80
BUTTON_END:
BUTTON_NOTPRESSED:
ret
答案 0 :(得分:3)
按下按钮时,输入引脚信号如下:
___---------------------------------___--__--___-_______
^ here the press starts ^ released ^ bounces (physically)
如果接触不够牢固,有时可能会在开始时发生一些弹跳,或者主信号中会出现一些噪声。
如果它是完美干净的数字信号,如:
_______-------------------------------_______________
然后您需要做的就是保持主要的先前状态,检查按钮是否被点击然后看起来像:
current reading | previous state | action
-------------------------------------------------------------------
0 | 0 | N/A (or refresh "previous")
1 | 0 | previous=1, call click function
1 | 1 | N/A (or refresh "previous")
0 | 1 | previous=0
但是由于按钮中实际开关的物理弹跳,你必须在代码中编写更强大的逻辑,这些逻辑在之前的#34;位更改也将重置一些"去抖定时器",并且直到该定时器(倒计数器)将达到零,"先前"状态被锁定,忽略在实际I / O线上读取的任何状态更改。因此,去抖动的逻辑将转向:
___---------------------------------___--__--___-_______
^ here the press starts ^ released ^ bounces (physically)
成:
real-time in from button pin:
___-_--_------------------------------___--__--___-____________
"previous" state:
___-----------------------------------_________________________
"debounce timer": (active means "> 0") (preventing change of previous)
___--------------------_______________--------------------_____
action in code:
*1 *2 *3 *4
操作:
如果你想实现"主要不停止"的幻觉,你需要保持onClick处理程序非常短(非阻塞,非延迟),并保持"的任何延迟逻辑。 main",可以无限循环并根据需要更新任何定时器/计数器(包括每个输入位的" debounce"定时器),并使用额外的复杂逻辑在发出的某些事件上运行短时快速函数一些计时器或输入状态。
编辑:关于新代码的一些注释,我试图部分理解。
我对你的基本架构存在问题,看起来你将所有与该按钮相关的值保存在固定寄存器中,这会使LOOP_BUTTON
固定到特定的引脚/按钮,而不是其他地方可重复使用
我建议你以更通用的方式设计子程序,通过参数配置特定的功能,而不是通过子程序的代码(只要它有意义,结果代码相当简单)。
我会以一种方式设计它,以便在一个寄存器中输入按钮对象实例的地址,并在另一个寄存器值中引脚,如:
免责声明:我无法验证这是否是有效的AVR asm语法,或者即使该代码有效,因此主要用作" idea" source(我使用此链接编写指令及其语法:http://www.avr-tutorials.com/sites/default/files/Instruction%20Set%20Summary.pdf):
... main loop code continues with button tests...
; read current state of PINB into R23
in R23,PINB
; button 1 check (data in memory at button1_data, pin: bit 0 of PINB)
ldi ZH,high(button1_data)
ldi ZL,low(button1_data)
ldi R24,0b00000001 ; bit 0 bitmask
rcall BUTTON_HANDLER ; R24 = 0/1 when onClick should be called
sbrc R24,0 ; skip onClick call, when result was 0
rcall BTN_1_ON_CLICK ; BTN1 was clicked, call onClick handler
; ^^ must preserve R23!
; button 2 check (data in memory at button2_data, pin: bit 1 of PINB)
ldi ZH,high(button1_data)
ldi ZL,low(button1_data)
ldi R24,0b00000010 ; bit 1 bitmask
rcall BUTTON_HANDLER ; R24 = 0/1 when onClick should be called
sbrc R24,0 ; skip onClick call, when result was 0
rcall BTN_2_ON_CLICK ; BTN2 was clicked, call onClick handler
; button 3 check (data in memory at button3_data, pin: bit 2 of PINB)
ldi ZH,high(button1_data)
ldi ZL,low(button1_data)
ldi R24,0b00000100 ; bit 2 bitmask
rcall BUTTON_HANDLER ; R24 = 0/1 when onClick should be called
sbrc R24,0 ; skip onClick call, when result was 0
rcall BTN_3_ON_CLICK ; BTN3 was clicked, call onClick handler
... continuation of main loop ...
按钮数据在.dseg中定义为:
.dseg
button1_data:
.byte 2 ; two bytes of storage per button
button2_data:
.byte 2 ; two bytes of storage per button
button3_data:
.byte 2 ; two bytes of storage per button
不要忘记在程序初始化期间清除它们,可能是这样的:
main:
; during program init don't forget to clear button data in memory
clr R1 ; R1 = 0
sts button1_data, R1
sts button1_data+1, R1 ; Not sure if this is legal syntax :/
sts button2_data, R1
sts button2_data+1, R1
sts button3_data, R1
sts button3_data+1, R1
最后按钮输入处理程序例程,它将接收R23
按钮(引脚)的当前状态,R24
是要检查的按钮的位掩码,Z
应该指向按钮数据。无论是否点击了按钮,它都将返回R24 = 0/1
状态:
; button input handler:
; R23 = pins state (preserved), R24 = pin bitmask, Z = button data
; returns R24 = 0/1 when onClick should be called
; button data structure: +0 = previous state, +1 = debounce timer
BUTTON_HANDLER:
; check debounce timer first, if > 0, state is locked
ldd R0,Z+1 ; debounce timer is second byte
tst R0 ; is it zero?
breq BUTTON_HANDLER_DEBOUNCE_OK
; debounce timer is > 0, just decrement it and ignore input
dec R0
std Z+1,R0
clr R24 ; R24 = 0 (no click)
ret
BUTTON_HANDLER_DEBOUNCE_OK:
; process input
ld R0,Z ; R0 = previous state of bit
and R24,R23 ; R24 = current state
cpse R0,R24 ; if previous == current, skip change
rjmp BUTTON_HANDLER_CHANGE_DETECTED
clr R24 ; R24 = no click (no change on pin)
ret
BUTTON_HANDLER_CHANGE_DETECTED:
st Z,R24 ; store new state into "previous" data
; EDIT - bugfix added, debounce timer need to be set too!
ldi R0,DEBOUNCE_DELAY ; amount of main_loops to pass
std Z+1,R0
tst R24 ; when new state is zero => released button
breq BUTTON_HANDLER_RELEASED ; return 0
ldi R24,1 ; when new state is non-zero, return 1 (click!)
BUTTON_HANDLER_RELEASED:
ret
然后,当点击某个按钮时,您将调用您的" onClick"特定按钮的例程:
; button 1 onClick handler (must preserve R23 (input pins of buttons)).
BTN_1_ON_CLICK:
; TODO anything you wish to do upon BTN1 pressed
ret
并定义一些去抖时间常数DEBOUNCE_DELAY
,它是要通过的main_loops量,直到按钮开始对当前状态作出反应(如果你每1ms循环一次,那么你可以尝试DELAY 30)。 / p>
哦等等,所以我没有评论你的代码,而是制作了自己的代码......即使我甚至无法验证它是否有效......对不起。 :)
(如果它有效,那么我猜它不是非常有效的AVR程序集,因为我觉得我总是从x86的角度来看问题并且缺少帮助我的指令,就像为什么一样AVR有很多指令直接设置标志(零/进位/ ...所有这些),但不是另一种方式,根据标志等将寄存器设置为0/1。)
请让我知道它是否以某种形式为你工作+建议修复我的代码以使其有效,使这个更好的答案(如果你不回应,我可能会随着时间推移删除它,因为我和#39;恐怕可能完全错了。)