Как задавать значения битов в регистрах ввода/вывода?

Документация

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

Регистры микроконтроллера ATmega8 обычно 8-битные, это значит, что регистр можно  образно представить в виде ячейки с 8-ю столбцами. Столбцы  это и есть биты (разряды регистра), которые могут принимать одно из двух значений  - 1 или 0.

7 6 5 4 3 2 1 0
1 1 0 1 0 0 0 0

Нумерация битов ведётся справа налево, начиная с нуля. Таким образом в представленном на примере регистре: 7-ой бит=1, 6-ой=1,  5-ый=0 и т.д. Думаю, логика ясна.

Теперь обратимся к главному вопросу - как выставлять значения битов. Существует несколько  способов.

Установка битов

1) С помощью побитовых логические операции "И" и "ИЛИ" 

Оператор  логическое "ИЛИ" записывается в виде вертикальной черты - "|" и может выполнятся между двумя переменными, а так же между переменной и константой.  Применение операции "ИЛИ" между двумя битами даёт в результате единственное значение - 1 (если хотя бы один из битов, к которому  применяется оператор равен единице) или 0 (если оба бита равны нулю).

Рассмотрим всё вышенаписанное на примере. Возьмём какой-нибудь реальный регистр микроконтроллера ATmega8, например  DDRA. И пусть он имеет некое стартовое  значение  "11001010" и нам требуется выставить 5-ый бит регистра в значение  1. Это  можно сделать несколькими способами:

1) При помощи битовой маски. Битовая  маска это обычная константа с единичным  N-ым битом (в нашем примере выставляется 5-ый бит, поэтому N=5). Находится она по формуле 2^N. В нашем случае она будет  равна 2^5=32. Если запустить калькулятор и перевести 32 из десятичной формы в двоичную,  то получится число вида 00100000 (или 100000, т.к впередистоящие нули часто принято пропускать). На месте 5-го бита (нумерация справа налево, отсчёт начинается с 0) стоит 1. Это нам и надо. Теперь применем операцию логическое "ИЛИ"  между регистром DDRA  и полученной единичной маской. Операция (DDRA |  32) в двоичном виде будет выглядеть следующим образом:

11001010  -  некое  стартовое значение регистра DDRA

00100000 - битовая маска

11101010 - результат, полученный после применения операции логического "ИЛИ" между DDRA и логической маской.  Логическое "ИЛИ" последовательно выполнилось между каждым из битов регистра, стоящим друг под другом.

Осталось только присвоить полученное значение  биту DDRA и  поставленная в начале задача будет выполнена. Делается  при помощи оператора присваивания "=":  DDRA=DDRA|32;

В числе 32 трудно сразу сказать, какой бит установлен. Поэтому на практике чаще пользуются другой формой записи  битовой маски - при  помощи оператора побитового  сдвига "<<". Например  (1<<<5). Для выполнения нашей задачи (установки 5-го бита регистра DDRA в единицу) можно записать: DDRA=DDRA|(1<<5). Или с использование укороченной записи в языке С:   DDRA|=(1<<5)

Сброс битов

Теперь  рассмотрим ещё одну  операцию языка С - логическое "И". Эта операция, будучи применённой к двум битам  даст в результате 1 только тогда, когда оба бита равны единице. В противном случае  результирующим битом будет 0. Это свойство оператора логическое  "И"  удобно применять для сброса (установки в 0) определённых битов регистра. При этом используется битовая маска, в которой все разряды единичные, кроме нулевого на позиции сбрасываемого. Её легко получить из маски с установленным N-ным битом, применив к ней операцию побитного инвертирования:

~(1<<<5) в двоичном представлении - 00100000, то ~(1<<5) будет выглядеть  как  - 11011111.

Для сброса 5-го бита  в регистре DDRA необходимо выполнить следующую операцию:

DDRA = DDRA & (~ (1<<5));  или кратко: DDRA &= ~ (1<<5);

 Устанавливать или сбрасывать несколько разрядов регистра одновременно можно, объединяя битовые маски в выражениях оператором логического "ИЛИ":

DDRA |= (1<<1)|(1<<4); //  выводы 1 и 4 установить порта A в единицу;
DDRA&=~((1<<2)|(1<<3)); // Выводы 2 и 3 порта A сбросить в ноль.

 

Проверка битов регистра

Допустим необходимо проверить значение в определённом бите N регистра  Registr, и в зависимости от значения бита N, выполнить то или иное действие. Это можно сделать при помощи операции логического "И" и условного оператора If.

Рассмотрим  выражение (REGISTR & (1<<5)). В этом выражении операция "И” во всех разрядах кроме N-ного даст нулевые значения, а проверяемый разряд оставит без изменения

 Пусть нам надо проверить 5-ый  бит регистра. Если он равен 1, то (REGISTR & (1<<<5)) будет равно 00100000, что будет интерпретировано оператором if как истина. Если бит 5 равен 0, то выражение  (REGISTR & (1<<5))  будет равно 00000000, а это значение будет расценено оператором if как false

Логическая операция "Исключающее ИЛИ"

Записывается как ^.  Принцип работы такой - при применении этой операции  к двум битам, единица в результате получится, только если один из битов равен 1, а другой 0.

Таблица истинности

И ещё кое-что

Значения регистров можно задавать также в виде шестнадцатеричного числа. Для этого запускаем калькулятор, переводим его в двоичный режим (bin), записываем значение битов регистра, например 00100000 (5-ый  бит установлен в 1). Конвертируем в шестнадцатеричный формат (hex),получаем число 20, записываем как 0x20 и присваиваем это значение регистру.

DDRA=0x20;

В некоторых средах разработки (например CodeVision AVR) к биту N регистра REGISTER можно обращаться через  точку:

REGISTER.N=1


Если у вас есть какие-то замечания по этому документу или что-то осталось непонятно, то вы можете оставить свой отзыв или вопрос

Комментарии (Ваш комментарий будет первым! :))

Анонимная отправка сообщений запрещена! Пожалуйста зарегистрируйтесь