Форум программистов, компьютерный форум, киберфорум
C для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.80/50: Рейтинг темы: голосов - 50, средняя оценка - 4.80
1 / 1 / 0
Регистрация: 03.09.2015
Сообщений: 11
1

В чем суть операторов << и >>

20.11.2015, 13:08. Просмотров 9092. Ответов 10
Метки нет (Все метки)

Здравствуйте.
Уважаемые Форумчане, нужна помощь.
Имеется следующий код
C
1
2
3
4
5
if ((PINB&(1 << PB0)) == 0) // Если на выводе PB0 лог. 0
{
PORTB |= (1 << PB0); // Лог. 1 на выводе PB0
}
else
Не могу понять значение операторов << и >>.
В документации к среде написано: операторы побитового сдвига (значение первого операнда сдвигается на количество бит указанных во втором операнде).
Однако, если я правильно понял РВ0 это имя одного (первого) бита регистра. Опять же наличие числа перед оператором, для меня снова делает это выражение непонятным.

Среда разработки CodeVision AVR 3.12.
Я понимаю, что в самой среде могут использоваться иные/дополнительные операторы не оговоренные в стандарте языка, либо операторы могут иметь совсем иное значение. Однако не могу найти детальную и достоверную информацию по данным операторам (возможно я не там ищу).

P.S. Если я правильно понял:
PINB - регистр размером один байт, значение каждого бита означает состояние сигнала на входе порта (1- логическая единица, 0 - ноль)
PORTB - регистр размером один байт, значение каждого бита означает состояние сигнала на выходе порта (что будет подано, 1- логическая единица, 0 - ноль).

Заранее спасибо за помощь.
Прошу прощения, если вопрос задан не в тему или не в той ветке.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.11.2015, 13:08
Ответы с готовыми решениями:

В чем суть continue в if-else
код первый. прата глава 7 упражнение 3. оператор continue отсутствует, все прекрасно работает....

Строгое чередование: в чем суть алгоритма?
Объясните пожалуйста смысл этого алгоритма. Я не могу понять, зачем мы turn присваиваем 1-i? Он же...

В чем суть функций putchar и getchar
подскажите кто знает что деляют эти функции

Поразрядные операции - в чем суть и применение?
Добрый вечер. Объясните, в каких задачах они могут понадобиться и как ими пользоваться. А конкретно...

10
651 / 237 / 45
Регистрация: 20.11.2012
Сообщений: 527
20.11.2015, 13:46 2
Может есть какой-нибудь макрос типа:
C
1
#define PB0 7
который указывает номер бита для порта.
Когда сдвигаешь 00000001b на 7 влево (1 << PB0) получается 10000000b. И затем проверяется установлен ли бит в регистре с помощью И.
А так с программированием МК не знаком...
1
1 / 1 / 0
Регистрация: 03.09.2015
Сообщений: 11
20.11.2015, 14:58  [ТС] 3
Все гораздо интереснее и запутаннее.
Многократно прочитав текст, выделил для себя смысл происходящего...
"Проверяем состояние младшего разряда порта B(PB0) к которому подключена кнопка, а затем выполняем операцию сравнения, где PB0 проверяется на равенстве нулю"

НО при всем при этом разложить данное предложение в коде на доступные для понимания части все равно не могу.
Например:
if(PINB==0 && PB==1) как логическое выражение я понимаю
но как проверку на равенство символов << ... Что то у меня не переваривается.
Дальше & побитное И. Это по сути операция побитного сравнения двух операндов с присвоением результата первому операнду. В выражении ведь не логические И (&&).

Так что все же делает выражение по пунктам, понять не могу или я "дурак"?

Самое забавное в данной ситуации, у меня параллельно открыта книга "руководство по CVAVR" и там ничего про такое использование операторов не говориться.
И Яндекс ничего путного не предлагает...
0
651 / 237 / 45
Регистрация: 20.11.2012
Сообщений: 527
20.11.2015, 15:18 4
Лучший ответ Сообщение было отмечено Сифон как решение

Решение

PB0 это макрос. Чему он равен - вторично. Ну для удобства предположим, что равен, например 7.
Если разобрать по шагам,
C
1
if ((PINB & (1 << PB0)) == 0)
получим:
1. (1 << PB0) == (1 << 7) == 1000000b
2. tmp = (PINB & 10000000b) //тут tmp равен либо 0 либо 10000000 в зависимости от того, установлен ли бит с номером 7. При & никакой результат левому операнду не присваивается - результат присваивается временной переменной tmp, PINB остается неизменным.
3. if (tmp==0)
1
1 / 1 / 0
Регистрация: 03.09.2015
Сообщений: 11
20.11.2015, 15:45  [ТС] 5
Спасибо. в общем значение выражения вроде бы дошло.
Но вот пункт 1 все же не понял.
параллельно рассматривал .h и там тоже присутствуют операторы << и >>. с похожим значением (мне непонятным)
C
1
2
3
4
5
6
/ Input/Output Ports initialization
// Port B initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In 
DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T 
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
Кстати возник вопрос о значении "|" в вышеозначенных выражениях.
Это побитное "или" или это типа разделитель?
0
651 / 237 / 45
Регистрация: 20.11.2012
Сообщений: 527
20.11.2015, 16:06 6
Обнуление регистра побитово, судя по всему. Вот код для наглядности.
| - побитовое или.


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include "windows.h"
 
#define DDB7 7
#define DDB6 6 
#define DDB5 5
#define DDB4 4
#define DDB3 3
#define DDB2 2
#define DDB1 1
#define DDB0 0
 
int main(int argc, char ** argv)
{
    BYTE DDRB = 0xFF;
 
    std::cout << "DDRB starting value is: " <<  (int)DDRB << std::endl;
    DDRB = (0 << DDB7) | (0 << DDB6) | (0 << DDB5) | (0 << DDB4) | (0 << DDB3) | (0 << DDB2) | (0 << DDB1) | (0 << DDB0);
    std::cout << "DDRB value after: " << (int)DDRB << std::endl;
 
    system("pause");
    return 0;
}
1
Миниатюры
В чем суть операторов << и >>  
1 / 1 / 0
Регистрация: 03.09.2015
Сообщений: 11
20.11.2015, 18:42  [ТС] 7

хочу крови!!!

Пересмотрел кучу источников: похоже используется только << как вариант присвоения или помещения 0 или 1 в соответствующий разряд. Причем НИГДЕ НЕТ ОПИСАНИЯ ДАННОЙ ОПЕРАЦИИ.
И что бесит - ОНА РАБОТАЕТ.

Похоже на внутренний макрос CVAVR.
Что еще занятнее подобные операции присутствуют в файлах созданных мастером CVAVR, а в самих хидерах таких операций нет. Все делается через родной =.

ААА!!!
0
651 / 237 / 45
Регистрация: 20.11.2012
Сообщений: 527
20.11.2015, 19:11 8
Сифон, я все не пойму, что именно непонятного? Оператор битового сдвига? Побитовые операции И ИЛИ НЕ?
Это все обыкновенные операторы языка С. Нужно в документации по языку смотреть. По сути на x86, например, << эквивалентно инструкции shl ассемблера.
0
Миниатюры
В чем суть операторов << и >>  
1 / 1 / 0
Регистрация: 03.09.2015
Сообщений: 11
20.11.2015, 20:29  [ТС] 9
Спасибо.
Вы были правы.
В выдранном мной коде несколько иная идея, но в целом Вы полностью правы.
Только что нашел обстоятельное рассмотрение данного выражения.
0
1 / 1 / 0
Регистрация: 03.09.2015
Сообщений: 11
11.12.2015, 12:17  [ТС] 10
Решил выложить, может кто то так же мучился с подобным кодом.
Вот нашел пояснения, уж разжевано доступно.


§ Обзор стандартных операций с регистрами

Настало время перейти к более серьёзным операциям над регистрами и программными переменными. Управление работой микроконтроллера в большинстве случаев сводится к следующему простому набору действий с его регистрами:

1. Запись в регистр необходимого значения.
2. Чтение значения регистра.
3. Установка в единицу нужных разрядов регистра.
4. Сброс разрядов регистра в ноль.
5. Проверка разряда на логическую единицу или логический ноль.
6. Изменение логического состояния разряда регистра на противоположное.

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

A = 16; // Присвоить переменной A значение 16;
A = B; // Считать значение переменной B и присвоить это значение переменной A;
A = B+10; // Считать значение переменной B, прибавить к считанному значению 10, результат присвоить переменной A (значение переменной B при этом не изменяется).

§ Запись и чтение регистров

Из рассмотренных примеров видно, что оператор присваивания сам по себе решает две первые задачи — запись и чтение значений регистров. Например для отправки микроконтроллером AVR байта по шине UART достаточно записать его в передающий регистр с именем UDR:

UDR = 8; // Отправить по UART число 8;

Чтобы получить принятый по UART байт достаточно считать его из регистра UDR:

A = UDR; // Считать принятый байт из UART и переписать в переменную A.


§ Установка битов регистров

Язык Си не имеет в своём составе команд непосредственного сброса или установки разрядов переменной, однако присутствуют побитовые логические операции "И" и "ИЛИ", которые успешно используются для этих целей.

Оператор побитовой логической операции "ИЛИ" записывается в виде вертикальной черты - "|" и может выполнятся между двумя переменными, а так же между переменной и константой. Напомню, что операция "ИЛИ" над двумя битами даёт в результате единичный бит, если хотя бы один из исходных битов находится с состоянии единицы. Таким образом для любого бита логическое "ИЛИ" с "1" даст в результате "1", независимо от состояния этого бита, а "ИЛИ" с логическим "0" оставит в результате состояние исходного бита без изменения. Это свойство позволяет использовать операцию "ИЛИ" для установки N-ого разряда в регистре. Для этого необходимо вычислить константу с единичным N-ным битом по формуле 2^N, которая называется битовой маской и выполнить логическое "ИЛИ" между ней и регистром, например для установки бита №7 в регистре SREG:

(SREG | 128) — это выражение считывает регистр SREG и устанавливает в считанном значении седьмой бит, далее достаточно изменённое значение снова поместить в регистр SREG:

SREG = SREG | 128; // Установить бит №7 регистра SREG.

Такую работу с регистром принято называть "чтение - модификация - запись", в отличие от простого присваивания она сохраняет состояние остальных битов без именения.

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

(1<<N) - это выражение на языке Си означает, число один, сдвинутое на N разрядов влево, это и есть маска с установленным N-ным битом. Тогда предыдущий код в более читабельном виде:

SREG = SREG | (1<<7);

или ещё проще с использование краткой формы записи языка Си:

SREG |= (1<<7);

которая означает - взять содержимое справа от знака равенства, выполнить между ним и регистром слева операцию, стоящую перед знаком равенства и записать результат в регистр или переменную слева.

§ Сброс битов в регистрах

Ещё одна логическая операция языка Си – побитовое "И", записывается в виде символа "&". Как известно, операция логического "И", применительно к двум битам даёт единицу тогда и только тогда, когда оба исходных бита имеют единичное значение, это позволяет применять её для сброса разрядов в регистрах. При этом используется битовая маска, в которой все разряды единичные, кроме нулевого на позиции сбрасываемого. Её легко получить из маски с установленным N-ным битом, применив к ней операцию побитного инвертирования:

~(1<<N) в этом выражении символ "~" означает смену логического состояния всех битов маски на противоположные. Так, например, если (1<<3) в двоичном представлении – 00001000b, то ~(1<<3) уже 11110111b. Сброс седьмого бита в регистре SREG будет выглядеть так:

SREG = SREG & (~ (1<<7));

или кратко:

SREG &= ~ (1<<7);

В упомянутом ранее заголовочном файле для конкретного микроконтроллера приведены стандартные имена разрядов регистров специального назначения, например:

#define OCIE0 1

здесь #define – указание компилятору заменять в тексте программы сочетание символов "OCIE0" на число 1, то есть стандартное имя бита OCIE0, который входит в состав регистра TIMSK микроконтроллера Atmega64 на его порядковый номер в этом регистре. Благодаря этому установку бита OCIE0 в регистре TIMSK можно нагляднее записывать так:

TIMSK|=(1<<OCIE0);

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

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


§ Проверка разрядов регистра на ноль и единицу

Регистры специального назначения микроконтроллеров содержат в своём составе множество битов-признаков, так называемых "флагов”, уведомляющих программу о текущем состоянии микроконтроллера и его отдельных модулей. Проверка логического уровня флага сводится к подбору выражения, которое становится истинным или ложным в зависимости от того установлен или сброшен данный разряд в регистре. Таким выражением может служить логическое "И” между регистром и маской с установленным разрядом N на позиции проверяемого бита :

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



Приведённое выражение можно использовать в условном операторе if (выражение) или операторе цикла while (выражение), которые относятся к группе логических, то есть воспринимают в качестве аргументов значения типа истина и ложь. Поскольку язык Си, приводя числовые значения к логическим, любые числа не равные нулю воспринимает как логическую истину, значение (REGISTR & (1<<N)) равное 2^N в случае установленного бита, будет воспринято как "истина".

Если появляется необходимость при установленном бите N получить для нашего выражения логическое значение «ложь», достаточно дополнить его оператором логической инверсии в виде восклицательного знака - !(REGISTR & (1<<N)). Не следует путать его с похожим оператором побитовой инверсии (~) меняющим состояние битов разряда на противоположное. Логическая инверсия работает не с числовыми значениями, а с логическими, то есть преобразует истинное в ложное и наоборот. Такая конструкция приводится в DataSheet на Atmega как пример для ожидания установки бита UDRE в регистре UCSRA, после которого можно отправлять данные в UART:

while ( !( UCSRA & (1<<UDRE)) ) { } // Ждать установки UDRE.

Здесь при сброшенном бите UDRE выражение ( UCSRA & (1<<UDRE)) даст значение ”ложь”, инвертированное !( UCSRA & (1<<UDRE)) — ”истину”, и пока это так, программа будет выполнять действия внутри фигурных скобок, то есть не делать ничего (стоять на месте). Как только бит UDRE установится в единицу, программа перейдёт к выполнению действий следующих за конструкцией while(), например займётся отправкой данных в UART.

§ Изменение состояния бита регистра на противоположное

Эту проблему с успехом решает логическая операция побитного "ИСКЛЮЧАЮЩЕГО ИЛИ” и соответствующий ей оператор Си, записываемый в виде символа " ^ ”. Правило "исключающего или" с двумя битами даёт "истину” тогда и только тогда, когда один из битов установлен, а другой сброшен. Не трудно убедиться, что этот оператор, применённый между битовой маской и регистром, скопирует в результат биты стоящие напротив нулевых битов маски без изменения и инвертирует расположенные напротив единичных. Например, если: reg=b0001 0110 и mask=b0000 1111, то reg^mask=b0001 1001. Таким способом можно менять состояние светодиода, подключенного к пятому биту порта A:

#define LED 5 // Заменять в программе сочетание символов LED на число 5 (вывод светодиода).

PORTA ^=(1<< LED); // Погасить светодиод, если он светится и наоборот.
1
WhiteP
11.12.2015, 16:14     В чем суть операторов << и >>
  #11

Не по теме:

Имхо, все все это вполне доступно после K&R. Но кому то может так проще. Спасибо.

0
11.12.2015, 16:14
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.12.2015, 16:14
Привет! Вот еще темы с ответами:

В чем суть директив #include <Windows.h> #include <stdlib.h>
/*хочу сделать простую графическую программу ранее работал с turbo 3.0 я так понимаю &lt;graphics.h&gt;...

В чем суть PHP?
Ребят, подскажите пожалуйста правильно ли я понял суть PHP. Вот лежит на сервере код определенный....

В чем суть интерфейсов?
За день я в интернете начиталась столько всего про интерфейсы, что запуталась до нельзя!!! И...

Интерфейсы - в чем их суть
В чем суть интерфейсов объясните пожалуйста. Добавлено через 19 минут А если быть точнее, то...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.