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
mcflurry
  • 41
  • 4

1 Answers1

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.
Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81