3

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
0

1 Answer 1

5

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 to main after its initialization.
  • The instructions ldi r16, … within the main loop serve no purpose: you are not using this register after the program initialization.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.