2016-09-07 49 views
1

我想在AVR组件中创建一个程序,它将轮询瞬时按钮开关的状态,并在按下开关时切换LED的状态。我正在使用带有ATMega328P芯片的Arduino Duemilanove。我有一个连接在数字引脚0和地之间的按钮开关,以及一个连接数字引脚8和+ 5V之间的330欧姆电阻的LED。这是我到目前为止的代码:在AVR组件中创建一个拨动开关

;============== 
; Declarations: 

.def temp = r16 
.org 0x0000 
rjmp Reset 

;============== 

Reset: 
     ser temp 
     out DDRB, temp   ; set all pins on Port B to OUTPUT mode 
     ldi temp, 0b11111110 ; set pin 0 on Port D to INPUT mode 
     out DDRD, temp 
     clr temp 
     out PORTB, temp  ; clear temp and set all pins on Port B to LOW state 
     ldi temp, 0b00000001 ; set pin 0 on Port D to HIGH state 
     out PORTD, temp 

;============== 
; Main Program: 

switch: 
     in temp, PIND   ; get state of pins on Port D 
     cpi temp, 0   ; compare result to 0 (pushbutton is pressed) 
     brne PC+3    ; if != 0, go check again 
     ldi temp, (1<<PB0)  ; otherwise, write logic 1 to pin 0 of Port B 
     out PINB, temp   ; which toggles the state of the pin 
     rjmp switch 

不幸的是这一切确实是光LED和保持它无论按键多少次推。我将这个代码从一个发现here的程序中解脱出来,只要按下按钮就可以打开上的LED。我只是想延长这一点,使LED保持当前状态,直到再次按下按钮。有什么建议么?

+0

切换它你应该使用口罩不是整个'PIND'仅比较'PIND0'到'0'。特别是如果您的端口悬空(二极管上的照明可能会改变浮动引脚的电平并使'cpi temp,0'始终错误)。 此外,您可以使用'SBI'指令来更改'PINB'中的单个位。 不确定这会工作,但目前我没有看到其他问题。 – Julien

+1

按钮弹跳。这在示例代码中无关紧要,但在您的情况下,即使在@ Julien的提示之后,您也会收到随机结果。 – datafiddler

+0

我试图围绕如何使用'sbi'来写入逻辑1到PB0,但我似乎无法使其工作。使用'sbi PORTB0,1'不会给出预期的结果。我看到你对按钮反弹的观点。也许在主循环中的某个延迟子例程会使开关脱落? –

回答

-1

您只会对PB0写入高电平。每按一次键,你需要您先前设定温度为1至反转引脚状态例如

in temp, PORTB 
com temp 
out PINB, temp 

然后1的恭维将其更改为11111110这样写在下一次零到PINB0和将00000001变成重新开启。

这种过于简单化的解决方案有一个不可预知的副作用,因为它不考虑反弹,因此当您按预期释放按钮时,您不确定LED是否会打开或关闭。这是一个离题的问题,应该单独提出。只是想给你一个在这里。

+1

这不是问题。根据数据表:写一个逻辑1到PINxn,切换PORTxn的值,独立于DDRxn的值。 请注意,SBI指令可用于切换端口中的单个位。 – KIIV

1

该代码很快就会更改该值,您将无法注意到任何更改。 每次按下按钮,它都会一直按住它的整个时间的值。您应该添加一些延迟,或者干脆忽略开启状态一段时间。此外,你应该从PIND中选择你想要的东西,掩盖它(最简单的方法就是使用andi)。

.def del = r15 
    clr del 
switch: 
    in temp, PIND   ; get state of pins on Port D 
    andi temp, (1<<PD0) ; you should mask to get only what you want 
    cpi temp, 0   ; compare result to 0 (pushbutton is pressed) 
    brne switch   ; if != 0, go check again 
    cpi del, 0    ; compare del to 0 
    brne dec_jmp   ; if != 0, ignore this run 
    ldi temp, (1<<PB0)  ; otherwise, write logic 1 to pin 0 of Port B 
    out PINB, temp   ; which toggles the state of the pin 
    ldi del, 250   ; next one will be ignored for 250 runs 

dec_jmp: 
    dec del    ; decrement del 
    rjmp switch 
0

您可以通过使用NOT操作

ldi temp2,0 
switch: 
in temp,PIND 
andi temp,1 ; remove all results except bit.0 
cpi temp,0 ; if pressed (i assume the button is active low) 
brne switch ; loop again if not pressed 
mov temp2,!temp2 ; not operator 
out PORTB,temp2 ; toggle PORTB output 
rjmp switch  ; back to main loop