|
|||||||
Структура программы на Ассемблере в AVR Studio
Время создания: 02.12.2021 17:33
Раздел: Компьютер - Программирование - Ассемблеры - Архитектура AVR - Ассемблер в AVR Studio
Запись: xintrea/mytetra_syncro/master/base/1638455582remgd4m5u3/text.html на raw.github.com
|
|||||||
|
|||||||
Рассмотрим синтаксические особенности ассемблера AVR на примере небольшой тестовой программы для микроконтроллера ATmega8, приведенной ниже. Программа формирует на выводе PB2 импульсы с частотой следования ≈ 2.5 Гц при частоте внутреннего RC-генератора 1 МГц.
В строках 1…3 приведено 3 возможных варианта оформления комментариев. Комментарий в строке 1, начинающийся со знака “;”, распознается любым ассемблером и поэтому является наиболее предпочтительным. Комментарии в строках 2 и 3 подобны тем, которые используются в нотациях языков высокого уровня. Последний из них дает возможность выделить сразу несколько строк (маркерами начала и конца фрагмента текста является “/*” и “*/” соответственно). В строке 5 директивой .include к программе подключается стандартный заголовочный файл "m8def.inc". Необязательные директивы .nolist и .list (строки 4 и 6 соответственно) запрещают вывод содержимого подключаемого файла в файл листинга. Все директивы допускается размещать в одной строке. Так, например, можно было бы записать Несмотря на это, желательно придерживаться правильного стиля программирования, в соответствии с которым в одной строке должна быть расположена только одна директива ассемблера. Объявление констант находится в строках 7 и 8. Константе LED присваивается номер линии ввода-вывода PB2 = 2, описание которой находится в заголовочном файле. В строках 9 и 10 двум рабочим РОНам назначаются пользовательские имена. Секция рабочего кода открывается директивой .cseg в строке 11. Директива .org 0 (строка 12) устанавливает начальный адрес в памяти программ. В строке 13 должна находиться инструкция перехода на метку начала основной программы initial. Метка представляет собой адрес в пределах секции кода или данных. В ассемблере AVR она должна быть записана в начале строки и завершаться в конце двоеточием. Конечно, адрес в команде может быть указан и явно. В данном примере его можно задать безошибочно (rjmp 0x20 вместо rjmp initial). Но, это возможно только потому, что директива .org 0x20 (строка 32) заставляет компилятор поместить команду в строке 33 по адресу 32-го слова FLASH-памяти программ. Однако, в большинстве случаев, адрес размещения той или иной команды заранее неизвестен и, кроме того, он может изменяться по мере того, как в программу будут вноситься изменения. Именно поэтому предпочтительней использовать метки. Назначение их адресов производится автоматически на этапе компиляции. Да и символьные имена меток, предоставляют об объектах намного больше информации, чем просо какие-то числа. На месте каждого неиспользуемого в программе прерывания желательно поставить “заглушки” в виде команды возврата rjmp 0 или reti, как это сделано в строках 14…31. В строках 33…39 производится инициализация ресурсов микроконтроллера. Любая программа обязательно должна начинаться с установки начального значения указателя стека (если он имеется). В строках 33…36 в SPH:SPL заносится значение RAMEND = 0x045F (вершина стека перемещается в самый верх SRAM). Для выделения младшего и старшего полубайтов константы RAMEND используются встроенные функции low(RAMEND)=0x5F и high(RAMEND)=0x04 соответственно. Далее разряд LED в регистре данных порта B сбрасывается на 0 (стока 37), а сама линия управления светодиодом настраивается на вывод (стока 38). В строке 39 в регистр temp заносится константа 1<
Код в строках 40…44 представляет собой тело основной программы. В регистр buffer считывается текущее состояние порта данных PORTB (строка 40). Далее между содержимым buffer и temp производится операция “Исключающее ИЛИ” (строка 41), после чего модифицированное содержимое buffer снова выводится в порт (строках 42). В результате такого действия логический уровень на линии PB2 изменится на противоположный. В строке 43 происходит вызов подпрограммы задержки времени delay (≈200 мс), а в строке 44 расположена инструкция перехода на метку main. Так образуется основной цикл программы, в котором происходит постоянное повторение операторов в строках 40…44: инвертирование уровня на выводе LED, задержка, затем снова инвертирование и т.д. Внутри подпрограммы delay в регистровую пару XH:XL заносится число PAUSE = 50000, определяющее длительность задержки времени (строки 45, 46). В строке 47 из содержимого XH:XL вычитается 1. Команда условного перехода в строке 48 проверяет, значение флага Z из SREG. Если Z = 1 (результат предыдущей операции не равен нулю), то управление передается на строку 47. Так будет повторяться до тех пор, пока не выполнится условие XH:XL = 0 (т.е. пока не пройдет 50000 циклов вычитания). Команда выхода ret в строке 49 возвращает управление в то место основной программы, с которого произошел вызов delay. Отдельно стоит обратить внимание на встроенную в ассемблер переменную PC в строке 48. Она представляет собой текущее содержимое программного счетчика. Адрес PC-1 будет указывать на предыдущее слово в памяти программ микроконтроллера. В данном случае в этом слове находится команда sbiw XH:XL,1. Использовать PC очень удобно для программных переходов в небольших пределах. Однако здесь всегда необходимо помнить, что у микроконтроллеров AVR имеются команды, которые имеют размер в 2 16-разрядных слова программ (lds Rd,k, jmp k и др.), из-за чего при вычислении смещения необходимо будет добавлять\отнимать к PC значение 2 вместо 1 на каждую такую инструкцию. Справа, в листинге приведен машинный код, который будет сгенерирован после компиляции программы. |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|