Побитовый сдвиг

Alexsis f
Offline
Зарегистрирован: 22.11.2016

Прошу, не бейте больно. Сломал мозг, но хучу разобраться.

  for (int i = 0; i < 8; i++)  {

Serial.println(!!(0B11100011 & (1 << i)));

Serial выводит следующую последовательность: 1,1,1,0,0,0,1,1. Тут вопросов нет.

Убираю двойное отрицание

  for (int i = 0; i < 8; i++)  {

Serial.println(0B11100011 & (1 << i));

И в Serial вылазят: 1,2,0,0,0,32,64,128

Почему так?

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

Так и должно быть.

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

Alexsis f пишет:

Почему так?

Потому что ! - логическая операция, на выходе её true или false которые соответствуют 1 или 0. Но эффект забавный.

Да, и сдвиг здесь вобще никаким боком.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Alexsis f пишет:

1,1,1,0,0,0,1,1. Тут вопросов нет.

И в Serial вылазят: 1,2,0,0,0,32,64,128

Наверно потому что bool 0  может быть только 0, а все что не 0 это уже 1 .

1 - это 1 // 2 это 1 // 32 это 1 // и так далее

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

ТС тут написал, что вопросов нет.

Я думаю, что нет вопросов исключительно потому, что он ничего не понял.

Невозможно понгять 3-ю строчку его сообщения и не понять 7-ю, т.к. 7-я получается из 3-й упрощением.

Идея - не скажу, что совершенно стандартная, но достаточно очевидная - двойное отрицание нужно, чтобы перевести единицу в любом разряде в единицу в нулевом разряде. По уму двигать нужно было число, а не маску, что все нормальные люди и делают, но автор 3-й строки (очевидно, не ТС) решил сделать по-другому. Такое нестандартное решение повлекло за собой другое нестандартное - какой операцией можно превратить любое ненулевое число в 1? Очевидно, двойным отрицанием.

2qwone: в Си нет булевого типа данных, обозначение bool нужно исключительно для программиста, чтобы ему легче было разобраться в коде. А так - это обычное целое  со всеми вытекающими отсюда последствиями.

Alexsis f
Offline
Зарегистрирован: 22.11.2016

Не буду цитировать каждого, т.к. все мне помогли разобраться. Спасибо вам.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Для управления CD74HC4067 на его "адресные" входа нужно поочередно подавать следующие состояния (от 0 до 15)

int readMux(int channel){
  int controlPin[] = {S0, S1, S2, S3};

  int muxChannel[16][4]={
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10
    {1,1,0,1}, //channel 11
    {0,0,1,1}, //channel 12
    {1,0,1,1}, //channel 13
    {0,1,1,1}, //channel 14
    {1,1,1,1}  //channel 15
  };

  //loop through the 4 sig
  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }

 

Используя регистры:

  DDRD |= (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7); //Выходы
  PORTD &= ~ ((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)); //LOW

  switch (var) {
    case 0:
      PORTD &= ~ ((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));//0000
      break;
    case 1:
      PORTD |= (1 << 4);
      PORTD &= ~ ( (1 << 5) | (1 << 6) | (1 << 7));
      break;
    case 1:
      PORTD |= (1 << 5);
      PORTD &= ~ ( (1 << 4) | (1 << 6) | (1 << 7));
      break;
  }

Чую с регистрами есть вариант проще...(не трогая другие биты порта)

Подскажите)

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

Попроще это вот так примерно:

int readMux(int channel){
  uint8_t controlPin[] = {S0, S1, S2, S3};

  //loop through the 4 sig
  for(uint8_t i = 0; i < 0x0F; i++) {
    for (uint8_t p = 0; p < sizeof(controlPin); p++) {
      uint8_t controlPinState = bitRead(i, p); 
      digitalWrite(controlPin[p], controlPinState);
    }
    ...
  }
...
}

А с регистрами - это никогда не "попроще".

Green
Offline
Зарегистрирован: 01.10.2015

<= 0x0f, bool controlPinState много букв)

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
/*byte port[16] = {
  0b00000000,//0000
  0b10000000,//1000
  0b01000000,//0100
  0b11000000,//1100
  0b00100000,//0010
  0b10100000,//1010
  0b01100000,//0110
  0b11100000,//1110
  0b00010000,//0001
  0b10010000,//1001
  0b01010000,//0101
  0b11010000,//1101
  0b00110000,//0011
  0b10110000,//1011
  0b01110000,//0111
  0b11110000,//1111
  };*/

byte port[16] = {0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0};

void setup() {
  DDRD |= (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7); //Выходы
  PORTD &= ~ ((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)); //LOW
}


byte readMux(byte channel) {
  for (byte b = 4; b < 8; b++) {
    byte bitread = port[channel] & (1 << b);
    if (bitread) {
      PORTD |= (1 << b);
    } else {
      PORTD &= ~ (1 << b);
    }
  }
}

Вот такой вариант

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

А если использовать битовые маски

byte BitsMask = port[2] & 0b11110000;
PORTD=BitsMask;

Взяла 4 5 6 7  биты из байта и записала их в порт

Но при этом будут меняться и 0 1 2 3 биты

Green
Offline
Зарегистрирован: 01.10.2015

Неужто нужна скорость?

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

Irinka пишет:

А если использовать битовые маски

byte BitsMask = port[2] & 0b11110000;
PORTD=BitsMask;

Взяла 4 5 6 7  биты из байта и записала их в порт

Но при этом будут меняться и 0 1 2 3 биты

Меняться - это полбеды. Вот когда нужно будет срочно пин освободить - тогда начнется кама-с-утра.

А избежать изменения можно:

int8_t writeToPort(const uint8_t _portNo, const uint8_t _value, const uint8_t _port_protect_mask) {
  volatile uint8_t *portRegister = portOutputRegister(_portNo);
...
  // Port write transaction
  // Use protection mask when write to port for saving some pins state
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *portRegister = (*portRegister & _port_protect_mask) | (_value & ~_port_protect_mask); }
...
}

port_protect_mask задается так: B11110000 - если в маске 1, то бит порта не изменяется, если 0 - перезаписывается новым значением.

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

Irinka пишет:

 на его "адресные" входа ...

Мы говорим не "входы". а "входа" -

Слова входят коротки и смачны.

"ПинЫ" - не "пИны" - сводят нас с ума,

Из флэша выкорчёвывая байты.

Почти Высоцкий! ;)))

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

Осталось измерить напряжение "на пину", и "прошить скейч".

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

Green пишет:

<= 0x0f, bool controlPinState много букв)

<= - верно.

А много букв - для понятности. Компилятору-то пофиг, он читать не умеет. Можно было, конечно, прямо в digitalWrite битшифт заговнокодить ))

Green
Offline
Зарегистрирован: 01.10.2015

wdrakula пишет:

Осталось измерить напряжение "на пину", и "прошить скейч".


Сплошь и рядом. "Залить скейч" обычное дело.) Ну ладно дети... Ребёнку постоянно выговариваю.(

Green
Offline
Зарегистрирован: 01.10.2015

Irinka, не страдали бы вы ерундой. Вся эта мнимая скорость никому не нужна. Постоянно вижу как "гонщики" скоростят до светофора.)

b707
Offline
Зарегистрирован: 26.05.2017

Irinka пишет:

А если использовать битовые маски

byte BitsMask = port[2] & 0b11110000;
PORTD=BitsMask;

Взяла 4 5 6 7  биты из байта и записала их в порт

Но при этом будут меняться и 0 1 2 3 биты

идея правильная, чуть-чуть подправить осталось:

PORTD &= ~  0b11110000;   // сначала обнуляем все биты с 4 по 7
PORTD |= port[2];          // а потом выставляем только те, что 1

Итог - биты с 4 по 7 поменяны в соответсвии со значением port[2], остальные биты порта не затронуты.

Green
Offline
Зарегистрирован: 01.10.2015

Ужос! Вот только зачем, спросит удивлённый читатель?

PORTD = (PORTD & B00001111) | ВАШИ БИТЫ ОТ 0 ДО 15<<4;

 

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

b707 пишет:

PORTD &= ~  0b11110000;   // сначала обнуляем все биты с 4 по 7
PORTD |= port[2];          // а потом выставляем только те, что 1

Так не пойдёт, каждый проход будет сбрасывать 4 адресных входа в ноль.

b707
Offline
Зарегистрирован: 26.05.2017

Irinka пишет:

Так не пойдёт, каждый проход будет сбрасывать 4 адресных входа в ноль.

запишите эти две строки в одну, как Green выше показал

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Green пишет:

PORTD = (PORTD & B00001111) | ВАШИ БИТЫ ОТ 0 ДО 15<<4;

Как эту запись понимать?

b707
Offline
Зарегистрирован: 26.05.2017

Irinka пишет:

Green пишет:

PORTD = (PORTD & B00001111) | ВАШИ БИТЫ ОТ 0 ДО 15<<4;

Как эту запись понимать?

это тоже самое, как

PORTD &= ~  0b11110000;   // сначала обнуляем все биты с 4 по 7
PORTD |= port[2];          // а потом выставляем только те, что 1

только записанное в одну строку

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
port[0]=0b11000000;

PORTD = (PORTD & B00001111) | port[0];

В итоге сначала биты с 4 по 7 будут 0, потом будут 1 1 0 0

Так?

 

b707
Offline
Зарегистрирован: 26.05.2017

Irinka пишет:

port[0]=0b11000000;

PORTD = (PORTD & B00001111) | port[0];

В итоге сначала биты с 4 по 7 будут 0, потом будут 1 1 0 0

Так?

все это считается в одно действие, поэтому никакие "сначала" и "потом" на содержимом PORTD не скажутся, результат будет аналогичен единомоментной установке старших четырех бит в значения 1 1 0 0

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Классно! Не то что digitalWrite...Код стал красивее, короче!

PORTD & B00001111 это тоже, что и PORTD = B00001111? Но при этом в 0 1 2 3 биты ничего не записывается.

далее | port[0] записываются в порт только 1, 0 не пишутся, т.е.  если port[0]=0b10000011

то два младших бита так же запишутся в порт?

 

 

Green
Offline
Зарегистрирован: 01.10.2015

Нет, ну это, конечно, годится для тренировки, но. Ардуино - это более высокая абстракция, нежели PORTD и DDRD.
И это удобно. Это специально сделано для вас, блондинок. А тогда заради чего вам спускаться вниз, в эту клоаку?

b707
Offline
Зарегистрирован: 26.05.2017

Иринка, не надо этой кучи банальных вопросов, ответы на которые вы и сами знаете. Не частите, просто посидите и подумайте

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Спасибо

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

Это специально сделано для вас, блондинок...

а что с брюнетками?

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Все куда прозаичнее

PORTD=(PIND)&(0xF0|port[0]);

Green
Offline
Зарегистрирован: 01.10.2015

ua6em пишет:

а что с брюнетками?


Это и мужиков касается. Раньше только избранные с МК работали, а сейчас любая блондинка может.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Green пишет:

Это и мужиков касается. Раньше только избранные с МК работали, а сейчас любая блондинка может.

Ты сейчас прям меня описал

Green
Offline
Зарегистрирован: 01.10.2015

Kakmyc пишет:
Все куда прозаичнее PORTD=(PIND)&(0xF0|port[0]);

Кактус, быдлокод детектед. Неверно. Должно быть вы хотели:
PORTD = (PORTD & 0xF0) | port[0];
Однако, даме нужно изменять старший ниббл, поэтому
PORTD = (PORTD & 0x0f) | port[0]<<4;
И никак иначе.
 

b707
Offline
Зарегистрирован: 26.05.2017

Green пишет:

Однако, даме нужно изменять старший ниббл, поэтому
PORTD = (PORTD & 0x0f) | port[0]<<4;
И никак иначе.
 

у нее в массиве port[] уже подготовленные данные, сдвинутые в старшие биты:

/*byte port[16] = {
  0b00000000,//0000
  0b10000000,//1000
  0b01000000,//0100
  0b11000000,//1100
  0b00100000,//0010
  0b10100000,//1010
  0b01100000,//0110
  0b11100000,//1110
  0b00010000,//0001
  0b10010000,//1001
  0b01010000,//0101
  0b11010000,//1101
  0b00110000,//0011
  0b10110000,//1011
  0b01110000,//0111
  0b11110000,//1111
  };*/

поэтому двигать port[0] уже не нужно

Green
Offline
Зарегистрирован: 01.10.2015

Нет, ну тогда, это уж как ей соизволится.)

Green
Offline
Зарегистрирован: 01.10.2015

Вообще, конечно, не красиво говорить о человеке в третьем лице, но думаю, вы понимаете. У нас тут всё по простому.)

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Всё поняла, спасибо)