Продолжаем наше краткое, обзорное, знакомство с системой команд процессоров микроконтроллеров. В предыдущей статье "Микроконтроллеры для начинающих. Часть 20. Команды логических операций" я рассказал о командах логических операций. В общем и целом, логических операций достаточно для работы с отдельными битами ячеек памяти.
Однако, это не очень удобно, так как приходится работать с битовыми масками. Кроме того, теоретически (именно теоретически!), битовые операции позволяют избежать последовательности чтение-модификация-запись для ячейки памяти в целом. А это может быть важно, если учесть, что ячейка памяти может быть аппаратным регистром управляющим каким-либо устройством. Этого вопроса мы будем еще не раз касаться при знакомстве с различными узлами и модулями микроконтроллеров. К сожалению, во многих (в большинстве) микроконтроллеров битовые команды все таки неявно воздействуют на ячейку памяти целиком.
Еще одним примером необходимости использования именно битовых команд может являться регистр состояния процессора. Дело в том, что этот регистр может и не иметь адреса, а вот устанавливать/сбрасывать флаги состояний все таки нужно.
Поскольку манипуляции с битами в меньшей степени знакомы новичкам и вызывают больше сложностей в понимании, да и ошибок бывает больше, я рассмотрю их подробнее, чем команды, которые мы рассматривали раньше.
Адрес бита
Бит является частью ячейки памяти. В нашем случае 8-битных микроконтроллеров, частью байта. При этом минимальной адресуемой порцией данных является байт, за редким исключением. Поэтому адресом бита является комбинация адреса байта, в котором этот бит и находится, и номера собственно бита в байте. Это очень похоже на адресацию база+смещение.
Это пример адресации бита в STM8 (команда установки бита), в других микроконтроллерах формат отличается, но принцип такой же. Биты обычно нумеруются начиная с младшего, от 0 до 7. Но бывают и исключения, особенно если говорить о процессорах в целом, включая специализированные.
При этом у нас возникает проблема, для рассматриваемых нами микроконтроллеров. Дело в том, что команды одноадресные. Поэтому номер бита задается в виде непосредственного операнда, в коде команды. Это может оказаться неудобным если номер бита должен изменяться. В таком случае приходится все таки пользоваться командами логических операций.
Неявная адресация бита
Команды установки/сброса флагов состояния процессора подразумевают, что выполняется модификация регистра состояния процессора, и никакого иного. А значит, указывать адрес ячейки памяти нет необходимости. А номер бита в таких командах, точнее, его мнемоническое обозначение, задается собственно мнемоникой команды.
Например, команда CLC в микроконтроллерах AVR сбрасывает флаг переноса (бит 0) регистра SREG.
Прямой адрес бита
Я не рассматриваю в данном цикле статей микроконтроллеры архитектуры MCS-51. Однако, интересно продемонстрировать еще один, редко встречающийся, способ адресации бит. Я уже говорил в статьях и комментариях о нем, но немного напомню.
Дело в том, что в MCS-51 есть диапазон адресов байт от 20h до 2Fh, где каждый бит имеет и свой собственный адрес в диапазоне 00h - 7Fh.
И этот адрес бита указывается в качестве операнда команды.
Многообразие и сложности
Я немного забегу вперед и при этом одновременно загляну в уже пройденное. Поговорим о том, что может вызвать затруднения у новичков. Здесь придется учитывать специфику микроконтроллеров, в большинстве случаев.
Рассмотрим задачу - установить бит номер 3 в ячейке памяти с адресом 70h. Это можно сделать несколькими способами. Рассмотрим на примере STM8
Наглядно видно преимущество битовой команды. Однако, давайте разберемся, почему потребовалось три логических команды. Во первых, команда OR применима только к аккумулятору и ячейке памяти. Значит, мы просто не можем указать маску бита непосредственно в коде команды. Что бы не использовать лишнюю ячейку памяти мы и загружаем маску в аккумулятор. А в качестве ячейки памяти для второго операнда указываем нужный нами адрес 70h. Во вторых, результат команды OR помещается в аккумулятор. Поэтому последней командой мы переносим его в нужную нам ячейку памяти.
В случае AVR все немного сложнее. Во первых, у нас нет команды подобной bset в STM8. Есть команда sbi, которая работает только с регистрами ввода-вывода("Микроконтроллеры для начинающих. Часть 12. Память и процессор в AVR"). Нам не повезло, адрес 70h не входит в эту область. Поэтому картинка будет не такая красивая
Здесь используется две битовые операции - set (устанавливает флаг Т) и bld (копирует флаг T в заданный бит заданного регистра). Логическую операцию ИЛИ использовать даже проще, только нужно учитывать, что команда ori работает с регистрами r16-r31. Вместо ori можно использовать команду sbr.
Однако, сбрасывать со счетов команду sbi не стоит. Если нужно установить бит в байте в диапазоне адресов 20h-51h (диапазон 00h-31h пространства ввода-вывода), это часть диапазона регистров ввода-вывода, то использование sbi позволит обойтись только одной командой.
Для PIC ситуация во многом похожа на STM8, так как есть команда bsf, но при этом может оказаться и сложнее. Дело в том, что для BaseLine микроконтроллеров адрес ячейки памяти лежит в диапазоне 0h-1Fh, а нам требуется 70h. Такого адреса просто не существует, например, в PIC12F510. А, например, в PIC12F506 он располагается в третьем банке памяти данных. А значит, нужно переключить банк установив соответствующие биты в регистре FSR. В более продвинутых PIC адрес 70h можно задать прямо в команде, что не исключает необходимости учитывать банковую организацию памяти. В иллюстрации я не буду учитывать этот момент.
Здесь я привел два варианта использования логической операции ИЛИ. Первый, полностью аналогичный предыдущим примерам. Второй, использующий возможность указать, куда помещать результат операции.
Флаги в регистре состояния процессора
Ранее рассмотренные примеры касались бит в ячейках памяти данных (и области ввода-вывода для AVR). А что можно сказать о флагах состояний?
Для PIC особых вариантов нет, используются обычные команды bsf и bcf. Для PIC18 доступна еще команда btg. Регистр STATUS, как вы уже знаете, имеет адрес 0x03, с которым и нужно работать.
Аналогичная ситуация и с STM8. Здесь регистр CC имеет адрес 0x0A. А для работы с флагами состояний используются обычные битовые команды bset, bres и bcpl.
С AVR ситуация более интересная. Здесь есть команды установки/сброса флагов состояния. Но при этом регистр SREG имеет адрес 3Fh в пространстве ввода-вывода (5Fh в пространстве данных). На первый взгляд, появляется возможность использовать команды sbi/cbi. Однако, это не возможно, так как максимальный адрес для sbi равен 31h. Таким образом, работа с флагами состояний возможна только специальными командами или обобщенными bset/bclr.
Краткий обзор команд работы с битами
Вот теперь, когда мы столько всего узнали, мы можем посмотреть, какие команды есть в различных микроконтроллерах
Установка бита
Как следует из названия операции, эта команда просто устанавливает бит, присваивает ему значение 1, вне зависимости от того, что с ним было ранее.
BSF - установка бита в ячейке с заданным адресом, включая регистр состояния процессора, в микроконтроллерах PIC.
BSET - аналогично, но для STM8.
SBI - установка бита в регистре ввода-вывода (не полное адресное пространство ввода-вывода) для AVR.
BSET - установка указанного бита в регистре SREG для AVR. Да, мнемоника похожа на команду для STM8, но применение команды в AVR специализированное.
SEC, SEN, SEZ, SEI, SES, SEV, SET, SEH - установка соответствующих флагов состояния для AVR. С каким именно флагом работает команда указывается последним символом в ее мнемонике. Так мы уже встречались с командой SET, которая устанавливает флаг Т. Команда SEI устанавливает флаг разрешения прерываний, то есть, разрешает собственно обработку прерываний.
SBR - специфичная для AVR команда групповой установки бит. Устанавливает указанные маской биты в регистрах r16-r31. Аналогична команде ORI.
Сброс бита
Как следует из названия операции, эта команда просто сбрасывает бит, присваивает ему значение 0, вне зависимости от того, что с ним было ранее.
BCF - сброс бита в ячейке с заданным адресом, включая регистр состояния процессора, в микроконтроллерах PIC.
BRES - аналогично, но для STM8.
CBI - сброс бита в регистре ввода-вывода (не полное адресное пространство ввода-вывода) для AVR.
BCLR - сброс указанного бита в регистре SREG для AVR.
CLC, CLN, CLZ, CLI, CLS, CLV, CLT, CLH - сброс соответствующих флагов состояния для AVR. С каким именно флагом работает команда указывается последним символом в ее мнемонике. Так команда CLT сбрасывает флаг Т.
CBR - специфичная для AVR команда группового сброса бит. Сбрасывает указанные маской биты в регистрах r16-r31. При этом, сбрасываются биты, которые установлены в маске. То есть, команда инвертирует маску, а потом выполняет ANDI.
Инверсия бита
Это более редкая команда. Из рассматриваемых в цикле статей микроконтроллеров эта операция доступна только в PIC18 и STM.
BTG - переключает заданный бит (меняет его значение на противоположное) в заданной ячейке памяти PIC18.
BCPL - аналогично, но для STM8.
Копирование (пересылка) бита
Тоже довольно редкая команда, хотя необходимость копирования битовой переменной иногда оказывается очень полезной.
BCCM - копирует флаг переноса в заданный бит заданной ячейки памяти STM8. Почему именно флаг переноса удостоился специальной команды? Дело в том, что этот флаг используется наиболее часто, причем не только как результат арифметических операций. Поэтому, особенно для программ на языках высокого уровня, не редко требуется сохранять его для последующего анализа.
BST - копирует заданный бит заданного регистра (r0-r31) в флаг Т SREG AVR. Я уже упоминал этот флаг, не только в данной статье, но и в "Микроконтроллеры для начинающих. Часть 14. Начинаем знакомство в системой команд. Флаги и статусы".
BLD - обратна команде BST, то есть, копирует флаг Т в заданный бит заданного регистра AVR.
Заключение
На этом мы заканчиваем знакомство с битовыми командами. Как я уже говорил ранее, эти команды не являются такими уж необходимыми, во многих случаях, так как заменяются обычными логическими командами. Это я проиллюстрировал на примерах, где задача решается двумя способами.
Выбор способа выполнения задуманного действия может быть не столь простой задачей. А при переносе программы на другой микроконтроллер может потребоваться довольно серьезное ее изменение. Разумеется, ситуация сильно упрощается, если используется язык высокого уровня.
В следующей статье мы познакомимся с командами сдвигов и вращений. Их тоже будем рассматривать достаточно подробно.
До новых встреч!