I've been trying this for days without success...
I need to turn on a LED on portb when a button in portd is pushed. Cabling works, I've tested it with Arduino IDE and it works like a charm.
This is what I got so far:
.global main
.equ LED, PB5
.equ BUTTON, PD3
main:
ldi r22,0xff ;all bits in portb are output
out _SFR_IO_ADDR(DDRB),r22
ldi r21,0x00 ;all bits in portd are input
out _SFR_IO_ADDR(DDRD),r21
ldi r19, 0b00000000 ;unpushed button
ldi r18, 0b00100000 ;pushed button
eor r16, r16
loop:
out BUTTON, r16 ;read button to r16
cp r16, r18 ;compare r16 with r19 (button on)
cbi _SFR_IO_ADDR(PORTB),LED
breq loop ;go back to loop
sbi _SFR_IO_ADDR(PORTB),LED ;if z=1, turn led on turn led on
rjmp loop ;back to loop
It is much easier with sbis
, if I got it right...
#include <avr/io.h>
.equ LED, PB5
.global main
ldi r16,0xff
out _SFR_IO_ADDR(DDRB),r16
ldi r16,0x00
out _SFR_IO_ADDR(DDRD),r16
main:
sbis portd, 3
rjmp ledoff
ldi r16,0xff
sbi _SFR_IO_ADDR(PORTB),LED ; turn on led
rjmp main
ledoff:
ldi r16,0x00
cbi _SFR_IO_ADDR(PORTB),LED ; turn off led
rjmp main
But I got this error compiling:
.pio\build\uno\src\main.o: In function `main':
(.text+0x8): undefined reference to `portd'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\uno\firmware.elf] Error 1
1 Answer 1
This line:
ldi r18, 0b00100000 ;pushed button
does not match the definition of BUTTON
. You are setting bit 5 of
the register, whereas the button is on bit 3. In order to avoid
this kind of error, I would rather write
ldi r18, _BV(BUTTON) ;pushed button
Then, here:
out BUTTON, r16 ;read button to r16
you are not reading anything: you are writing somewhere. I guess you mean:
in r16, _SFR_IO_ADDR(PIND) ;read button to r16
Note that this reads the whole port at once. If you are only interested in one bit, you should then
andi r16, _BV(BUTTON) ;keep only the relevant bit
before the comparison.
One last thing: you may want to read about the sbis
and sbic
instructions: they could simplify the code you have here.
Edit: answering the updated question.
undefined reference to `portd'
This is because there is no such thing as "portd". You mean
_SFR_IO_ADDR(PORTD)
. Well, no, you should actually use
_SFR_IO_ADDR(PIND)
, as this is the port input register, whereas
PORTD
is the output register.
A couple of extra notes:
- Do not put code before
main
: it will not be executed, as the C runtime jumps tomain
after its initialization. - The instructions
ldi r16, ...
within the main loop serve no purpose: you are not using this register after the program initialization.