Сборка для цикла, повторяющегося 2 раза, хотя предполагается, что это нужно сделать только один раз

Я программирую Arduino Nano, поэтому считаю, что этот вопрос подходит для этого SE.

Я пытаюсь уменьшить яркость светодиода с помощью цикла for в сборке AVR.

Моя проблема в том, что цикл повторяется дважды перед завершением, хотя предполагается, что он закончится после первого цикла.

Цикл — это когда red_loop повторяется 256 раз (чтобы затемнить светодиод). В этот момент значение должно переполниться, в результате чего переменная вернется к 0. Код должен остановиться на этом, но загадочным образом он выполняет еще один цикл, а затем останавливается.

Кто-нибудь знает почему?

Вот мой код:

.org 0x000

ldi r16, 0b111
out ddrb, r16

ldi r16, 0xff
out portb, r16

ldi r16, 0

; ff00 pin
; ff01 value
; ff02 led

ldi r16, 0b000
sts $ff00, r16

ldi r16, 0
sts $ff01, r16

red:
    ldi r16, 0b001
    sts $ff00, r16

red_loop:
    rcall pwm

    lds r16, $ff01
    inc r16
    sts $ff01, r16
    cpi r16, 0
    brne red_loop

end:
    rjmp end

pwm:
    ldi r24, 190

pwm_pre_loop:
    ldi r17, 0

pwm_loop:
    lds r16, $ff01
    cp r17, r16
    brge off

    cp r17, r16
    brlo on

pwm_loop_check:
    inc r17
    cpi r17, 0
    brne pwm_loop

    inc r24

    cpi r24, 0
    brne pwm_pre_loop

    ret

on:
    lds r16, $ff00

    sbrc r16, 0
    cbi portb, 0

    sbrc r16, 1
    cbi portb, 1

    sbrc r16, 2
    cbi portb, 2

    rjmp pwm_loop_check

off:
    lds r16, $ff00

    sbrc r16, 0
    sbi portb, 0

    sbrc r16, 1
    sbi portb, 1

    sbrc r16, 2
    sbi portb, 2

    rjmp pwm_loop_check

, 👍1

Обсуждение

вы не сказали, что означает cycle, поэтому я предполагаю, что это означает red_loop..... вы уверены, что red_loop повторяется только два раза?.... я не очень знаком с инструкциями по сборке avr, но похоже, что red_loop повторяется гораздо больше двух раз, @jsotola

Сборка AVR - это не Arduino, @Juraj

Что это за ардуино? Если у вас нет памяти вроде 64 КБ, $ff00 будет вне диапазона., @Edgar Bonet

Я предлагаю переписать этот код на C и взглянуть на ассемблерный вывод компилятора в качестве справочного материала. Кроме того, возможно, было бы неплохо передать это в симулятор. Например, http://www.avr-asm-tutorial.net/avr_sim/index_en.html., @ex-punctis

@jsotola цикл — это когда red_loop повторяется 256 раз. После этого значение переполнится, что приведет к тому, что значение будет равно 0. В этот момент. Это должно прекратиться, @Dat Ha

@Juraj Я программирую Arduino Nano, поэтому этот вопрос должен быть квалифицирован для этого сайта., @Dat Ha

@ЭдгарБонет. Удивительно, но я могу без проблем писать в $ff00. Теперь, когда я об этом думаю, немного странно, что это вообще возможно..., @Dat Ha

Адрес будет просто «зацикливаться», а старшие биты будут отброшены., @Majenko

SRAM начинается с адреса 0x100 — вы должны использовать его в качестве базы для доступа к памяти., @Majenko

Чтобы облегчить себе задачу, вам следует определить свои переменные в .DSEG, чтобы вам не приходилось беспокоиться об адресах. (и не забудьте убедиться, что ваш код находится в формате .CSEG...), @Majenko

вы уверены, что red_loop запускается дважды? .... как вы это определяете?, @jsotola

@jsotola red_loop на самом деле выполняется 512 раз (2 раза по 256). Я хочу, чтобы он запускался только 256 раз. Я знаю это, потому что у меня есть светодиод, подключенный к нему, и предполагается, что он постепенно загорится только один раз. Но вместо этого он один раз постепенно загорается, затем гаснет и повторяет это снова. Потом это прекращается., @Dat Ha

все может быть не так, как вы думаете..... возможно, светодиод циклически переключается на 128 шагов, @jsotola


1 ответ


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

1

Проблема в том, что регистр r17, который вы используете в качестве тайминга ШИМ, Ramp, переполняется дважды каждый раз, когда вы вводите pwm_pre_loop:

  • когда вы увеличиваете его больше 127, оно переполняется до −128.
  • когда вы увеличиваете его больше 255, оно переполняется до 0.

При использовании счетчика так, как вы используете здесь r17, у вас обычно есть он переполняется только один раз за цикл: либо вы считаете, что он содержит знак число, которое переполняется от 127 до −128, или вы считаете, что оно содержит беззнаковое число, которое переполняется от 255 до 0. Я думаю, последнее чаще. Ваш код не понимает подписи этого регистра:

  • Инструкция brge (названная «Перейти, если больше или равно (подписано)» в в таблице набора команд) проверяет бит S (знаковый флаг) регистр состояния, который полезен для подписанных сравнений.

  • Инструкция brlo («Перейти, если меньше (без знака)») проверяет перенос флаг, который используется для сравнений без знака.

Следует один раз определиться с подписанностью счетчика, а затем использовать его последовательно. Поскольку здесь беззнаковый имеет больше смысла, вы можете просто заменить brge от brsh («Перейти, если то же самое или выше (без знака)»).

Или еще лучше, удалите второй тест, он лишний:

pwm_loop:
    lds r16, value
    cp r17, r16
    brsh off  ; if (r17 >= r16) goto off;
    rjmp on   ; else goto on;

Обратите внимание, что вы можете давать имена переменным оперативной памяти. И вы можете использовать некоторые другие доступные регистры вместо ОЗУ.

,