Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #93, СЕНТЯБРЬ 2006 г.

Кодим жесть

Долин Сергей

Хакер, номер #093, стр. 093-024-3


Первая программа для микроконтроллера.

Все программисты начинали писать свои творения с примитивной программы «Hello World». Своеобразный «Hello World» для микроконтроллера – это процесс моргания светодиодом.

Собираем данную схему. У нас в арсенале имеются и разъем программирования, и светодиоды. Теперь нам нужен пакет для разработчиков на ассемблере – AVR Studio. Ставим, запускаем и жмем кнопку «New project». Выбиваем AVR Assembler и называем проект, например, Hello World. Жмем Next, выбираем AVR Simulator и тип микроконтроллера (в нашем случае — ATmega8535). Все. Теперь ваяем программу. Начинать кодинг следует с инклудника:

.include "m8535def.inc"

Данное включение определяет имена регистров, параметры стека и всякую системную инфу, которую можно посмотреть, заглянув в него. Данный инклуд для каждого МК будет свой, его необходимо найти самостоятельно, в папке с AVR Studio, или покопаться в инете. Далее следует описание переменных, но это необязательный процесс. Однако он облегчает читабельность и отладку нашей программы. Потом по нулевому адресу мы ставим безусловный переход на основной код.

.org 0

rjmp START

За переходом обычно находится таблица прерываний, но в нашей программе она не используется. Потом у нас идет инициализация стека.

START:

ldi R16,low(RAMEND)

out SPL,R16

ldi R16,high(RAMEND)

out SPH,R16

Это стандартная процедура, где мы определяем адресное пространство, где будет располагаться стек. Значения low(RAMEND) и high(RAMEND) определены в нашем подключаемом файле m8535def.inc. Затем мы инициализируем порты ввода/вывода. В нашем случае мы ставим PORTA на вывод.

ser R16

out DDRA, R16

Командой ser мы загружаем в регистр R16 значение FF. Далее мы устанавливаем в регистре DDRA все пины порта А на вывод. Если установить какой-либо бит в ноль, то это будет означать, что данный пин порта будет работать на ввод. После всех инициализаций начинается основная программа, которая бегает в бесконечном цикле.

LOOP:

ldi R17, 1

out PORTA,R17

ldi R20,50

rcall WAIT

...

rjmp LOOP

Тут мы по очереди загружаем в регистр R17 значение 1,2,4,8 и выводим их в порт, затем вызываем процедуру задержки (весь листинг программы лежит на диске). Получается, что у нас по очереди будут зажигаться светодиоды сначала на нулевой ножке порта А, потом на первой и т.д. С некоторой задержкой, определяемой в процедуре WAIT:

WAIT:

dec R18

brne WAIT

dec R19

brne WAIT

dec R20

brne WAIT

ret

Данная процедура работает следующим образом: уменьшает регистр-счетчик R18 и переходит на метку WAIT, если он не стал нулем. Если он стал нулем, то пропускает эту команду и уменьшает регистр R19 и снова начинает уменьшать регистр R18. Данная процедура рассчитывается по тактам. То есть верхняя часть будет равна числу 256*3, потом умножаем это число снова на 256, потом умножаем на число, записанное в регистр R20, перед вызовом процедуры (у нас 50). Получаем 9830400 тактов, что при частоте внутреннего таймера 1 МГц даст задержку примерно 10 секунд. При частоте 4 МГц будет уже 2,5 секунды.

Назад на стр. 093-024-2  Содержание  Вперед на стр. 093-024-4