Регистры общего назначения, регистры ввода/вывода, стек, счетчик команд
Процессорное ядро микроконтроллеров:
- регистры общего назначения
– регистры ввода/вывода
– стек
– счетчик команд
Доброго дня уважаемые радиолюбители!
Приветствую вас на сайте “Радиолюбитель“
Сегодня мы с вами продолжим более подробное изучение процессорного ядра микроконтроллера.
В прошлый раз мы рассмотрели арифметико-логическое устройство и организацию памяти микроконтроллера. В этой статье я постараюсь кратко, но и в тоже время как можно подробнее рассмотреть оставшиеся вопросы:
- регистры общего назначения
– регистры ввода/вывода
– стек
– счетчик команд
и очень подробно, но чуть позже, рассмотрим порты ввода/вывода.
Регистры общего назначения
Регистры общего назначения в любом микроконтроллере играют очень важную роль. В дальнейшем я буду сокращать их название – писать просто РОН.
РОН принимают участие в выполнении практически всех команд МК, и практически все данные проходят через них. В микроконтроллерах AVR имеется 32 РОН (и это очень хорошо, что их так много. А к примеру, в МК PIC – всего один регистр).
Каждый РОН имеет свое имя: R0, R1, R2 ….. R29, R30, R31. Все РОН объединяются в один файл, который называется файл регистров общего назначения. Регистры общего назначения восьмиразрядные (однобайтовые). Каждому РОН в области памяти данных (SRAM) отведен свой адрес – они занимают ячейки памяти с “нулевой” по “тридцать первую”, или в шестнадцатиричном исчислении – от $00 (0х00) до $1F (0x1F). Т.е., получается, что ячейки памяти SRAM с 0 по 31, одновременно являются и регистрами общего назначения. Мы можем в программе прописать команду: “записать 255 в регистр R31″, а можем прописать: “записать 255 в 31 ячейку памяти данных”, – результат будет один и тот же.
Надо помнить, что физически РОН (как и рассматриваемые ниже регистры ввода/вывода) не входят в память данных, но для повышения эффективности работы МК и его производительности, РОН (и регистры ввода/вывода) располагаются в адресном пространстве памяти данных, и к ним можно обращаться как по их именам, так и как к ячейкам памяти ОЗУ (SRAM).
Так как все РОН восьмиразрядные (однобайтовые) то и оперировать они могут только с однобайтными данными. В случае, если необходимо проводить операции с двухбайтными данными (шестнадцатиразрядными), то РОН с R26 по R31 могут образовывать сдвоенные регистры, которые в свою очередь могут выступать в роли самостоятельных шестандцатиразрядных регистров и тогда они имеют другие имена (такие сдвоенные регистры иногда называют “словом”, по аналогии с ячейками памяти программ):
R26 и R27 – сдвоенный регистр “Х”,
R28 и R29 – сдвоенный регистр “Y”,
R30 и R31 – сдвоенный регистр “Z”.
При этом первый регистр в такой паре (R26, или R28, или R30) играет роль младшего байта и обозначается дополнительной буквой “L”. Например: XL, YL, ZL.
Второй регистр в паре играет роль старшего байта и обозначается дополнительной буквой “H”. Например: XH, YH, ZH.
Это позволяет нам записать (или считать значение), к примеру, двухбайтовое число непосредственно в двойной регистр, обратившись к его буквенному обозначению X, Y или Z, а также считать любой байт (или записать в любой байт) выбрав буквенное обозначение младшего или старшего байта двойного регистра (к примеру XL или XH).
Кроме того необходимо помнить, что хотя и все регистры общего назначения одинаковы, но не все из них могут участвовать в некоторых операциях. При этом, регистрам с R16 по R31 доступны все операции, а регистрам с R0 по R15 – не все.
И еще. В некоторых МК (Tiny) двойной регистр только один – Z (R30,R31).
В описание каждой команды указывается, какие РОН могут участвовать в данной операции, к примеру:
Регистры ввода/вывода
Как мы уже знаем, в МК присутствует много различных периферийных устройств. Кроме них, в МК есть и внутренние устройства. Всеми этими устройствами необходимо управлять, задавать необходимые режимы работы. Для этих целей в МК существуют регистры ввода/вывода.
Все регистры ввода/вывода (в дальнейшем буду писать РВВ) условно можно разделить на два типа:
- служебные регистры микроконтроллера
- регистры, относящиеся к конкретным периферийным устройствам
Все регистры ввода/вывода (как и РОН) занимают свое адресное пространство в памяти данных (SRAM) – от 32 до 95 (или в шестнадцатиричном счислении от $20 до $5F) и идут сразу за регистрами общего назначения, в так называемом адресном пространстве ввода/вывода. Каждый регистр восьмиразрядный и занимает память в один байт.
Всего МК может иметь 64 регистра ввода/вывода – максимальное число (за редким исключением). В тоже время, если МК простенький и в нем мало устройств, и он использует меньшее число РВВ, в области памяти данных все равно резервируется 64 адреса. Некоторым, слишком навороченным МК, стандартного значения в 64 РВВ недостаточно. В таких МК в адресном пространстве памяти данных выделяется еще дополнительно 160 ячеек памяти для дополнительных регистров ввода/вывода.
Еще раз напомню, что хотя РОН и РВВ выделяется место в памяти данных, но доступное пространство памяти данных для нас от этого не уменьшается, ведь физически они там не располагаются. Если написано, что МК имеет память данных 128 байт, то значит мы можем использовать эти 128 байт в своих целях. Просто первый адрес памяти данных будет начинаться не с нуля, как в памяти программ или энергонезависимой памяти.
Каждый регистр ввода/вывода имеет свой номер – от 0 до 63 (или в шестнадцатиричном виде – от $00 до $3F), который соответствует его адресу в адресном пространстве ввода/вывода. Адрес РВВ в адресном пространстве ввода/вывода и адреса соответствующих им ячеек в ОЗУ (памяти данных) не совпадают. Если регистр имеет номер 0, то в адресном пространстве ОЗУ он будет занимать 32 ячейку памяти (ведь сначала идут 32 регистра общего назначения, а за ними уже – РВВ). Для определения адреса РВВ в области памяти данных необходимо прибавить к его номеру 32.
Помимо номера, каждый регистр имеет свое имя (буквенную аббревиатуру) – для удобства программистов.
Для разных МК имена регистров, имеющих одинаковое назначение, обычно совпадают, а вот номер регистра может отличаться. Но это не так и важно, потому, что при программирование оперируют в основном именами регистров.
К примеру, для управления портом ввода-вывода (а их мы рассмотрим очень подробно в следующей статье) имеется три РВВ – один служит для задания направления работы порта (на вывод или ввод информации), второй для … рассмотрим в следующей статье. И так каждое устройство.
Кусочек из таблицы регистров ввода/вывода (первое число – номер регистра, и оно же его адрес в адресном пространстве РВВ, в скобках указывается адрес регистра в адресном пространстве памяти данных, т.е. номер +32):
Назначение и работу РВВ мы будем изучать постепенно, по мере изучения работы устройств МК.
Следующую статью мы посвятим изучению одного, но самого главного, чаще всего используемого в программах – регистру состояния, под названием SREG.
Стек
Стек, или указатель стека – это специальный регистр, который предназначен для организации стековой памяти.
Можно сказать, что стек (точнее стековая память, стек состоит из двух частей: указатель стека и стековая память) – это туннель с тупиком в конце, состоящий из ячеек памяти. По мере заполнения ячеек памяти первые данные уходят в глубь стека, и добраться до них можно, только вытащив сначала последние введенные данные. Допустим, если мы запишем в стек последовательно три числа: 10,20 и 30, то для того, чтобы затем извлечь из стековой памяти число 10, предварительно придется извлечь числа 30 и 20. Т.е., значение записанное последним всегда будет прочитано первым.
Стек широко используются не только МК в своих целях, но и программистами.
К примеру, при выполнении команды перехода к подпрограмме, МК самостоятельно записывает в стек адрес следующей команды, с которой будет продолжено выполнение основной программы после возвращения из подпрограммы. Возвращаясь из подпрограммы, МК извлекает этот адрес и загружает в счетчик команд, в результате чего выполнение программы продолжается с прерванного места.
Для нас тоже очень удобно сохранять в стеке данные при входе в подпрограмму, а затем извлекать их по возвращению из подпрограммы. Также удобно в стеке сохранять промежуточные результаты вычислений, а затем, по мере необходимости, извлекать их.
В микроконтроллерах, в которых отсутствует память данных (ОЗУ), а это часть МК семейства Tiny, стек организуется аппаратно. В таких МК стек располагается в собственной памяти а глубина его равна трем уровням. Аппаратный стек не доступен программисту, его в своих целях использует только сам МК, сохраняя в нем адреса команд при переходе к подпрограммам. Так как возможности аппаратного стека мы использовать в своих целях не можем, то на этом и закончим его изучение.
Во всех остальных МК, которые имеют память данных, стек организуется программно. Стек в этом случае не имеет собственной памяти а использует память данных (ОЗУ). Такой стек доступен для наших целей и рассмотрим его подробней.
Для организации процесса записи данных в стек и их чтения предназначен указатель стека.
В качестве указателя стека используются один или два регистра ввода/вывода:
– если память данных небольшая (до 256 байт), используется один восьмиразрядный РВВ – SPL;
– если память данных большая (более 256 байт), к первому РВВ – SPL, добавляется второй – SPH, и вместе они составляют один шестнадцатиразрядный указатель стека.
В указателе стека содержится адрес ячейки памяти, в которую будут записаны или считаны данные.
Для программиста в системе команд МК есть две специальные команды:
- PUSH – команда записи в стек
– POP – команда чтения из стека
Давайте рассмотри как происходит запись в стек и чтение из него.
Запись данных в стек:
Для того, чтобы записать данные в стек, их предварительно необходимо загрузить в любой РОН.
По команде PUSH МК записывает данные из указанного нами РОН в память данных по адресу, на который указывает указатель стека, а затем уменьшает содержимое стека на 1 (если указатель восьмиразрядный) или на 2 (если указатель шестнадцатиразрядный). Новая команда PUSH запишет данные в следующую ячейку ОЗУ и опять уменьшит содержимое указателя стека. И так, далее.
Чтение данных из стека:
По команде POP, МК сначала увеличивает содержимое указателя стека на 1 или 2, а затем считывает данные с ячейки ОЗУ, на которую указывает указатель стека. И так, далее.
После сброса МК содержимое указателя стека равно нулю. Т.е. получается, что после сброса, указатель стека указывает на нулевую ячейку памяти ОЗУ.
А теперь смотрите, что получится, если мы попробуем что-то записать в стек:
– первая команда PUSH – содержимое РОН будет записано в нулевую ячейку памяти,а затем МК попытается уменьшить содержимое стека на 1 или 2 – и ни чего не получится – адрес ячейки памяти не может быть меньше нуля!
Поэтому, прежде чем пользоваться стековой памятью, необходимо записать в указатель стека значение его вершины – адрес конечной ячейки памяти с которой начнется запись в стек.
Обычно вершиной стека указывают адрес последней ячейки памяти данных. Если у вашего МК ОЗУ составляет 128 байт, то указывают адрес 128 ячейки памяти. Под стек можно использовать всю память, если только вы не будете хранить в ней свои переменные. Если в качестве вершины стека вы укажите конечную ячейку памяти, то следить за стековой памятью в большинстве случаев не обязательно. А если вершиной стека указать ячейку памяти поближе к началу, и при этом использовать ОЗУ для хранения своих данных, то следить за размерностью стека придется – он может залезть на ячейки в которых вы будете хранить свои данные.
Счетчик команд
Счетчик команд – представляет собой регистр, в котором содержится адрес следующей исполняемой команды.
Размер счетчика команд может быть от нескольких разрядов до шестнадцати (двухбайтовый). Размерность счетчика зависит об объема памяти программ. Счетчик команд не доступен для программиста, в него мы не можем ничего записать и не можем из него ничего считать. Работой счетчика команд руководит единолично МК.
При включении питания устройства или сброса микроконтроллера, счетчик команд устанавливается в ноль, т.е. указывает на нулевой адрес памяти программ. Поэтому адресу начинается наша программа (если мы не используем прерывания) или адрес, по которому начинается наша программа (если мы используем прерывания). При нормальном ходе программы содержимое счетчика команд автоматически увеличивается на 1 или 2 (в зависимости от выполняемой команды) в каждом машинном цикле. Т.е., после выполнения команды, счетчик будет указывать адрес следующей команды. Этот порядок будет нарушен, если на пути МК при выполнении программы встретится команда перехода, команда вызова подпрограммы (или возврата из подпрограммы), а также при возникновении прерывания. В этом случае содержимое счетчика – адрес следующей команды, записывается в стек, а в счетчик записывается адрес по которому надо перейти по команде перехода или по прерыванию. По команде возвращения из подпрограммы, в счетчик записывается адрес команды сохраненный в стеке, программа продолжается дальше. Все это проделывается автоматически, без нашего участия.
В продолжении этой статьи, а точнее – окончании, мы очень подробно рассмотрим порты ввода/вывода микроконтроллера.
После этого, вся теория пойдет вперемешку с практикой. Легче понимать работу микроконтроллера разрабатывая практическое устройство.
Расскажу немного о том, что будет дальше.
После портов ввода/вывода мы начнем собирать цифровой вольтметр, попутно изучая и необходимые для этого теоритические вопросы.
Вольтметр я буду собирать на основе МК ATiny26 – самый подходящий (как мне кажется) для этого микроконтроллер. Для вывода информации, в целях изучения вопроса подключения к МК различных типов устройств для отображения информации, мы будем использовать сначала светодиодные сегментные индикаторы, которые потом заменим сегментным LCD дисплеем, который потом заменим буквенно-цифровым ЖК индикатором, а его, в свою очередь, если не погибнем в процессе, графическим ЖК индикатором. Затем добавим к вольтметру амперметр, а сверху этого бутерброда положим частотомер. Что будет дальше, честно говоря, я пока не знаю.
Предыдущие статьи:
♦ Микроконтроллер и как его победить
♦ Микроконтроллер и системы счисления
♦ Микроконтроллер и логические операции
♦ Общее устройство микроконтроллера
♦ Арифметико-логическое устройство и организация памяти – память программ, память данных, энергонезависимая память
Следующие статьи:
♦ Регистр состояния SREG
♦ Порты ввода/вывода микроконтроллера