Применение подпрограмм при программировании.

При написании программ часто при реализации алгоритма работы устройства приходится повторять одни и те же операторы (например, операторы, работающие с параллельным или последовательным портом). Было бы неплохо использовать один и тот же участок кода, вместо того, чтобы повторять одни и те же операторы несколько раз.

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

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

Рис. 3.2. Иллюстрация состояния программного счетчика при работе с подпрограммами

Для того, чтобы получить возможность возвращаться на команду, следующую за командой вызова подпрограммы, требуется запомнить адрес этой команды. Адрес возврата хранится в особых ячейках памяти. После выполнения подпрограммы необходимо осуществить переход к адресу, который записан в этих ячейках.

Для обращения к подпрограмме и возврата из нее в систему команд микропроцессоров вводят специальные команды. В микроконтроллерах семейства MCS-51 это командыLCALL, ACALL для вызова подпрограммы и команда RET для возврата из подпрограммы.

Пример использования подпрограммы:

...

MOV A,#56

CALL PeredatByte

...

MOV A,#37

CALL PeredatByte

...

;********************************************

;Подпрограмма передачи байта

;через последовательный порт

;********************************************

PeredatByte:

JB TI,$ ;Если предыдущий байт передан

MOV SBUF,G_Per ;то передать очередной байт

RET

Внимание! Ни в коем случае нельзя попадать в подпрограмму любым способом кроме команды вызова подпрограммы CALL! В противном случае команда возврата из подпрограммы передаст управление случайному адресу! По этому адресу могут быть расположены данные, которые в этом случае будут интерпретированы как программа, или обратиться к внешней памяти, откуда будут считываться случайные числа.

Очень часто требуется из одной подпрограммы обращаться к другой подпрограмме. Такое обращение к подпрограмме называется вложенным. Количество вложенных подпрограмм называется уровнем вложенности подпрограмм. Максимально допустимый уровень вложенности подпрограмм определяется количеством ячеек памяти, предназначенных для хранения адресов возврата из подпрограмм.

Ячейки памяти, в которых хранятся адреса возврата из подпрограмм называются стеком. Логически эти ячейки памяти организованы так, чтобы считывание последнего записанного адреса производилось первым, а первого записанного адреса производилось последним. Такая логическая организация формируется специальным счетчиком. Этот счетчик называется указателем стека SP. Ячейка памяти, в которую в данный момент может быть записан адрес возврата из подпрограммы, называется вершиной стека. Количество ячеек памяти, предназначенных для организации стека, называется глубиной стека. Последняя ячейка памяти, в которую можно производить запись называется дном стека. Логическая организация стека приведена на следующем рис. 3.3.

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

каждом конкретном случае устанавливать необходимую для программы глубину

стека. Оставшуюся память можно использовать для размещения глобальных и

локальных переменных программы. Глубина стека устанавливается при помощи

Рис. 3.3. Логическая организация стека

записи начального адреса вершины стека в указатель стека. Глубина стека устанавливается один раз после включения питания в процедуре инициализации контроллера.

Глобальными называются переменные, используемые при выполнении всей программы, включая микропрограммы.

Локальными называются переменные, используемые только данной подпрограммой.

Например, в микроконтроллерах семейства MCS-51 при занесении информации в стек содержимое указателя стека увеличивается - стек растет вверх, поэтому стек размещается в самой верхней части памяти данных. Для того, чтобы установить глубину стека 28 байт, необходимо вычесть из адреса максимальной ячейки внутренней памяти микроконтроллера глубину стека и записать полученное значение в указатель стека SP:

Кроме содержимого программного счетчика часто требуется запоминать содержимое внутренних регистров и флагов процессора, локальных переменных подпрограммы. Стек оказался удобным средством и для этой задачи. Сохранение локальных переменных в стеке позволило осуществлять вызов подпрограммы самой из себя (реализовывать рекурсивные алгоритмы). Это привело к введению в систему команд специальных команд работы со стеком. В микроконтроллерах семейства MCS-51 это команды PUSH и POP. Использование этих команд показывается на следующем примере:

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