Биты и преобразование

Мининова
Offline
Зарегистрирован: 08.06.2012

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

void DoBlinking() 
{
  int data_size = sizeof(main_data);
  int blink_size = sizeof(blink_data);
  if(data_size != 0 && blink_size != 0)
  {
    for(int i=0; i<data_size; i++)
    {
      byte m_d = main_data[i];
      byte b_d = blink_data[i];

      if(b_d > 0x00) 
      {
        for(int b=0; b<8; b++)
        {
          byte curr_bit_data = bitRead(m_d,b);
          byte curr_bit_blink = bitRead(b_d,b);
          if(curr_bit_blink == 1)
          { 
//Был 1
            Serial.print("was ");
            Serial.print(curr_bit_data);
            bitWrite(curr_bit_data, b, ~curr_bit_data ); 
            Serial.print(" set ");
            Serial.print(curr_bit_data);    
// а становится черти-чем 9, 17, 33, 65, 129 итд..
          }

          Serial.println("~~~~~~~~~~~~~~~");
          delay(1000);
        }
      }    
    }
  }
}

Благодарю.

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Вместо  Serial.print(curr_bit_data);

Сделайте Serial.println(curr_bit_data,BIN); - тогда число выведется в двоичном виде. Проще будет понять какие биты установились.

А вместо 

bitWrite(curr_bit_data, b, ~curr_bit_data );
 

Попробуйте 

curr_bit_data ^= 1 << b;

 

leshak
Offline
Зарегистрирован: 29.09.2011

 И еще, строка 16-ть.

Зачем она? У вас же получается что curr_bit_data всегда только 0 или 1. Только первый бит установлен. Наверное логичней будет

curr_bit_data=m_d

 

Мининова
Offline
Зарегистрирован: 08.06.2012

Благодарю за помощь, опять вы меня выручаете.

Serial.print("was ");
Serial.print(curr_bit_data,BIN);
curr_bit_data ^= curr_bit_data; // XOR текущего бита
Serial.print(" set ");
Serial.print(curr_bit_data,BIN); 

Я сделал вот так.
Я использую 13 сдвиговых регистров чтобы управлять большим массивом Пираний.

Строка 16 нужна чтобы понимать что из себя представлеят текуший бит. Был ли он зажжен ранее. Все 8 бит задейсвованны в этом байте - ведь они двигаются как паровозик по микросхемам при заливке новых данных. Каждый бит - это 1 из 8 ножек.

P.S. Мне очень хочется стать "пилотом F1". Думаю что я на верном пути, благодарю Вас еще раз. С вашей помощью это происходит быстрее.
 

leshak
Offline
Зарегистрирован: 29.09.2011

 И у вас так заработало? По идее же XOR в этом случае должен всегда тупо сбрасывать curr_bit_data в ноль. А вы, вроде, хотели инвертирование. Если же это "то что нужно", то не проще ли просто написать curr_bit_data=0;? А если инвертировать, то нужно было not логический делать curr_bit_data = !curr_bit_data;

Кстати не обязательно менять каждый бит отдельно менять. Можно "одним махом восьмерых побивахом" (а в случае int сразу 16-ть). Причем менять только "те которые нужно". Смотрите:

void setup(){
  Serial.begin(9600);
  
  byte inputData=B10101010; // выходные данные
  byte mask=     B00001111; // маска по которой будем инвертировать. нужно поменять только младшие четыре бита

  byte outputData=(inputData & ~mask) | (~inputData & mask); // инвертируем только те биты, которые в mask равны 1
  
  Serial.print("Input:");Serial.println(inputData,BIN); // выведет   Input: 10101010
  Serial.print("Outout:");Serial.println(outputData,BIN); // выведет Outout:10100101


}

void loop(){}

 

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Вообщем весь этот DoBlinking(), если выкинуть Serial.print-ты можно ужать до одной строчки (там еще и куча If-фов лишняя, которые никакой погоды не делает).

void DoBlinking() 
{
  for(int i=0; i<sizeof(main_data); i++)main_data[i]=(main_data[i] & ~blink_data[i]) | ( ~main_data[i] & blink_data[i] );
  // а тут уже можем блинкать исходя из новых, инвертированных значений.
}

А если, потом почитать http://arduino.ru/Tutorial/Upravlenie_portami_cherez_registry

То можно сразу, без циклов и светики устанавливать "пачкой". По 8-мь штук за раз. Одним присваиванием байта.

Мининова
Offline
Зарегистрирован: 08.06.2012

Да, вы как всегда правы. Ступил. Конечно curr_data = !curr_data не XOR a NOT
Проверил. теперь все работает как нужно.
 

void DoBlinking() 
{
  int blink_size = sizeof(blink_data);
  if(blink_size != 0)
  {
    for(int i=0; i<blink_size; i++)
    {
      byte m_d = main_data[i];
      byte b_d = blink_data[i];

      if(b_d > 0x00) 
      {
        for(int b=0; b<8; b++)
        {
          byte curr_bit_data = bitRead(m_d,b);
          byte curr_bit_blink = bitRead(b_d,b);
          if(curr_bit_blink == 1)
          { 
               curr_bit_data = !curr_bit_data;
               bitWrite(m_d, b, curr_bit_data);
          }
        }
         main_data[i] = m_d;
      }
    }
  }
}

 

Благодарю за ссылку. Обязательно разберусь.

leshak
Offline
Зарегистрирован: 29.09.2011

 >Благодарю за ссылку. Обязательно разберусь.

Вначале дожмите код который есть. Строка 04 повторяет условие в строке 06. Ничего полезного, кроме захламления кода - не делает.

Строку 11 - тоже можно убрать. Без нее поведение не изменится.  Ну съэкономится пара микросекунд в случае если b_d=0 ну и что?  Строка 17 - все равно ничего неправильного не даст сделать. Так что можно спокойно убрать что-бы код был легче. Тем более что во всех других случаях, эти микросекунды будут тратится на проверку этого условия.

> Ступил. Конечно curr_data = !curr_data не XOR a NOT

А не зря он вам тут премерещился. Только применять его нужно не к одному биту, а ко всему байту. Еще раз вгляделся в то что получилось итогово: да мы же изобрели велосипед!!! Всмотритесь: вы, многословно, через цикл, я, чуть компактней, но все равно не идеально, заново реализовали XOR!!!!!

Пустите такой скетч:

void setup(){
  Serial.begin(9600);
  
  byte inputData=B10101010; // выходные данные
  byte mask=     B00001111; // маска по которой будем инвертировать. нужно поменять только младшие четыре бита

  byte outputData=(inputData & ~mask) | (~inputData & mask); // инвертируем только те биты, которые в mask равны 1
  byte outputData2=inputData ^ mask; // по идее то же самое, только короче
  
  Serial.print("Input  :");Serial.println(inputData,BIN); // выведет  Input  :10101010
  Serial.print("Output :");Serial.println(outputData,BIN); // выведет  Output :10100101
  Serial.print("Output2:");Serial.println(outputData2,BIN); //выведет  Output2:10100101


}

void loop(){}

 Учитывая это, ваш блин можно сделать еще проще

void DoBlinking(){  for(int i=0; i<sizeof(main_data); i++)main_data[i]^=blink_data[i]; }

Попробуйте.  По идее должно вести себя так же как и ваша текущая версия.