Код сборки Arduino Uno R3 для нажатия кнопки и включения светодиода

avr assembly platformio

Я пытался это сделать уже несколько дней, но безуспешно...

Мне нужно включить светодиод на порте при нажатии кнопки в порте. Кабель работает, я тестировал его с помощью Arduino IDE, и он работает просто великолепно.

Вот что у меня получилось:

.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

С sbis гораздо проще, если я все правильно понял...

#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

Но при компиляции я получил вот такую ошибку:

.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

, 👍3


1 ответ


Лучший ответ:

5

Эта строка:

   ldi r18, 0b00100000             ;pushed button

не соответствует определению BUTTON. Вы устанавливаете бит 5 регистре, тогда как кнопка находится на бите 3. Во избежание такого рода ошибка, я бы лучше написал

   ldi r18, _BV(BUTTON)            ;pushed button

Тогда вот:

   out BUTTON, r16                 ;read button to r16

вы ничего не читаете: вы куда-то пишете. я думаю, вы имею в виду:

   in r16, _SFR_IO_ADDR(PIND)      ;read button to r16

Обратите внимание, что при этом считывается весь порт одновременно. Если вам интересно только в один момент, тогда вам следует

   andi r16, _BV(BUTTON)           ;keep only the relevant bit

перед сравнением.

И последнее: возможно, вам захочется прочитать о sbis и sbic инструкции: они могли бы упростить ваш код.


Обновлено: ответ на обновленный вопрос.

неопределенная ссылка на `portd'

Это потому, что не существует такого понятия, как «portd». Ты имеешь в виду _SFR_IO_ADDR(PORTD). Ну нет, на самом деле вам следует использовать _SFR_IO_ADDR(PIND), так как это регистр входного порта, тогда как PORTD — это выходной регистр.

Несколько дополнительных примечаний:

  • Не помещайте код перед main: он не будет выполнен, так как C среда выполнения переходит к main после инициализации.
  • Инструкции ldi r16, … внутри основного цикла бесполезны: вы не используете этот регистр после инициализации программы.
,