0
votes

I want to create a program in AVR assembly that will poll the state of a momentary pushbutton switch and toggle the state of an LED whenever the switch is pressed. I am using an Arduino Duemilanove with an ATMega328P chip. I have a pushbutton switch connected between digital pin 0 and ground, and an LED with 330 ohm resistor connected between digital pin 8 and +5V. Here is my code so far:

;==============
; 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

Unfortunately all this does is light the LED and keep it on no matter how many times the button is pushed. I am basing this code off of a program found here that turns the LED on as long as the button is pushed. I simply want to extend that to hold the LED in its current state until the button is pushed again. Any suggestions?

3
You should compare only PIND0 to 0 by using a mask not whole PIND. Especially if your port is left floating (the lighting on the diode may change the level of floating pin and make the cpi temp, 0 always wrong). Also, you may use the SBI instruction to change single bits in PINB. Not sure this will work but I do not see other problems for the moment. - Julien
Buttons Bounce. This does not matter in the sample code, but in your case you'll receive random results, even after @Julien's hint. - datafiddler
I've tried to wrap my head around how to write a logic 1 to just PB0 using sbi, but I can't seem to make it work. Using ` sbi PORTB0, 1` does not give the expected results. I see your point about button bounce though. Maybe a delay subroutine somewhere in the main loop would debounce the switch? - Josh Benson
@JoshBenson my understanding of datasheet is sbi PORTB, 0 (no need for a 1 as Sbi is for set bit (cbi clear bit)). Yes some delay after a press detection would debounce - Julien

3 Answers

1
votes

This code changes the value so quickly, that you won't be able to notice any change. Everytime you press the button, it will keep toggling the value for whole time it's pressed down. You should add some delay or simply ignore the on state for some time. Also, you should pick up from PIND only what you want, by masking it (easiest way is to use 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
1
votes

you can toggle it by using NOT operator

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
-1
votes

Your only ever writing a HIGH to PB0. Each time the key is pressed you need to invert the pins state for example

in  temp, PORTB
com temp
out PINB, temp

As you've previously set temp to 1 then 1's compliment would change it to 11111110 thus writing a zero to PINB0 and the next time it would be 00000001 turning the led back on.

This over simplistic solution has an unpredictable side affect in that it doesn't take bounce into consideration, therefor you're not really guaranteed the LED will be on or off when you release the button as expected. That is a question that digresses from the scope of this one and should be asked separately. Just wanted to give you a heads up here.