При программировании микроконтроллеров постоянно приходится работать с битами. Устанавливать их, сбрасывать, проверять их наличие в том или ином регистре. В AVR ассемблере для этих целей существует целый ряд команд. Во-первых, это группа команд операций с битами – они предназначены для установки или сброса битов в различных регистрах микроконтроллера, а во-вторых, группа команд передачи управления – они предназначены для организации ветвлений программ. В языке Си естественно нет подобных команд, поэтому у начинающих программистов часто возникает вопрос, а как в Си работать с битами. Эту тему мы сейчас и будем разбирать.
В Си существуют 6 операторов для манипулирования битами. Их можно применять к любым целочисленным знаковым или беззнаковым типам переменных.
В Си существуют 6 операторов для манипулирования битами. Их можно применять к любым целочисленным знаковым или беззнаковым типам переменных.
<< - сдвиг влево
>> - сдвиг вправо
~ - поразрядная инверсия
| - поразрядное ИЛИ
& - поразрядное И
^ - поразрядное исключающее ИЛИ
_______________ сдвиг влево << _______________
Сдвигает число на n разрядов влево. Старшие n разрядов при этом исчезают, а младшие n разрядов заполняются нулями.
unsigned char tmp = 3; //0b00000011
tmp = tmp << 1;
//теперь в переменной tmp число 6 или 0b00000110
tmp = tmp << 3;
//теперь в переменной tmp число 48 или 0b00110000
Выражения, в которых над переменной производится какая-либо операция, а потом результат операции присваивается этой же переменной, можно записывать короче, используя составные операторы.
tmp = 7; //0b00000111
tmp <<= 2; //сокращенный вариант записи
//теперь в переменной tmp число 28 или 0b00011100
Операция сдвига влево на n разрядов эквивалентна умножению переменной на 2n.
_______________ сдвиг вправо >> _______________
Сдвигает число на n разрядов вправо. Младшие n разрядов при этом теряются. Заполнение старших n разрядов зависит от типа переменной и ее значения. Старшие n разрядов заполняются нулями в двух случаях – если переменная беззнакового типа или если переменная знаковая и ее текущее значение положительное. Когда переменная знаковая и ее значение отрицательное – старшие разряды заполняются единицами.
Пример для беззнаковой переменной
unsigned char tmp = 255; //0b11111111
tmp = tmp >> 1;
//теперь в переменной tmp число 127 или 0b01111111
tmp >>= 3; //сокращенный вариант записи
//теперь в переменной tmp число 15 или 0b00001111
Пример для переменной знакового типа
int tmp = 3400; //0b0000110101001000
tmp >>= 2;
//теперь в переменной число 850 или 0b0000001101010010
tmp = -1200; //0b1111101101010000
tmp >>= 2;
//теперь в tmp число -300 или 0b1111111011010100
//видите - два старших разряда заполнились единицами
Операция сдвига вправо на n разрядов эквивалентна делению на 2n. При этом есть некоторые нюансы. Если потерянные младшие разряды содержали единицы, то результат подобного “деления” получается грубоватым.
Например 9/4 = 2,5 а 9>>2 (1001>>2) равно 2
11/4 = 2,75 а 11>>2 (1011>>2) равно 2
28/4 = 7 а 28>>2 (11100>>2) равно 7
Во втором случае ошибка больше, потому что оба младших разряда единицы. В третьем случае ошибки нет, потому что потерянные разряды нулевые.
_______________поразрядная инверсия ~ _______________
Поразрядно инвертирует число. Разряды, в которых были нули – заполняются единицами. Разряды, в которых были единицы – заполняются нулями. Оператор поразрядной инверсии являтся унарным оператором, то есть используется с одним операндом.
unsigned char tmp = 94; //0b01011110
tmp = ~tmp;
//теперь в переменной tmp число 161 или 0b10100001
tmp = ~tmp;
//теперь в tmp снова число 94 или 0b01011110
_______________ поразрядное ИЛИ | ______________
Оператор | осуществляет операцию логического ИЛИ между соответствующими битами двух операндов. Результатом операции логического ИЛИ между двумя битами будет 0 только в случае, если оба бита равны 0. Во всех остальных случаях результат будет 1. Это проиллюстрировано в табице истинности.
Оператор | обычно используют для установки заданных битов переменной в единицу.
tmp = 155
tmp = tmp | 4; //устанавливаем в единицу второй бит переменной tmp
155 0b10011011
|
4 0b00000100
159 0b10011111
tmp = 155
tmp = tmp | 4; //устанавливаем в единицу второй бит переменной tmp
155 0b10011011
|
4 0b00000100
159 0b10011111
Использовать десятичные числа для установки битов довольно неудобно. Гораздо удобнее это делать с помощью операции сдвига влево <<.
tmp = tmp | (1<<4); //устанавливаем в единицу четвертый бит переменной tmp
Читаем справа налево – сдвинуть единицу на четыре разряда влево, выполнить операцию ИЛИ между полученным числом и значением переменной tmp, результат присвоить переменной tmp.
Установить несколько битов в единицу можно так
tmp = tmp | (1<<7)|(1<<5)|(1<<0);
//устанавливаем в единицу седьмой, пятый и нулевой биты переменной tmp
С помощью составного оператора присваивания |= можно сделать запись компактней.
tmp |= (1<<4);
tmp |= (1<<7)|(1<<5)|(1<<0);
_______________ побитовое И & _______________
Оператор & осуществляет операцию логического И между соответствующими битами двух операндов. Результатом операции логического И между двумя битами будет 1 только в том случае, если оба бита равны 1. Во всех других случаях результат будет 0. Это проиллюстрировано в таблице истинности.
Оператор & обычно применяют, чтобы обнулить один или несколько битов.
tmp = 155;
tmp = tmp & 247; //обнуляем третий бит переменной tmp
155 0b10011011
&
247 0b11110111
147 0b10010011
Видите, третий бит стал равен 0, а остальные биты не изменились.
Обнулять биты, используя десятичные цифры, неудобно. Но можно облегчить себе жизнь, воспользовавшись операторами << и ~
tmp = 155;
tmp = tmp & (~(1<<3)); //обнуляем третий бит
1<<3 0b00001000
~(1<<3) 0b11110111
tmp & (~(1<<3)) 0b10011011 & 0b11110111
результат 0b10010011
tmp = 155;
tmp = tmp & 247; //обнуляем третий бит переменной tmp
155 0b10011011
&
247 0b11110111
147 0b10010011
Видите, третий бит стал равен 0, а остальные биты не изменились.
Обнулять биты, используя десятичные цифры, неудобно. Но можно облегчить себе жизнь, воспользовавшись операторами << и ~
tmp = 155;
tmp = tmp & (~(1<<3)); //обнуляем третий бит
1<<3 0b00001000
~(1<<3) 0b11110111
tmp & (~(1<<3)) 0b10011011 & 0b11110111
результат 0b10010011
Читаем справа налево – сдвинуть единицу на три разряда влево, выполнить инверсию полученного числа, выполнить операцию & между значением переменной tmp и проинвертированным числом, результат присвоить переменной tmp.
Обнулить несколько битов можно так
tmp = tmp & (~((1<<3)|(1<<5)|(1<<6))); //обнуляем третий, пятый и шестой биты
Здесь сначала выполняются операции сдвига, потом операции поразрядного ИЛИ, затем инверсия, поразрядное И, присвоение результата переменной tmp.
Используя составной оператор присваивания &= ,можно записать выражение более компактно
tmp &= (~((1<<3)|(1<<5)|(1<<6)));
Как проверить установлен ли бит в переменной? Нужно обнулить все биты, кроме проверочного, а потом сравнить полученное значение с нулем
if ((tmp & (1<<2)) != 0 ){
// блок будет выполняться, только если установлен
// второй бит переменной tmp
}
if ((tmp & (1<<2)) == 0 ){
// блок будет выполняться, только если не установлен
// второй бит переменной tmp
}
_______________побитовое исключающее ИЛИ ^ _______________
Оператор ^ осуществляет операцию логического исключающего ИЛИ между соответствующими битами двух операндов. Результатом операции логического исключающего ИЛИ будет 0 в случае равенства битов. Во всех остальных случаях результат будет 1. Это проиллюстрировано в табице истинности.
tmp = 155;
tmp = tmp ^ 8; // инвертируем четвертый бит переменой tmp
155 0b10011011
^
8 0b00001000
147 0b10010011
Четвертый бит изменил свое значение на противоположное, а остальные биты остались без изменений.
tmp = tmp ^ 8; // опять инвертируем четвертый бит переменой tmp
147 0b10010011
^
8 0b00001000
155 0b10011011
Видите, четвертый бит снова изменил свое значение на противоположное.
Так записывать выражение намного удобнее
tmp = tmp ^ (1<<3); // инвертируем третий бит переменой tmp
А так и удобно и компактно
tmp ^= (1<<4); //инвертируем четверый бит
Можно инвертировать несколько битов одновременно
tmp ^= ((1<<4)|(1<<2)|(1<<1)); //инвертируем 4,2 и 1 биты
tmp = var1;
var1 = var2;
var2 = tmp;
Но используя оператор ^ переставить значения можно так:
var1 ^= var 2;
var 2 ^= var 1;
var 1 ^= var 2;
Чистая магия, хотя, честно говоря, я ни разу не пользовался таким приемом.
Пример:
#include "iom8535.h"
//порт, к которому подключены кнопки
#define PORT_BUTTON PORTA
#define PIN_BUTTON PINA
#define DDRX_BUTTON DDRA
//выводы, к которым подключены кнопки
#define DOWN 3
#define CANCEL 4
#define UP 5
#define ENTER 6
int main()
{
//конфигурируем порт на вход,
//и включаем подтягивающие резисторы
DDRX_BUTTON = 0;
PORT_BUTTON = 0xff;
…..
}
При задании символического имени можно использовать и выражения
#define MASK_BUTTONS ((1<<DOWN)|(1<<CANCEL)|(1<<UP)|(1<<ENTER))
пример использования:
tmp = PORTB & MASK_BUTTONS;
Используя #define не жалейте скобок чтобы четко задать последовательность вычисления выражений!
Некоторые выражения можно замаскировать под «функции».
#define ADC_OFF() ADCSRA = 0
пример использования:
ADC_OFF();
Можно использовать многострочные определения, используя в конце каждой строки символ \
#define INIT_Timer() TIMSK = (1<<OCIE0);\
TCCR0 = (1<<WGM01)|(0<<WGM00)|(1<<CS02);\
TCNT0 = 0;\
OCR0 = 0x7d
пример использования:
INIT_Timer();
Ну и самое мощное применение директивы #define – это задание макроопределений (или просто макросов). Вот как с помощью #define можно задать макросы для рассмотренных ранее операций с битами
#define SetBit(reg, bit) reg |= (1<<bit)
#define ClearBit(reg, bit) reg &= (~(1<<bit))
#define InvBit(reg, bit) reg ^= (1<<bit)
#define BitIsSet(reg, bit) ((reg & (1<<bit)) != 0)
#define BitIsClear(reg, bit) ((reg & (1<<bit)) == 0)
пример использования:
…
SetBit(PORTB, 0); //установить нулевой бит порта B
InvBit(tmp,6); //инвертировать шестой бит переменной tmp
…
if (BitIsClear(PIND, 0)) { //если очищен нулевой бит в регистре PIND
….. //выполнить блок
}
#define SQUARE(x) x*x
выражение
tmp = SQUARE(my_var);
даст корректный результат.
А что будет если в качестве аргумента макроопределения использовать выражение my_var+1
tmp = SQUARE(my_var +1);
Препроцессор заменит эту строчку на
tmp = my_var + 1 * my_var +1;
а это вовсе не тот результат, который мы ожидаем.
Чтобы избежать таких ошибок не скупитесь на скобки при объявлении макросов!
Оператор ^ применяется не так часто как остальные битовые операторы, но и для него находится работенка. Например, с помощью него можно инвертировать один или несколько битов переменной.
tmp = 155;
tmp = tmp ^ 8; // инвертируем четвертый бит переменой tmp
155 0b10011011
^
8 0b00001000
147 0b10010011
Четвертый бит изменил свое значение на противоположное, а остальные биты остались без изменений.
tmp = tmp ^ 8; // опять инвертируем четвертый бит переменой tmp
147 0b10010011
^
8 0b00001000
155 0b10011011
Видите, четвертый бит снова изменил свое значение на противоположное.
Так записывать выражение намного удобнее
tmp = tmp ^ (1<<3); // инвертируем третий бит переменой tmp
А так и удобно и компактно
tmp ^= (1<<4); //инвертируем четверый бит
Можно инвертировать несколько битов одновременно
tmp ^= ((1<<4)|(1<<2)|(1<<1)); //инвертируем 4,2 и 1 биты
У поразрядного исключающего ИЛИ есть еще одно интересное свойство. Его можно использовать, для того чтобы поменять значения двух переменных местами. Обычно для этого требуется третья переменная.
tmp = var1;
var1 = var2;
var2 = tmp;
Но используя оператор ^ переставить значения можно так:
var1 ^= var 2;
var 2 ^= var 1;
var 1 ^= var 2;
Чистая магия, хотя, честно говоря, я ни разу не пользовался таким приемом.
________________Директива #define__________________
Теперь мы знаем, как устанавливать, обнулять и инвертировать биты, знаем, как проверять установлен ли бит или нет. Рассмотренные выше выражения довольно громоздки, но с помощью директивы препроцессора #define, им можно придать более приятный вид.
Директива #define используется для присваивания символических имен константам и для макроопределений. Использование символических имен делают программу более модифицируемой и переносимой.
Например, вы используете в тексте программы константу, и вдруг вам понадобилось изменить ее значение. Если она встречается всего в трех местах, то исправить ее можно и в ручную, а что делать, если она встречается в пятидесяти строчках? Мало того, что исправление займет много времени, так еще и ошибиться в этом случае проще простого. Здесь то, как раз и выручает директива #define. В начале программы задается символическое имя константы, которое используется по ходу программы. Если нам нужно изменить это значение, это делается всего лишь в одном месте. А перед компиляцией препроцессор сам подставит во все выражения вместо имени константы ее значение.
Программирование микроконтроллера неразрывно связано с его аппаратной частью и чаще всего с внешней обвязкой. Взять хотя бы кнопки - опрашивая их в своей программе, мы обращаемся к реальным выводам микроконтроллера. А если нам вдруг понадобилось использовать программу опроса кнопок в другой схеме, где кнопки подключены к другим выводам? Придется исправлять программу. Опять таки, задав с помощью директивы #define символическое имя для соответствующих выводов, модифицировать программу будет проще простого
Пример:
#include "iom8535.h"
//порт, к которому подключены кнопки
#define PORT_BUTTON PORTA
#define PIN_BUTTON PINA
#define DDRX_BUTTON DDRA
//выводы, к которым подключены кнопки
#define DOWN 3
#define CANCEL 4
#define UP 5
#define ENTER 6
int main()
{
//конфигурируем порт на вход,
//и включаем подтягивающие резисторы
DDRX_BUTTON = 0;
PORT_BUTTON = 0xff;
…..
}
При задании символического имени можно использовать и выражения
#define MASK_BUTTONS ((1<<DOWN)|(1<<CANCEL)|(1<<UP)|(1<<ENTER))
пример использования:
tmp = PORTB & MASK_BUTTONS;
Используя #define не жалейте скобок чтобы четко задать последовательность вычисления выражений!
Некоторые выражения можно замаскировать под «функции».
#define ADC_OFF() ADCSRA = 0
пример использования:
ADC_OFF();
Можно использовать многострочные определения, используя в конце каждой строки символ \
#define INIT_Timer() TIMSK = (1<<OCIE0);\
TCCR0 = (1<<WGM01)|(0<<WGM00)|(1<<CS02);\
TCNT0 = 0;\
OCR0 = 0x7d
пример использования:
INIT_Timer();
Ну и самое мощное применение директивы #define – это задание макроопределений (или просто макросов). Вот как с помощью #define можно задать макросы для рассмотренных ранее операций с битами
#define SetBit(reg, bit) reg |= (1<<bit)
#define ClearBit(reg, bit) reg &= (~(1<<bit))
#define InvBit(reg, bit) reg ^= (1<<bit)
#define BitIsSet(reg, bit) ((reg & (1<<bit)) != 0)
#define BitIsClear(reg, bit) ((reg & (1<<bit)) == 0)
пример использования:
…
SetBit(PORTB, 0); //установить нулевой бит порта B
InvBit(tmp,6); //инвертировать шестой бит переменной tmp
…
if (BitIsClear(PIND, 0)) { //если очищен нулевой бит в регистре PIND
….. //выполнить блок
}
Перед компиляцией препроцессор заменит эти строчки объявленными ранее выражениями, подставив в них соответствующие аргументы.
Макросы очень мощное средство, но использовать их нужно осторожно. Вот самые распространенные грабли, о которых написано во всех учебниках по программированию.
Определим макрос, вычисляющий квадрат числа:#define SQUARE(x) x*x
выражение
tmp = SQUARE(my_var);
даст корректный результат.
А что будет если в качестве аргумента макроопределения использовать выражение my_var+1
tmp = SQUARE(my_var +1);
Препроцессор заменит эту строчку на
tmp = my_var + 1 * my_var +1;
а это вовсе не тот результат, который мы ожидаем.
Чтобы избежать таких ошибок не скупитесь на скобки при объявлении макросов!
Если объявить макрос так
#define SQUARE(x) ((x)*(x))
выражение
tmp = SQUARE(my_var +1);
даст корректный результат, потому что препроцессор заменит эту строчку на
tmp = ((my_var + 1) * (my_var +1));
записываем их в папку проекта, а в начале файла main.c прописываем #include "bits_macros.h"
Comments
tmp = tmp & (~(1 < < 3)); //обнуляем третий бит - внешние скобки лишние, это хорошо видно по следующему примеру - tmp &= (~((1
tmp = tmp & (~(1 shl 3)); //обнуляем третий бит
---------
tmp = tmp ^ 8; // инвертируем четвертый бит переменой tmp
tmp = tmp ^ (1 shl 3); // инвертируем третий бит переменой tmp
в первом случае, наверное, тоже третий бит.
но за их применения автору огромный респект!!!!!
А вообще очень рад, что наткнулся на такой великолепный сайт, где пишет такой энтузиаст своего дела. :-)
SetBitVal(reg, bit, val)
Результат понятен. А как работает?
Что означает обратный слеш?
Как понять Wile (0) в конце?
Как возможно, что точка с запятой в середине?
Code:
define BIT(x) (1<<(x))
Я имел ввиду можно ли присвоить символическое имя определенному биту в определенном регистре.
Например бит MUX0 в регистре ADMUX хочу обозвать CHANNEL такое возможно. И могу ли я его проверять при помощи конструкции If...else?
Биты можно проверять так
Code:
if (BitIsSet(ADMUX, MUX0){
...
}
пример:
Code:
PORTB_Bit0 = 1; // Установка бита 0 в PORTB
PORTB_Bit0 = 0; // Сброс бита 0 в PORTB
MCUCR &= ~(1<<ISC11)
Простите за такой мусор в коментах.
Вопрос вы поняли надеюсь.
про теги прочел только сейчас )))
MCUCR &= ~(1<<ISC11)
Устанавливает в ноль бит с номером ISC11
Code:
#define LED_GREEN PORTB,5
#define SETBIT(PORT,PIN ) do{PORT|=(1<<(PIN));}while(0)
#define UNSETBIT(PORT,PIN ) do{PORT&=(~(1<<(PIN)));}while(0)
// --------------
for(;;){
SETBIT(LED_GREEN);
_deelay_ms(1000);
UNSETBIT(LED_GREEN);
_deelay_ms(1000);
}
По идее в макрос SETBIT(PORT,PIN ) вместо PORT,PIN должно подставиться макрос LED_GREEN ко компилятор рузается, говорит нужно 2 параметра вместо одного.
В интересующем меня вопросе я разобрался сам.
Code:
// ...
#define BTN_A 3
#define BTN_B 4
#define SetBit(reg, bit) reg |= (1<<bit)
// ...
int main(void)
{
SetBit(DDRD,(BTN_A+BTN_B));
SetBit(DDRD,(BTN_A|BTN_B));
SetBit(DDRD,(BTN_A||BTN_B));
}
// ...
Но результат всегда неверный (0x80).
Проверял в AvrStudio и VMLab
Во втором случае побитное ИЛИ 0011 | 0100 == 0111, тоже дает 7.
В третьем случае - надо пробовать на месте. До сих пор я считал, что компилятор перед логической операцией производит приведение типов, т.е. BTN_A и BTN_B превращает в TRUE. А как известно TRUE == 1. Раз ты пробовал, и результат получился 0x80, то это не так. Никакого приведения произведено не было.
Еще один постулат, перед выполнением вычислительных операций все исходные типы, которые могут быть представлены в int, в том числе и булева переменная.
Если считать, что TRUE - это все, что угодно, кроме нуля, то тогда сходится.
[SetBitVal(reg, bit, val)]
вместо bit поставь 0, а вместо val - свое выражение (BTN_A | BTN_B). В макросе стоит выражение ((val)
Не (BTN_A | BTN_B) а Code:
((1 << BTN_A) | (1 << BTN_B))
Так, что проще написать свою функцию.
SetBitVal(reg, bit, val)
равно
Code:
(reg) = (reg) | ((val) << (bit))
Бит устанавливается или ничего не делается в зависимости от величины val.
Если нужно в байт вставить поле, в котором одни биты сбрасываются, а другие устанавливаются , нужно писать спещиальную функцию. Но этого никто не делает, поскольку, если идет работа с SFR, то надо контролировать каждое чтение и запись в регистр. Иначе могут быть "эффекты". Поэтому все предпочитают обходиться самыми простыми макросами.
Code:
#define SetBit2(reg, bit1, bit2) ((1 << (bit1)) | (1 << (bit2)))
Вопрос: во время выполнения Line_ON (); одновременно выполняется и Pulse_OFF();
(выставляется линия в «1», строб в «0» ) Line и Pulse биты одного порта. Если Line и Pulse биты разных портов, к примеру, PORTE и PORTF все работает правильно. Выставляется линия затем пауза далее строб и по циклу, пока не «выплюнет» слово 0Х80 в порт. Каким образом «обмануть» компилятор KEIL. Камушек 1986ВЕ92У?
Code:
while (1)
{
uint8_t i=0X80; //0b10010000
Opros_OFF (1); //включение опросной линии
while (i != 0x00)
{
if ((MDR_TIMER3->CNT & i) == i ) {Line_ON ();} else {Line_OFF ();}
i = i >> 1 ;
__ nop ();
Pulse_OFF(); //строб импульс
Pulse_ON(); //строб импульс
}
i=0X80;
Opros_ON (1);
}
После этой статьи меня как осенило)
Из-за этих макросов я ночи не спал, книжки читал...
Что ж ты сразу мне сылку на этот курс не дал?
Я одну электронную книгу по Си уже закинул себе в бошку)))
Спасибо Паша! Ты как всегда, молодца!
У меня просто слов нет.
tmp|= (1
tmp=-1200;
tmp>>=2;
Должно стоять значение -300, вместо -600.
вот проверяю наложение одного массива на другой(solid[15 ] CurrentFig[3])
Code:
for(i=0; i<4; i++){
if(solid[i+1+CurrentFigY] & CurrentFig > 0)
j++;
}
смысл в том, что если в лог умножении появляется хотя бы одна единица j растёт.
но условие не срабатывает.
Code:
((val & 1) != 0) ? reg |= (1<<bit) : reg &= (~(1<<bit))
Можно также воспользоваться исключающим или. Тогда можно будет отслеживать был ли бит изменен. Лучше использовать просто if.
Code:
(val<<bit != (reg & (1<<bit))) ? reg ^= (1<<bit) : 0
Code:
#define SOUND(x) \
if (S[x].key) { \
temp_dac += Sample[*((char*)&S[x].f+1) & 0x3F]; \
*((char*)&S[x].f+1) += *((char*)&S[x].F+1); \
*((char*)&S[x].f+0) += *((char*)&S[x].F+0); \
if (CARRY) *((char*)&S[x].f+1) += 1; \
}
У меня STM8L101. Как из ИАР Си прочитать состояние флага CARRY? Можно с ассемблерной вставкой.
REGISTR |= ABC | DEF;[code/] - здесь мы используем побитовое ИЛИ, т.е. 1 и 1 даёт 1, 1 и 0 даёт 1, 0 и 0 даёт 0. Чтобы выставить данные биты в единицу. Теперь вопрос - откуда в этих битах берётся 1, если они изначально равны 0 в начале программы?
CVAVR 2.05. Смотрю на подгружаемый файл mega8535_bits.h:
Code:
/* PORTA - Port A Data Register */ #define PORTA0 0 // Port A Data Register bit 0 #define PORTA1 1 // Port A Data Register bit 1 #define PORTA2 2 // Port A Data Register bit 2 #define PORTA3 3 // Port A Data Register bit 3 #define PORTA4 4 // Port A Data Register bit 4 #define PORTA5 5 // Port A Data Register bit 5 #define PORTA6 6 // Port A Data Register bit 6 #define PORTA7 7 // Port A Data Register bit 7
Когда мы будем работать просто запишем PORTA0, но ведь в коде выше не пишется что в PORTA0 это сокращённая запись именно для PORTA или в CVAVR где-то ещё определяется или это фишка самой программы??
" Как проверить установлен ли бит в переменной? Нужно обнулить все биты, кроме проверочного, а потом сравнить полученное значение с нулем
Code:
if ((tmp & (1<<2)) != 0 ){
"// блок будет выполняться, только если установлен
// второй бит переменной tmp
}
if ((tmp & (1<<2)) == 0 ){
// блок будет выполняться, только если не установлен
// второй бит переменной tmp
}
не получится ж таким образом проверить переменную на наличие установленного бита:
Code:
1<<2
получится 0000 0100операция и с tmp(допустим он равен 1111 0010)
получится 0000 0000 и это выражение равно 0, а значит выражение под if-ом не будет выполнятся, хотя бит №2 установлен. Подскажите, может я не прав)
Например (...tmp
Например (...1 "сдвиг влево" 3) сдвигает первый бит на 3 бита влево, а значит устанавливает !!! 4-ый бит, а не 3-ий. А у Вас везде ошибки, то правильно напишете, то неправильно. Прошу пересмотреть.
RSS feed for comments to this post