Работа с битами.

select2
Offline
Зарегистрирован: 31.10.2012

Коллеги!

Есть переменная типа uint16_t. Необходимо с битами этой переменной проводить операции: установить в 0, установить в 1, инвертировать.
В качестве параметра получаю номер бита и собственно переменную.
Установить в 1 - я понимаю. Сделать битовую маску возведением 2 в степень i и выполнить битовое ИЛИ.
Вопросы:
1. можно ли инвертировать битовую маску? Например из 00010000 получить 11101111.
2. Как красиво инвертировать i-й бит?

Не гуру в С.
Подскажите пожалуйста.

ich
Offline
Зарегистрирован: 10.06.2012

bitRead()
bitWrite()
bitSet()
bitClear()

Ну и так чуть чуть на примере:

int i = 5; // бинерно: 101
i |= (1<<2); // Or -> 111 или i |= _BV(2);
i &= ~(1<<1); // And -> 110 или i &= ~_BV(1);

select2
Offline
Зарегистрирован: 31.10.2012

Спасибо огромное! То что нужно!
А вот от последних двух строчек аж волосы на спине дыбом встали! Где бы почитать про синтаксис?

p.s. Еще раз спасибо!

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

Читать теорию по с. Любой учебник, битовые операции.
| - или (OR)
& - и (AND)
~ - инверсия (NOT)
^ - исключающее или (XOR)
<< - сдвиг влево
>> - сдвиг вправо

Borland
Offline
Зарегистрирован: 17.05.2012

тоглить к-тый бит
i^=1<<k;

Andry Smart
Offline
Зарегистрирован: 06.09.2016

подскажите  пожалуйста. не могу сообразить как реализовать.

есть переменная типа int принимает значения от 1 до 252 (цвет оттенка (всего 252 оттенков)

далее 255/3 получаем 84. весь смысл в том, что три основных цвета будут задаваться уровнем от 1 до 84

в итоге мне нужно из одной переменной типа int (от 1 до 252)

получить три переменные (от 1 до 64)

 

я понимаю, что это можно сделать с помощью операций с битами но что то не соображу как.

ptr
Offline
Зарегистрирован: 28.05.2016

Andry Smart пишет:

я понимаю, что это можно сделать с помощью операций с битами но что то не соображу как.

84 не является степенью двойки. Так что битами не получится. Далее, если бы на каждый цвет было бы по 84 градации яркости, то и цветов было бы 84^3=592704

А раз у вас всего оттенков 252, то больше чем по 2-3 бита на цвет не получается. Например:


    8×8×4 (R3G3B2)

    В этой палитре используется 3-битный красный цвет, 3-битный зелёный и 2-битный синий.

Бит     07 06 05 04 03 02 01 00
Данные   R  R  R  G  G  G  B  B  (где R-красная, G-зелёная, B-синяя составляющие)

А вот их можно обрабатывать структурой

typedef struct colors_st {
unsigned char red:3;
unsigned char green:3;
unsigned char blue:2;
} colors_t;

 

Andry Smart
Offline
Зарегистрирован: 06.09.2016

я что то совсем ничего не понял (((. что такое структуры не могу осилить.

вы бы не могли пример кода сделать. точнее например функцию. я ей отдаю значение от 1 до 255 а на выходе получаю три значения для трех цветов. от 1 до 255/3 (примерно 84) я потом просто умножку его на три перед записью в порт?

ptr
Offline
Зарегистрирован: 28.05.2016

Andry Smart пишет:

 я ей отдаю значение от 1 до 255 а на выходе получаю три значения для трех цветов. от 1 до 255/3 (примерно 84) я потом просто умножку его на три перед записью в порт?

Это невозможно, так неправильно считаете! Тогда уже не делить на три надо, а кубический корень извлекать!

Я же привел выше пример восьмибитного RGB-332. А какая у Вас цветовая модель (RGB, CMY, YUV, YCbCr, RYB и т.п.) и как она кодируется я вообще без понятия.

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Глупец! Не делить, а извлекать корень!!!!! Млин!

84 оттенка синего * 84 оттенка красного * 84 оттенка зеленого = 592704 различных цвета, ити его мать!!!

в байт укладывается, иля, по 6 оттенков, 6*6*6 = 216. И еще несколько цветов бонусом.

------------------

ЗЫ:опять школьники-дебилы набежали, спасу от них нет.

ЗЗЫ: ptr, Это, конечно, не Вам!

Andry Smart
Offline
Зарегистрирован: 06.09.2016

Цветовая модель RGB.

 

 

ptr
Offline
Зарегистрирован: 28.05.2016

Andry Smart пишет:

Цветовая модель RGB.

Для RGB-332 я Вам структуру дал выше. Через нее и можно работать с отдельными цветами. В зависимости от того, как удобней, или через union, или через указатель.

Но у меня есть большие сомнения, что у Вас она. Число 252 наводит на мысль, что у Вас вариация на тему палитры Netscape. 6x7x6=252. В этом случае через биты не поработаете. К тому же в Netscape эта таблица начиналась с 4, а не с нуля. То есть, допустимыми оттенками были от 4 до 255, а не от 0 до 251

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

если, как полагает ptr, палитра RGB 6x7x6, то

byte rgb, rg, r,g,b;

div_t qr;

qr = div(rgb, 6);

rg = qr.quot;

b = qr.rem;

qr = div(rg,7);

r = qr.quot;

g = qr.rem;

//--------------------- и наоборот

rgb=r*g*b;

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Andry Smart, а откуда родом эта переменная ваша? Какая функция/библа её генерит? Может удобнее будет исходный код подправить, что-б давал по стандарту -3 байта.

Andry Smart
Offline
Зарегистрирован: 06.09.2016

значит я так и сделал. храню три переменные и изменяю их. хотя для моих задач такое количество оттенков избыточно.

а вот http://www.getchip.net/posts/118-adjusty_led-podstraivaemyjj-rgb-svetodiod/ например реализовано то, что мне хотелось. на вход АЦП подаем напряжение и меняется цвет. в первой табличке наглядно описано то, что я хотел. правда тут диапазон от 32 до 224.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Andry Smart, вообще интресная тема. По картинке палитры RGB из ссылки выше я попытался примитивными средствами создать алгоритм.

void setup() {
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
}

void loop() {
static byte R,G,B;
byte n=analogRead(A0)>>2;
if (n>=0 && n<63){ R=n*4;  G=0;    B=0; }
if (n>64 && n<127){ R= ~((n-64)*4);    G=n*4;     B=0;}
if (n>128 && n<191){ R=0;    G= ~((n-128)*4);     B=(n-128)*4;}
if (n>192 && n<=255){ R=(n-192)*4;   G=(n-192)*4;    B=255; }
analogWrite(9,R);
analogWrite(10,G);
analogWrite(11,B);
}

Работает. Но есть подозрение что можно сделать всё проще и оптимальнее, но не хватает мозгов что-б найти формулу и уйти от IF 'фов..

Andry Smart
Offline
Зарегистрирован: 06.09.2016

по моему мне именно это и нужно. огромное спасибо.

 

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

dimax пишет:

Andry Smart, вообще интресная тема. По картинке палитры RGB из ссылки выше я попытался примитивными средствами создать алгоритм.

Работает. Но есть подозрение что можно сделать всё проще и оптимальнее, но не хватает мозгов что-б найти формулу и уйти от IF 'фов..

Я немного избыточно расписал как (скопируйте код куда-нибудь, чтобы вошёл по длине):

unsigned char n6 = ( n & 0x40 ) ? 1 : 0;
unsigned char n7 = ( n & 0x80 ) ? 1 : 0;

    /*  0 <= n < 64          64 <= n < 128            128 <= n < 192           192 <= n < 256  */
R = 4 * ( n * !n6 * !n7 - ( n - 127 ) * n6 * !n7           + 0 * !n6 * n7 + ( n - 192 ) * n6 * n7 );

G = 4 * ( 0 * !n6 * !n7  + ( n - 64 ) * n6 * !n7 - ( n - 191 ) * !n6 * n7 + ( n - 192 ) * n6 * n7 );

B =                                            4 * ( n - 128 ) * !n6 * n7         + 255 * n6 * n7; 

 

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Это симуляция вывода по моей программе:

void loop()
{
    //byte n = analogRead( A0 ) >> 2;
    
    for ( unsigned short n = 0; n < 256; n++ )
    {
        unsigned char n6 = ( n & 0x40 ) ? 1 : 0;
        unsigned char n7 = ( n & 0x80 ) ? 1 : 0;;    
        
          0 <= n < 64        64 <= n < 128             128 <= n < 192           192 <= n < 256  */
        R = 4 * ( n * !n6 * !n7 - ( n - 127 ) * n6 * !n7           + 0 * !n6 * n7 + ( n - 192 ) * n6 * n7 );
        
        G = 4 * ( 0 * !n6 * !n7  + ( n - 64 ) * n6 * !n7 - ( n - 191 ) * !n6 * n7 + ( n - 192 ) * n6 * n7 );
        
        B =                                            4 * ( n - 128 ) * !n6 * n7         + 255 * n6 * n7;    

        analogWrite( 9, R );
        analogWrite( 10, G );
        analogWrite( 11, B );     
        
        delay( 5 );
    }    
}

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Промоделировано в Proteus 7.7 SP2.

Andry Smart
Offline
Зарегистрирован: 06.09.2016
блин замучился я уже. вот выкладываю весь код. помогите довести до ума.

это светильник RGB с датчиком движения.

к пинам 9,10,11 подключена лента RGB
к пинам 2,3,4 клавиши (подтянуты к питанию а при нажатии к минусу)
к пину 5 подключен сенсорный датчик (им управляется срабатывание датчика движения)
к пину 6 подключен датчик движения
к пину 7 подключен светодиод, который подсвечивает сам датчик движения (нужен для индикации включения датчика движения)

клавиша на пин 2 переключает режимы свечения по кольцу 1 переливание цветов, 2 имитация горения свечи, 3 режим обычного света
при срабатывании датчика движения включается режим 4 яркий свет.
клавиши на пинах 3 и 4 изменяются настройки
в режиме 1 изменяется яркость. в режиме 2 в небольших пределах яркость свечи (одной клавишей увеличивается другой уменьшается)
а вот в режиме 3 нихрена не получается.
(задача, что бы одной клавишей изменялся оттенок а другой яркость)
уже крышу сносит на фиг, я понимаю, что код у меня ужасен. может кто поможет? 
//------------------- всякие дефайны ----------------------------------------
#define  Rled 9                          // Красный 
#define  Gled 10                         // Зеленый
#define  Bled 11                         // Синий
#define  KeySET 2                        // Клавиша "настройка"
#define  KeyPLUS 3                       // Клавиша "+"
#define  KeyMINUS 4                      // Клавиша "-"
#define  Sensor 5                        // Датчик сенсорный
#define  PIR 6                           // датчик движения
#define  Glaz 7                          // Подсветка датчика движения 
    unsigned long currentMillis = 0;     //
    unsigned long prevMillis = 0;        //
    unsigned long currentMillisPIR = 0;            //
    unsigned long prevMillisPIR = 0;            //
    unsigned long zaderzhkaF = 60000;      // задержка режима яркого света во включенном состоянии (60 секунд)
    int SENstate=0;
    int SENflage=0;
    int PIRstate=0;
    int key1state=1;                     //
    int key1flag=0;
    int key2state=1;                     //
    int key3state=1;                     //
    int PIRon=0;                         // состояние выключателя датчика движения (когда он включен то по сигналу с датчика изменяется режим на яркий свет)
    int mode=1;                          // текущий режим: 1 перелив 2 свеча 3 свет 4 вспышка
    int prevmode=1;                      // предидущий режим (запоминаем сюда, что бы вернуться к нему)
    int Rc=0;                            // текущая яркость красного
    int Gc=0;                            // текущая яркость зеленого
    int Bc=0;                            // текущая яркость синего
    int Rtar=0;                          // целевой уровень красного
    int Gtar=0;                          // целевой уровень зеленого
    int Btar=0;                          // целевой уровень синего
    //----------- настройки для режима свеча --------------------------------------------------------------------
    int DELAYcandle = 45;                // величина задержки в реиме свеча
    int Mincandle = 16;                  // минимальный уровень пламени
    int Maxcandle = 72;                  // максимальный уровень пламени
    int BRcandleM=25;                    // основная яркость свечи (к этой яркости стремится пламя, если нет внешнего воздействия)
    int Ccounter = 15;                   // счетчик
    int delta=17;                         // изменяет оттенок свечи (больше меньше зеленого)
    int interval=10;
    int candlemode=1;                     // подрежим свечи 1 набор основного уровня яркости, 2 набор заданной внешним воздействием яркости,
                                          // , 3 задать случайный уровень яркости
    int NEWcandle=20;                    // новое случайное значения внешнего воздействия
    //------------------------ настройки для режима переливания цвета ----------------------------------------------
     int DELpereliv = 20;                  // величина задержки в режиме перелив
    int BRpereliv=255;                     // максимальная яркость режима "радуга"
    int nextcolor=1;                       // 1 с голубого до синего, 2 от синего до фиолетового, 3 от фиолетового до красного, 
                                           // 4 от красного до желтого, 5 от желтого до зеленого, 6 от зеленого до голубого
    //------------------- настройка режима свет----------------------------------------------------------------------
    int BRlithMAX=20;                      // яркость для режима "свет" 
    int BRlithR=200;                       // для режима "свет" значение красного
    int BRlithG=200;                       // для режима "свет" значение зеленого
    int BRlithB=200;                       // для режима "свет" значение синего
    int DELAYsvet = 10;                  // величина задержки в режиме свет
    //------------- настройка режима яркий свет----------------------------------------------------------------------
    int BRflash=255;                     // максимальная яркость режима "вспышка"
    int DELAYflash1 = 15;                 // задержка для режима яркий свет
    int DELAYflash=1500;
   //-------------------------- нажата клавиша 1 ------------------------------------                           
void ONkey1 ()
{
  if (key1state==LOW&&key1flag==0)
  {
  mode++;                                     
  key1flag=1;
  if (mode==4) mode=1;
  if (mode==1) initmode1 ();
  if (mode==2) initmode2 ();
  if (mode==3) initmode3 ();
  } 
  if (key1state==HIGH&&key1flag==1)  {key1flag=0;}
}
 //--------------------------- нажата клавиша 2 ------------------------------------
void ONkey2 ()                                 
{
  if (mode==1&&BRpereliv<254)  {BRpereliv++; initmode1 (); }
  if (mode==4&&BRflash<254)  {BRflash++; initmode4 (); }
}
//---------------------------- нажата клавиша 3 -------------------------------------    
void ONkey3 ()                                  
{
  if (mode==1&&BRpereliv>5)  {BRpereliv--; initmode1 ();}
  if (mode==4&&BRflash>3) {BRflash--;initmode4 ();}
  if (mode==3&&BRlithMAX<254&&key3state==0)  {BRlithMAX++; initcolor (); }
   if (mode==3&&BRlithMAX>254&&key3state==0) {BRlithMAX==1; initcolor (); }
}
//------------------------------------------ нажат сенсор ---------------------------
void ONsensor ()
{
    if (SENstate==1&&SENflage==0)
 {
    SENflage=1;
    if (PIRon==LOW) 
      {
    PIRon=HIGH;
      }
    else 
      {
    PIRon=LOW;
    returnmode ();
      }
    digitalWrite (Glaz,PIRon);
 }
    if (SENstate==0&& SENflage==1) SENflage=0;
}
// ---------------------------------------- сработал датчик движения ---------------------
void ONpir ()                                      
{
    if (PIRon==1)
    {
    prevMillisPIR = millis (); 
    if (mode!=4)  {prevmode=mode;  mode=4;  initmode4 ();}
    }
}
//---------------------------------------- проверка нажатия клавиш, срабатывания сенсоров --
void scankey ()
{
       SENstate = digitalRead(Sensor);    // узнаём состояние сенсора
       PIRstate= digitalRead (PIR);       // копируем состоние датчика движения
       key1state=digitalRead(KeySET);     // читаем состояние клавиши 1
       key2state=digitalRead(KeyPLUS);    // читаем состояние клавиши 2
       key3state=digitalRead(KeyMINUS);  // читаем  состояние клавиши 3
  if (SENstate==HIGH) ONsensor (); 
  if (SENstate==0&& SENflage==1) SENflage=0;
  if (PIRstate==HIGH) ONpir ();
  if (key1state==0) ONkey1 ();
  if (key1state==HIGH&&key1flag==1) key1flag=0;
  if (key2state==0) ONkey2 ();
  if (key3state==0) ONkey3 ();
 }
 //---------------------------------------- подсчет для следующих преобразований в зависимости от режима
void calculator ()       
{
                         // обработка красного
 if (mode==1)             // если включен 1 режим переливание цвета
{                     
  if (Rc<Rtar) Rc++;
  if (Rc>Rtar) Rc--;
  if (Rc==Rtar&&nextcolor==2)  {nextcolor=3;  Btar=0; }
  if (Rc==Rtar&&nextcolor==5)  {nextcolor=6;  Btar=BRpereliv; }
                         // обработка зеленого
  if (Gc<Gtar) Gc++;
  if (Gc>Gtar) Gc--;
  if (Gc==Gtar&&nextcolor==1)  {nextcolor=2;  Rtar=BRpereliv; }
  if (Gc==Gtar&&nextcolor==4)  {nextcolor=5;  Rtar=0;   }
                         // обработка синего
  if (Bc<Btar) Bc++;
  if (Bc>Btar) Bc--;
  if (Bc==Btar&&nextcolor==3)  {nextcolor=4;  Gtar=BRpereliv; }
  if (Bc==Gtar&&nextcolor==6)  {nextcolor=1;  Gtar=0;  }
}
                        // если включен второй режим свеча
 if (mode==2)
{
  scankey ();
  if (Rc<Rtar) Rc++;
  if (Rc>Rtar) Rc--;
  if (Gc<Gtar) Gc++;
  if (Gc>Gtar) Gc--;
  
  if (candlemode==1)
  {
  if (Gc==Gtar&&Rc==Rtar) 
  {
  
  Ccounter=random (1,500);
  if (Ccounter>450) 
  {
  NEWcandle=random(Mincandle,Maxcandle);
  }
  else NEWcandle=BRcandleM;
  candlemode=2;
  Rtar=BRcandleM+5;
  Gtar=BRcandleM-delta;
  }
  }
  if (candlemode=2)
  {
  if (Gc==Gtar&&Rc==Rtar) 
   {
  Rtar=NEWcandle;
  Gtar=NEWcandle-delta; 
  candlemode=1;
   } 
  }
}
 if (mode==3)               // если включен режим 3 свет
 {
  if (Rc<Rtar) Rc++;
  if (Rc>Rtar) Rc--;
  if (Gc<Gtar) Gc++;
  if (Gc>Gtar) Gc--;
  if (Bc<Btar) Bc++;
  if (Bc>Btar) Bc--;
 }
 if (mode==4)               // если включен режим 4 яркий свет
  {
  if (Rc<Rtar) Rc++;
  if (Rc>Rtar) Rc--;
  if (Gc<Gtar) Gc++;
  if (Gc>Gtar) Gc--;
  if (Bc<Btar) Bc++;
  if (Bc>Btar) Bc--;
   currentMillisPIR = millis();         
    if (currentMillisPIR-prevMillisPIR >zaderzhkaF )
    {
      returnmode ();
    }
   }
 }
 
//-------------------------------   инициализация режима 1 переливание цвета ---------
   
void initmode1 ()   
{
   Rc=0;         
   Gc=BRpereliv; 
   Bc=BRpereliv;
   Gtar=0;
   Btar=BRpereliv;
   Rtar=0;
   nextcolor=1;
   interval=DELpereliv;
}

//-------------------------------  инициализация режима 2 свеча -----------------------
void initmode2 ()   
{
   Rc=BRcandleM;
   Gc=BRcandleM-delta;
   Bc=0;
   Rtar=BRcandleM;         
   Gtar=BRcandleM-delta;
   Bc=0;
   interval=DELAYcandle;
   candlemode=1;
}
//-------------------------------   инициализация режима 3 свет ----------------------- 
void initmode3 ()   
{
 initcolor();
 interval=DELAYsvet;
}

//------------------------------  инициализация режима  4 яркий свет ------------------ 
void initmode4 ()   
{
   Rtar=BRflash;         
   Gtar=BRflash; 
   Btar=BRflash;
   interval=DELAYflash1;
}
//-------------------------------------------- возвращаем предидущий режим -----------------
void returnmode ()  // возврат предидущего режима
{
  mode=prevmode;
  if (mode==1) initmode1 ();
  if (mode==2) initmode2 ();
  if (mode==3) initmode3 ();
}
//--------------------------------------------- устанавлвиваем значения портов -------------
void drawwing ()
{
  digitalWrite (Glaz,PIRon);
  analogWrite (Rled,Rc); 
  analogWrite (Gled,Gc); 
  analogWrite (Bled,Bc);
}
  //-------------------------------------------   инициализация цвета.... ------------------
void initcolor ()
{
   if (BRlithR>BRlithMAX) Rtar=BRlithR-BRlithMAX;
   else Rtar=BRlithR;
   if (BRlithG>BRlithMAX) Gtar=BRlithG-BRlithMAX;
   else Gtar=BRlithG;
   if (BRlithB>BRlithMAX) Btar=BRlithB-BRlithMAX;
   else Btar=BRlithB;
}
//---------------------------------------- настраиваем периферию при запуске-----------------
void setup()
{
    pinMode(Rled,OUTPUT);
    pinMode(Gled,OUTPUT);
    pinMode(Bled,OUTPUT);
    pinMode(Glaz,OUTPUT);
    pinMode(KeySET,INPUT);
    digitalWrite(KeySET,HIGH);    // включаем подтягивающий резистор 
    pinMode(KeyPLUS,INPUT);
    digitalWrite(KeyPLUS,HIGH);   // включаем подтягивающий резистор 
    pinMode(KeyMINUS,INPUT);
    digitalWrite(KeyMINUS,HIGH);  // включаем подтягивающий резистор 
    pinMode(Sensor,INPUT);
    pinMode(PIR,INPUT);
    initmode1 ();
}
//------------------------------------   основной цикл --------------------------------------
void loop()
{
  scankey ();
  drawwing ();
  calculator ();
  delay (interval);
}

 

Andry Smart
Offline
Зарегистрирован: 06.09.2016

короче в моем случае клавишей регулируется яркость в режиме свет (3й режим) но уменьшив ее до конца она опять становится максимум (так и задумано) но перестает дальше регулироваться.

а настройку цвета в 3м режиме я убрал, а то она была очень кривая