Битовый сдвиг

DezmontDeXa
Offline
Зарегистрирован: 09.02.2016

Мне нужно управлять светодиодной матрицей. Пытаюсь получать из функции управляющий сигнал вида B00000000. т.е. для X = 3, Y = 2 должно получиться B01000010. - Младшие 4 бита  - это Х координаты, старшие - Y.

Написал вот такую функцию
 

void LedOn(int x, int y) {
  
  int num = B00000000; //создаем переменную
  if (x < 5 && x > 0) { //Проверяем что введенные данные подходят для матрицы 4х4
    int xn = 1; //создаем переменную равную 1
    xn<<3; //делаем сдвиг влево, для перехода к младшим битам должно получиться 8(DEC) или 1000(BIN)
    xn<<x; //сдвигаем влево, что бы единица встала на нужное место. Для x = 3, должно получиться 01000000.
    num|xn; //делаем ИЛИ с num. Получится 01000000
    Serial.println(num, BIN); // в Протеусе выдает 0
  }
  if (y < 5 && y > 0) {
    int yn = 1;
    yn<<y-1;
    num|yn; //В результате для Х = 3 У= 2 должно было получиться 01000010. Но и тут протеус выдает 0.
  }
}

У меня ошибка в коде или Протеус тупит?

DezmontDeXa
Offline
Зарегистрирован: 09.02.2016

DezmontDeXa пишет:

Очепятка. У меня операция ИЛИ без присвоения. Исправил. Теперь протеус выдает 1.

 

void LedOn(int x, int y) {
  
  int num = B00000000; //создаем переменную
  if (x < 5 && x > 0) { //Проверяем что введенные данные подходят для матрицы 4х4
    int xn = 1; //создаем переменную равную 1
    xn<<3; //делаем сдвиг влево, для перехода к младшим битам должно получиться 8(DEC) или 1000(BIN)
    xn<<x; //сдвигаем влево, что бы единица встала на нужное место. Для x = 3, должно получиться 01000000.
    num|=xn; //делаем ИЛИ с num. Получится 01000000
    Serial.println(num, BIN); // в Протеусе выдает 0
  }
  if (y < 5 && y > 0) {
    int yn = 1;
    yn<<y-1;
    num|=yn; //В результате для Х = 3 У= 2 должно было получиться 01000010. Но и тут протеус выдает 0.
  }
}

У меня ошибка в коде или Протеус тупит?

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

DezmontDeXa, да похоже вся функция сплошная ошибка. Для начала поясните, как , цитата "для X = 3, Y = 2 должно получиться B01000010"

Если младшие пол-байта это X, то Y остаётся просто задвинуть на 4 бита влево, результат =  x | (y<<4)  , то есть  будет B00100011

DezmontDeXa
Offline
Зарегистрирован: 09.02.2016

дело не в числах которые получаются. Мне важна последовательность битов. С ардуины этот байт попадет на сдвиговый регистр. При данных: X = 3, Y = 2. Я хочу получить подледовательность битов 0100 0010 - где
0100 - означает X = 3. Единица сдвинута влево на 3.
0010 - Y=2. Единица сдвинута влево на 2.
Не сомневаюсь, что можно использовать другую последовательность, для которой потребуется лишь изменить связи в Протеусе. Но вот уже дошел умом до чего-то подобного.

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

DezmontDeXa, тогда так:  rezultat =  (1<<x+3) | (1<< y-1);

DezmontDeXa
Offline
Зарегистрирован: 09.02.2016

Спасибо! Так работает, но я не понимаю что было не так. Ну всм, ваш код гораздо компактнее и понятнее, но смысл то вроде тот же. Или нет? Распишите, пожалуйста, нужно ведь учиться, а не тупо исправлять косяки)

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

DezmontDeXa, чессно говоря смотреть что в вашем не так -утомительно.  В моём объяснялка простая - установить в переменной "результат"  два бита , под номерами  (х+3) и (у-1)

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

DezmontDeXa пишет:

Спасибо! Так работает, но я не понимаю что было не так. Ну всм, ваш код гораздо компактнее и понятнее, но смысл то вроде тот же. Или нет? Распишите, пожалуйста, нужно ведь учиться, а не тупо исправлять косяки)

Только всё остальное сам, без меня, потому что гугл всё знает.

void LedOn(int x, int y) {
  
  int num = B00000000;	// Ок
  if (x < 5 && x > 0) {	// Ок
    int xn = 1;			// Ок
    xn<<3;				// Лажа. Сдвиг мы делаем, но никуда результат не сохраняем.
    xn<<x;				// Лажа. Сдвиг мы делаем, но никуда результат не сохраняем.
    num|xn;				// Лажа. ИЛИ мы делаем, но никуда результат не сохраняем.
    Serial.println(num, BIN); // в Протеусе выдает 0 И ЭТО КОРРЕКТНО, потому что num нигде не меняется
  }
  if (y < 5 && y > 0) {
    int yn = 1;
    yn<<y-1;			// Лажа. Сдвиг мы делаем, но никуда результат не сохраняем.
    num|yn;				// Лажа. ИЛИ мы делаем, но никуда результат не сохраняем.
  }
}

 

DezmontDeXa
Offline
Зарегистрирован: 09.02.2016

Кисофт, спасибо! Уже в котоырй раз выручаешь)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DezmontDeXa пишет:
xn<<3; //делаем сдвиг влево, для перехода к младшим битам должно получиться 8(DEC) или 1000(BIN)

xn<<x; //сдвигаем влево, что бы единица встала на нужное место. Для x = 3, должно получиться 01000000.

Кому должно? Ну, сдвинули Вы, а результат куда? Выбросили? Присваивать его (результат) Вы чему-нибудь собираетесь?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
if (x < 5 && x > 0) { 
или все же
if ((x < 5) && (x > 0)) { 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

if (x < 5 && x > 0) { 
или все же
if ((x < 5) && (x > 0)) { 

Без разницы, но второе более системно.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

qwone пишет:

if (x < 5 && x > 0) { 
или все же
if ((x < 5) && (x > 0)) { 

 

Читайте о приоритетах операций.

Лично мне лень запоминать, в каком языке какие приоритеты, поэтому я всегда выбираю второй вариант.

DezmontDeXa
Offline
Зарегистрирован: 09.02.2016

Еще вопрос по теме битовых операций.
num=1<<x+3|1<<y-1;
Я упустил момент. Мне нужно инвертировать биты показывающие Y т.е. второй операнд ИЛИ должен быть инвертирован. 
num=(1<<x+3)|(~(1<<y-1)); - так инвертируются все 16бит(или сколько там в типе int?)
не хватет мне мозгов придумать как это слелать)

Сделал вот такую функцию, но может есть способ проще?
 

int NE(int var, int count){ //инвертирует указнное(count) кол-во битов в переменной (var)
  for (int i = 0; i<count; i++){
    if (bitRead(var, i)) {
      bitWrite(var, i, 0);
    }else{
      bitWrite(var, i, 1);
    }
  }
  return var;
}

 

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

rezultat =  (1<<x+3) | 15 & ~(1<< y-1);

DezmontDeXa
Offline
Зарегистрирован: 09.02.2016

Как всегда потрясающе) Как можно блин, так легко решать пободные задачи одним блин выражение?!

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

DezmontDeXa, а вы поменьше пользуйтесь ардуиновскими функциями, тогда битовые операции волей-неволей станут намного ближе и понятней:)

Buldakov
Offline
Зарегистрирован: 17.01.2016

Не могу нигде найти что за операции. Есть подозрение что битовые           <<=         и       |=

Применительно к коду:

cardid <<= 8;
cardid |= uid[1];

На что более понятное можно заменить?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Buldakov пишет:

Не могу нигде найти что за операции. Есть подозрение что битовые           <<=         и       |=

Применительно к коду:

cardid <<= 8;
cardid |= uid[1];

А чего их искать, вот они - операции http://ru.cppreference.com/w/cpp/language/operator_precedence

Buldakov пишет:

На что более понятное можно заменить?

А что Вам "более понятно"?

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

Buldakov пишет:

Не могу нигде найти что за операции. Есть подозрение что битовые           <<=         и       |=

Применительно к коду:

cardid <<= 8;
cardid |= uid[1];

На что более понятное можно заменить?

вот почему, после таких вопросов, не банить? из милосердия

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:

вот почему, после таких вопросов, не банить? из милосердия

Эвтаназия вроде как вне закона.

Logik
Offline
Зарегистрирован: 05.08.2014

Дак пусть себе и жил бы на другом каком форуме. Но если за полтора года ничему не научился здесь, то нафига продолжать. И это реально милосердие. У чела  жизнь одна, а он её так безцельно на ардуино тратит.

Buldakov
Offline
Зарегистрирован: 17.01.2016

спасибо за помощь. Как всегда когда делаещь что то новое приходится разбираться в том что есть. А если буржуи таким способом переводят шестнадцатиричную систему в десятичную поэтому и возникают вопросы.

Готовых кодов читать  карты под pn532  сложно найти. А как пользоваться библиотекой и подавно.

hugoboss317
Offline
Зарегистрирован: 21.03.2013
uint32_t var;  // т4 байта (32 бита вроде как)

var = (1 << 1); / / печатаем в бинарном виде получаем "0b10" (хорошо) 
var = (1 << 14); // печатаем .., получаем "0b100000000000000 (1 и 14 нулей, хорошо)
var = (1 << 15); // печатаем .., получаем
                         // 0x11111111111111111000000000000000  (17 "1" и  15 "0", упс) 
var = (1 << 16); // и более 16 до 31, печатаем .., получаем "0b0 (вообще не понятно).

Это нормально?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Нормально.

А Вы чего ожидали?

nik182
Offline
Зарегистрирован: 04.05.2015

А если так var= ((uint32_t)1 << 15); ?

Или var=(1UL <<15); ? 

hugoboss317
Offline
Зарегистрирован: 21.03.2013

ЕвгенийП пишет:

Нормально.

А Вы чего ожидали?

А я ожидал что единицу переместить до конца влево можно.

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

for(mask=(1<<(width-1)); mask!=0; mask>>=1)

Пока выводил символы шириной до 16, проблем не было.

Написал шрифт шириной 32 и (посадив шпионов во внутырь функции) обратил внимание что оператор "for" игнорится. Причина только одна - mask равна нулю.

поупражнявшись с выводом разных значений в бинарном виде вспомнил Хайяма.

 .. " Мне известно, что мне ничего не известно.

 Вот последняя правда открытая мной."

 

hugoboss317
Offline
Зарегистрирован: 21.03.2013

nik182 пишет:

А если так var= ((uint32_t)1 << 15); ?

Или var=(1UL <<15); ? 

Да, так получается.

for(mask=((uint32_t)1<<(width-1)); mask!=0; mask>>=1)

Теперь "шпионы" сказали что оператор выолняется.

В двух словах поясните?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

hugoboss317 пишет:

А я ожидал что единицу переместить до конца влево можно.

Так она до конца и сдвигает. Ведь Вы что написали?

var = (1 << 1);

Сначала вычисляется правая часть, а потом выполняется присваивание. Что у Вас в правой части? Единица типа int. Вот её Вы и сдвигаете, а она 16-битная и знаковая! А уже результат этого сдвига будет преобразован в uint32_t и присвоен var.

Понятно?

Что делать Вам уже nik182 сказал.

hugoboss317
Offline
Зарегистрирован: 21.03.2013

ЕвгенийП пишет:

Понятно?

Да, спасибо.

hugoboss317
Offline
Зарегистрирован: 21.03.2013

Опять я к вам. Только я не по поводу ограбленного Шпака, нет... Тут дело похлеще будет...

Atmega168P.

Есть глобальная переменная 16 бит.

При каждом цикле присваиваем случайное значение:

 mat = micros() >> 2;

Затем в цикле "for" перебираем по битам.

Если бит установлен, читаем содержимое eeprom с номером установленного бита + 20.

 for(col = 0; col < 16; col++){
    if((mat & _BV(col)) && (col < 4)){ // первые 4 для отладки
  dat = eeprom_read_byte(col+20);

 

Перебираем и находим какой по счёту бит установлен уже в восьми битной переменной.

Запоминаем, а затем значение сдвигаем на 1 бит влево. (или устанавливаем нулевой).

После чего записываем новое (сдвинутое на бит влево) значение в ту же ячейку до следующего раза.

while(!(bitRead(dat, row)) && row < 8){
  row++;
  }
// matrix(col*6, row, random(53));
rd1 = dat; // значение до сдвига
 if(row < 8) dat <<= 1;
 else        dat |= 1 << 0;
rd2 = dat; // значение прсле сдвига
 eeprom_write_byte(col+20, dat);

Для чего это я делаю не важно наверное. 

Проблема появляется в сдвиге, точнее после него. Причём если работать только с одним битом 16-и битной, то проблем нет. Всё как надо сдвигается. Но если 2 и больше, то с первым по счёту всё ОК,а в остальных после сдвига может появится единичка. Вот наглядно:

col - номер бита

rd1 - значение до сдвига

rd2 - после сдвига

dat - новые данные записанные в ее

rd3 - прочитанные из ее после записи (контрольно)

Нулевой или первый бит по по порядку, не важно. Всё как надо.

А остальные:

После сдвига просто появляется единица:

То есть даже не сдвигается.

Вот Этот же кусок кода целиком:

mat = micros() >> 2;
  for(col = 0; col < 16; col++){
    if((mat & _BV(col)) && (col < 4)){
  dat = eeprom_read_byte(col+20);
  
while(!(bitRead(dat, row)) && row < 8){
  row++;
  }
// matrix(col*6, row, random(53));
rd1 = dat; // значение до сдвига
 if(row < 8) dat <<= 1;
 else        dat |= 1 << 0;
rd2 = dat; // значение прсле сдвига
 eeprom_write_byte(col+20, dat);
 delay(250);
rd3 = eeprom_read_byte(col+20);
...// выводим на экран в бинарном виде

Сначала думал что с чтением из ЕЕ что то не так. Сдвигаю не так. Но если одна или первая без проблем, что потом не так? Грешу на железо... после рук естественно....

sadman41
Offline
Зарегистрирован: 19.10.2016

Конечно железо виновато, кто ж еще-то.

Где объявления переменных? Сделайте такой фрагмент, чтобы его можно было проверить на более другом железе.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

hugoboss317 пишет:
Грешу на железо...
Китайское поди? :-)

hugoboss317
Offline
Зарегистрирован: 21.03.2013

sadman41 пишет:
Конечно железо виновато, кто ж еще-то. Где объявления переменных? Сделайте такой фрагмент, чтобы его можно было проверить на более другом железе.

Да я не утверждаю, а предпоЛАГАЮ.

  uint8_t col, dat = 0, row = 0, rd1, rd2, rd3;

Переменные локальные (кроме вышеупомянутой). Это собственно первая строчка в функции. 

В общем то и реализация сводится к экономии всех типов памяти.

 

PS. Нашёл. Так тупо. Откуда, думаю, единички перетягиваются.

row = 0;

Перед повторным перебором байта предыдущий номер установленного бита обнулить надо...

  row = 0;
while(!(bitRead(dat, row)) && row < 8){
  row++;
  }

Я его при объявлении во избежании подобных лагов обнулял. А в цикле for он та остаётся.

В любом случаи спасибо что откликнулись и не стали критиковать исполнение.