2016-09-07 86 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