11011111
В каких задачах управления используются эти логические операторы? В прикладных программах (т.е. программах управления) часто приходится изменять сигналы на отдельных линиях портов ввода/вывода. Регистры данных портов расположены по строго определенным в техническом описании физическим адресам. Так для того, чтобы сконфигурировать все линии порта PORT A на ввод, необходимо в регистр направления передачи порта DDRA (физический адрес 0x0002) записать все нули. Это может быть выполнено под управлением следующей строки:
*(unsigned char volatile*)(0х0002) = 0х00;
Если порт Port A настроен на вывод, то установить линию PTA7 в единицу без изменения состояния остальных линий порта можно посредством следующей записи:
PORTA |= 0х80; //установить PTA7
Выше использована сокращенная форма записи выражения:
PORTA = PORTA | 0х80; //установить PTA7
Выражение возвращает результат операции поразрядного логического ИЛИ числа 0x80 (10000000 в двоичной системе счисления) и содержимого порта PortA. После операции старший бит Port A будет установлен в 1, остальные биты останутся без изменения.
Аналогично, старший бит порта Port A может быть установлен в 0 (сброшен) посредством записи выражения:
PORTA &= ~0х80; //сбросить бит PTA7
Это выражение аналогично другому, более понятному для начального уровня освоения языка Си:
PORTA = PORTA & 0х7F; //сбросить бит PTA7
Для установки в 0 старшего разряда порта Port A содержимое порта побитно логически умножается на константу 0x7F (01111111 в двоичном коде). В результате старший бит становится равным 0, а остальные биты остаются без изменения. Запись ~0х80 в первом выражении предписывает перед выполнением операции логического И взять инверсию константы 0x80 (10000000), которая будет равна 0x7F (01111111). Вторая запись более понятна на начальном этапе программирования на Си, в то время как первая запись позволяет использовать одну и ту же константу в выражениях по установки и сбросу бита, что в практическом программировании удобно.
Операцию поразрядного логического И также следует использовать, если необходимо проверить, установлены или сброшены биты порта с определенными номерами. Например, приведенный ниже фрагмент программы производит чтение регистра данных порта Port A, логически умножает его содержимое на константу 0x81 и сравнивает полученный результат с нулем. Если условие равенства нулю выполняется, то это означает, что биты 7 и 0 порта Port A одновременно равны нулю, и следует выполнить действия, которые описаны операторами в фигурных скобках. Если хотя бы один бит PTA7 или PTA0 не равен нулю, то условие ((PORTA & 0х81) == 0) не выполняется, и операторы в фигурных скобках будут пропущены при исполнении.
if ((PORTA & 0x81) == 0) {
:
}
В качестве примера использования оператора ИСКЛЮЧАЮЩЕГО ИЛИ приведем выражение для инвертирования значения бита 7 порта Port A:
PORTA ~= 0х80; //инвертировать бит PTA7
Операторы группы унарных операций. Поскольку операторы инкремента и декремента были рассмотрены выше, основное внимание уделим операторам указателя и косвенной адресации (см. табл. 3.2). Для иллюстрации действия этих операторов рассмотрим следующий пример. Определим три целочисленных переменных с именами num, address, и new_num:
int num, address, new_num;
Также предположим, что переменная num расположена в памяти по адресу 0x2000. Запишем следующее выражение:
address = #
Результатом исполнения выражения будет присвоение переменной address значения адреса переменной num, т.е. новое значение переменной address будет равно 0x2000.
Запишем новое выражение:
new_num = *address;
Результатом выполнения этого выражения будет присвоение переменной new_num значения, которое содержится в ячейке памяти, адрес которой равен текущему значению переменной address. Поскольку содержимое address равно 0x2000, т.е. адресу переменной num, то рассматриваемое выражение в нашем случае эквивалентно выражению:
new_num = num;
Несмотря на то, что в рассмотренных примерах используется корректный синтаксис, в стандарте ANSI C переменную, в которой будут храниться адреса, используемые в качестве указателей на ячейки памяти других переменных, следует определять следующим выражением:
int *address
Отличие от предыдущего способа определения состоит в том, что теперь компилятор самостоятельно определяет формат представления данных для переменной address, чтобы в этой переменной было бы возможно разместить численное значение адреса. Если бы в предыдущем случае программист ошибся и определил тип переменной address как char, то в процессе исполнения выражения address = &num возникла бы потеря информации. В последнем случае ошибка формата исключается.
Читать дальше