Например TDA7294

РадиоКот >Обучалка >Микроконтроллеры и ПЛИС >Микроконтроллеры AVR - пишем, компилируем, прошиваем... >

Бегущий огонек v1.0

Ну вот, что-то уже сделали. По крайней мере, наша железка перестала быть ничего не делающей. Теперь на ней светятся некоторые светодиодики…

Сейчас мы немного отвлечемся от светодиодиков и поговорим о такой страшной вещи как ветвящийся алгоритм.

Алгоритм - это некоторая последовательность команд. Это вы, надеюсь знаете.
Линейный алгоритм - это такой алгоритм, в котором команды выполняются в строго определенной последовательности, и этому ничто не может помешать.
Пример линейного алгоритма:

1.Прийти домой
2.Подойти к холодильнику
3.Взять банку Kitekat
4.Покормить кота…

Нелинейный (ветвящийся) алгоритм, выглядит так:

1.Прийти домой
2.Подойти к холодильнику.
3.Если в холодильнике есть банка Kitekat - взять ее, иначе взять банку пива.
4.Если взяли Китекет - покормить кота, иначе налить содержимое банки в кружку…

Ветвящийся алгоритм отличается от линейного тем, что в зависимости от каких-то воздействий, он может выполняться либо так, либо сяк, либо эдак, либо хрен знает как… Линейный алгоритм от начала до конца выполняется в одной и той же последовательности.

Ветвящимся алгоритм делают именно команды выбора:
Если() - тогда(), иначе()

В ассемблере тоже есть такие команды. Сегодня мы рассмотрим некоторые из них.

brne (Branch if Not Equal) - переход к метке, если результат предыдущего действия - не ноль

Пример:
brne Label - перейти к метке Label.

Кстати! Я ж еще не рассказал про метки!
Рассказываю. Метка обозначает какое-то место в программе, позволяя тем самым в любой момент "перепрыгнуть" в это место, не выполняя операции, стоящие раньше этой метки.
Каждая метка имеет свое единственное и неповторимое имя внутри одной программы. Причем, Ассемблер абсолютно не чувствителен к регистру, поэтому, имена Label, label и LABEL - для компилятора совершенно идентичны. Так что, если вы выросли на C++, срочно отвыкайте от привычки баловаться с регистром.

В Асме метка ставится так:

          ...
          and Temp1,Temp3
Label:   ldi Temp1,14
          mov Temp,Temp1
          ...

То есть, при переходе на метку Label, программа начнет выполняться с команды "ldi Temp1,14".

Кстати, перейти на метку можно не только по условию, но и за "просто так". Такой переход называется безусловным:

rjmp - безусловный переход к метке

Пример:
rjmp Label

Ну и для полной красоты, вот еще несколько условных переходов:

breq - (Branch if Equal)переход, если результат предыдущего действие - ноль
brmi - (Branch if Minus) переход, если результат отрицателен. (При этом, число 0 считается положительным.)
brpl - (Branch if Plus) переход, если результат положителен

Все, теперь можно писать ветвящийся алгоритм.

Но до того, вот вам еще две команды:

inc - (Increment) увеличение значения РОН на 1 (инкремент)
dec - (Decrement) уменьшение значения на 1 (декремент).

Пример:
inc Temp2
dec Temp3

Ну а теперь, скажите мне, как работает вот такая программа:

          ldi Temp,0

Loop:     dec Temp
          brne Loop

Сначала мы инициализировали Temp числом 0. Далее из Temp вычитается 1. Его значение становится -1 (иначе говоря, 255). Далее мы проверяем, не получился ли у нас ноль. Поскольку число 255 не равно нулю, нас снова перекидывают на операцию декремента. Значение Temp уменьшается еще на 1. Теперь оно - 254. Но это тоже - явно не ноль, и нас снова кидают в начало… И так до тех пор, пока в один прекрасный момент в ответе не получится 0. Как только сие свершилось, нас "отпускают" из цикла дальше…

То что мы только что рассмотрели, называется циклом задержки. Почему? Да потому что, этот кусок программы по сути - ничего толкового не делает, но жрет процессорные такты, а стало быть - время. Однако, нам этот цикл задержки очень пригодится. Он будет определять скорость "бега" огоньков.

Кстати, можно делать несколько вложенных циклов задержки:

          ldi Temp1,0
          ldi Temp2,0
          ldi Temp3,10

Loop:     dec Temp1
          brne Loop

          dec Temp2
          brne Loop

          dec Temp3
          brne Loop

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

.cseg
.org 0

          ldi Temp,0b11111111  ;настройка порта B
          out DDRB,Temp

Begin:    ldi Temp,0b00000001  ;зажигаем 1-й светодиод
          out PortB,Temp

          ldi Temp1,0          ;задержка
          ldi Temp2,0
          ldi Temp3,10

Loop1:    dec Temp1
          brne Loop1

          dec Temp2
          brne Loop1

          dec Temp3
          brne Loop1



          ldi Temp,0b00000010  ;зажигаем 2-й светодиод
          out PortB,Temp

          ldi Temp1,0          ;задержка
          ldi Temp2,0
          ldi Temp3,10

Loop2:    dec Temp1
          brne Loop2

          dec Temp2
          brne Loop2

          dec Temp3
          brne Loop2



          ldi Temp,0b00000100  ;зажигаем 3-й светодиод
          out PortB,Temp

          ldi Temp1,0          ;задержка
          ldi Temp2,0
          ldi Temp3,10


Loop3:    dec Temp1
          brne Loop3

          dec Temp2
          brne Loop3

          dec Temp3
          brne Loop3



          ldi Temp,0b00001000  ;зажигаем 4-й светодиод
          out PortB,Temp

          ldi Temp1,0          ;задержка
          ldi Temp2,0
          ldi Temp3,10

Loop4:    dec Temp1
          brne Loop4

          dec Temp2
          brne Loop4

          dec Temp3
          brne Loop4


          rjmp Begin


Программа написана только для 4-х светодиодов. Я думаю, что дописать код для остальных светодиодов не составит большого труда.

Ну, как всегда: компилируем, шьем, наблюдаем…

Я думаю, что без лишних комментариев понятно, что программа получилась громоздкая. В следующий раз, мы поговорим о том, как ее оптимизировать.

<<--Вспомним пройденное----Поехали дальше-->>


Как вам эта статья?

Заработало ли это устройство у вас?

28 0 0
15 3 0