![]() |
![]() |
|||||||||||||||
Создание функций в Ассемблере. Бегущий огонек v1.1
Автор: На данный момент у нас уже бежит огонек, и мы бесконечно этому рады. Однако, программа, увы и ах, оставляет желать лучшего по своей компактности. Вот как выглядит ее алгоритм (без настройки портов):
1.Вывод 00000001 А теперь посмотрите: все задержки как две капли воды похожи друг на друга. Так зачем же прописывать тыщу раз одно и то же? Надо написать задержку один раз, а потом обращаться к ней столько, сколько нужно! Те, кто учил языки высокого уровня, знакомы с понятием "функция". Так вот, нам нужно оформить задержку именно как функцию. Для этого, познакомимся еще с парой команд:
rcall - (Relative Call) - вызов подпрограммы Вообще, что такое метка и как происходит переход? В самом самом начале, мы говорили что программа контроллера записана в ПЗУ. Причем, каждая команда имеет свой уникальный адрес. Существует счетчик адресов, который последовательно вызывает команды данной программы. Так вот, при компиляции кода, компилятор заменяет все наши метки на соответствующие им адреса ПЗУ, и вычисляет расстояние от каждой метки до каждой команды, обращающейся к этой метке. Почему, собственно, команды называются rjmp (RELATIVE jump), rcall (RELATIVE call) - потому что они содержат не абсолютный адрес метки, а относительный. То есть - число, на которое нужно увеличить/уменьшить текущий адрес ПЗУ, чтоб оказаться на метке. Когда при выполнении программы, процессор натыкается, скажем, на команду rjmp, он берет из нее число и прибавляет его к значению счетчика адресов ПЗУ...
Команда rcall отличается от rjmp лишь тем, что прежде чем изменить текущее значение счетчика,
оно записывается в ОЗУ. Далее - прибавляем константу и переходим к выполнению подпрограммы. Для того, чтобы команда rcall смогла работать, нам надо-таки инициализировать стек. То есть - поставить указатель стека.
Что такое СТЕК? Ну так вот, для того чтоб стек стал работать, нам нужно указать адрес ОЗУ, который станет "дном рюкзака". Каждый следующий байт будет сохраняться в ячейке памяти с адресом, на 1 меньше предыдущего. Обычно, указатель стека ставится на последний адрес ОЗУ. Это делается так:
ldi Temp,RamEnd ;загрузить в Темп адрес последней ячейки ОЗУ
RamEnd - это константа, равная значению последнего адреса ОЗУ. Она инициализируется в файле def.inc.
Почему LOW? Дело в том, что в контроллере 2313 разрядность адреса ОЗУ не превышает 8 бит.
Значит, и указатель стека должен быть 8-битным. Для его хранения, соответственно, используется один 8-битный регистр. Это было лирическое отступление…
Итак, давайте перепишем нашу программу, выделив задержку как отдельную подпрограмму (функцию, если хотите).
.cseg Ну вот, теперь наша программулина стала намного компактнее. Однако, это не предел! Дальше я расскажу, как можно еще сильнее ее уменьшить :) <<--Вспомним пройденное----Поехали дальше-->>
|
|
|||||||||||||||
![]() |
![]() |


![]() |
![]() |
|||
|
||||
![]() |
![]() |