Найти тему

Заготовка программы на ассемблере

Ну вот ты решил делать прошивку, как все-таки организовать программу, чтобы она легко читалась и была возможность ее расширять? В этом плане лучше всего разделить ее на части (модули), отвечающие за отдельные функции системы/периферию. Рассмотрим пример:

Рисунок 1.- пример организации программы на ассемблере
Рисунок 1.- пример организации программы на ассемблере

Что здесь важно: программа начинает выполняться с метки Reset (адрес 0x0000), далее перескакивает на метку Init. Сегменте кода между rjmp Init и. самой меткой Init располагается таблица векторов прерываний (int_vectors.asm) и определяются подпрограммы их обработки (int_routines.asm). Так вот если в нашей программе используются прерывания, мы должны определить таблицу прерываний и сами обработчики прерываний/или поставить заглушки на них. Если мы этого не сделаем и разрешим прерывания, программа будет глючить и вот почему: в каждом контроллере есть прерывания и зарезервированы адреса, куда передается управление программы в случае возникновения оных. Эти адреса располагаются в самом начале сегмента кода за адресом 0x0000. То есть, если разрешены прерывания и не определены обработчики в положенном месте, то в случае прерывания управление передастся по вектору прерывания а там будет не обработчик, а просто какой-нибудь код.

В чипе AtMega32 определены следующие векторы прерываний:

Рисунок 2.-векторы прерываний AtMega32
Рисунок 2.-векторы прерываний AtMega32

Видим, что по адресу 0x0002 располагается точка перехода по внешнему прерыванию. Теперь включим эти векторы прерываний в тело программы и посмотрим листинг.

Рисунок 3. - программа с определенными векторам прерываний (некоторыми для примера)
Рисунок 3. - программа с определенными векторам прерываний (некоторыми для примера)

По адресам 0x0002 и 0x0004 расположены заглушки для внешних прерываний. Теперь рассмотрим программу без определения таблицы прерываний.

Рисунок 4. - программа без векторов прерываний
Рисунок 4. - программа без векторов прерываний

Что ты видишь? теперь по адресам прерываний 0x0002 и 0x0004 расположены команды загрузки в регистры ввода/вывода SPH и SPL регистра общего назначения r16. При этом значение r16 не определяется. Теперь рассмотрим ситуацию, что мы не определили векторы прерываний и их обработчики, глобально разрешили прерывания и получили аппаратно INT0 или INT1. Программа прекратит свое выполнение в перейдет по адресу прерывания, где ожидает обработчик, но там его нет. В итоге указатель на стек изменится и программа словит глюк, который трудноуловим.

За определением векторов прерываний идут определения процедур их обработки, ставим их поближе к началу кода, чтобы перехода rjmp хватало.

После этого инициализируем стек, он нужен при вызове подпрограммы, в него помещается адрес инструкции возврата из подпрограммы.

Далее за меткой MainLoop идет собственно основной цикл приложения.

В конце программы, за rjmp MainLoop, помещаем подпрограммы общего характера, такие как работа с периферией или задержками, вычисление функций и прочего.

Собственно все.

В процессе сборки ассемблер сперва создает единый файл, подставляя вместо .include текст включаемого файла, затем продолжает сборку.