Как управлять выводом регистров сдвига по отдельности побитово

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

Поэтому я использую 2 регистра сдвига, соединенных цепочкой с 16 светодиодами. Теперь я хочу, чтобы я управлял светодиодами по отдельности, просто перемещая биты

вот что я попробовал

первая попытка

int latchPin = 4;   // Latch pin of 74HC595 is connected to Digital pin 5
int clockPin = 5;   // Clock pin of 74HC595 is connected to Digital pin 6
int dataPin = 3;    // Data pin of 74HC595 is connected to Digital pin 4

byte leds=0b1000000000000001; // byte has 16 bits

void setup() 
{
   
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
}


void loop() 
{

  updateShiftRegister();
  
}


void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);

   shiftOut(dataPin, clockPin, LSBFIRST, leds);
   digitalWrite(latchPin, HIGH);
}

Не работает! 2 - й регистр сдвига, похоже, копирует первый регистр сдвига, который мне не нужен

Во второй попытке я попробовал метод маскировки с шестнадцатеричным типом данных. Вот оно.

int latchPin = 4;   // Latch pin of 74HC595 is connected to Digital pin 5
int clockPin = 5;   // Clock pin of 74HC595 is connected to Digital pin 6
int dataPin = 3;    // Data pin of 74HC595 is connected to Digital pin 4

byte leds=0xFFFF & 0x8001; // used hex masking method

// 0xFFFF = 1111111111111111
// 0x8001 = 1000000000000001
// After & it should be 1000000000000001

void setup() 
{
   
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
}


void loop() 
{

  updateShiftRegister();
  
}


void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);

   shiftOut(dataPin, clockPin, LSBFIRST, leds);
   digitalWrite(latchPin, HIGH);
}

Это тоже дает тот же эффект, что и попытка 1 выше.

Теперь вот чего я хочу и в чем нуждаюсь...

byte leds = 0b1000000000000001


/* As you can see the index 0 and index 15 of the byte led
  is set 1 or high which should produce +ve to the 15th pin of first register and 8th pin of second register.

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

Итак, есть ли какой-либо способ смещения битов для индивидуального управления выходами регистра сдвига?

если да, то, пожалуйста, приведите четкий пример кода с четким объяснением.

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

Схема: arduino.cc/en/Tutorial/Foundations/ShiftOut

Большое Вам спасибо за ваше драгоценное время.

С нетерпением жду ваших ответов .

:)

, 👍2

Обсуждение

Пожалуйста, покажите, как вы подключили регистры сдвига. Если у вас действительно есть два из них, связанных цепочкой, они не могут копировать друг друга. Кроме того, вы, кажется, смещаетесь всего на 1 байт (8 бит). Для 16 светодиодов, подключенных к двум 8-разрядным регистрам сдвига, необходимо сдвинуть 2 байта., @StarCat

https://www.arduino.cc/en/Tutorial/Foundations/ShiftOut/ здесь вы можете найти схему, @Subha Jeet Sikdar

Не могли бы вы добавить эту ссылку к вопросу?, @StarCat

Ок добавил ссылку на вопрос через свой мобильный телефон., @Subha Jeet Sikdar


2 ответа


Лучший ответ:

2

У вас есть две проблемы с вашим кодом:

  • byte равен символу без знака и может содержать только ровно один байт, он же 8 бит (а не 16 бит, как говорится в вашем комментарии). Но вы пытаетесь присвоить ему 16-битный номер. В этом процессе вырезаются верхние 8 бит. Они заблудились. Если вы хотите сохранить 16-битное число, вам необходимо использовать тип данных размером не менее 16 бит, например uint16_t (или вы можете использовать unsigned int, хотя в таких ситуациях часто лучше использовать тип, который имеет одинаковый размер на всех платформах).

      uint16_t leds = 0b1000000000000001;
    
  • Функция shiftOut() имеет это объявление в wiring_shift.c:

      void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
    

    Вы можете видеть, что val (то есть данные, которые должны быть сдвинуты) имеет тип uint8_t, такой же, как byte, который также может содержать только 8 бит. Верхние 8 бит 16-битного значения будут отключены, и функция также просто передает 8 бит, не более того (когда вы посмотрите на ее реализацию в упомянутом файле, вы увидите цикл for с 8 в качестве предела).

    Вместо этого вы должны вызывать эту функцию для каждого байта, который вы хотите передать в одной передаче; в вашем случае 2 раза, потому что у вас 2 регистра сдвига.

Таким образом, полученная программа будет выглядеть примерно так:

int latchPin = 4;   // Latch pin of 74HC595 is connected to Digital pin 5
int clockPin = 5;   // Clock pin of 74HC595 is connected to Digital pin 6
int dataPin = 3;    // Data pin of 74HC595 is connected to Digital pin 4

uint16_t leds=0b1000000000000001; // uint16_t has 16 bits

void setup() 
{
   
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
}


void loop() 
{

  updateShiftRegister();
  
}


void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);

   // Shiftout lower byte by masking the other byte with bitwise AND (&)
   shiftOut(dataPin, clockPin, LSBFIRST, leds & 0xFF);
   // Shiftout higher byte by shifting the bit pattern 8 bits to the right
   // resulting in the high byte getting to the position of the low byte
   // and then masking away anything else than the new position of the high
   // byte data
   shiftOut(dataPin, clockPin, LSBFIRST, (leds >> 8) & 0xFF);
   digitalWrite(latchPin, HIGH);
}

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


Поэтому мне нужно сохранить почти 50 бит в переменной, чтобы управлять столбцами, так может ли метод "uint" быть полезным в этом случае ?

В этом случае я бы использовал массив байтов для хранения данных. При 50 битах вы получаете 6,25 или 7 байт (так как у вас не может быть суббайтов). Декларация будет выглядеть примерно так:

byte leds[] = {0b00011001, ... }; // list the byte data here

А затем вы можете изменить это с помощью цикла for:

void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);
   for(int i=0;i<sizeof(leds)/sizeof(leds[0]);i++){
       shiftOut(dataPin, clockPin, LSBFIRST, leds[i]);
   }
   digitalWrite(latchPin, HIGH);
}

Обратите внимание, что sizeof(светодиоды) вернет размер массива светодиодов в байтах. Я также разделил размер одного элемента массива, чтобы получить количество элементов в массиве вместо байтов. В данном случае это то же самое, но поскольку типы данных могут меняться по ходу выполнения кода, лучше сохранить, чем сожалеть.

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

Данные, которые выходят, те же самые. Arduino знает только двоичные данные. Он не знает о различных представлениях (например, двоичных, шестнадцатеричных или десятичных). Компилятор уже преобразует это в целевое значение. Так что для Arduino оба способа эквивалентны.

,

На самом деле, я работаю над проектом матрицы 50x8 точек и пишу библиотеку самостоятельно, вместо того, чтобы копировать чей-либо код. Поэтому мне нужно сохранить почти 50 бит в переменной для управления столбцами, так может ли метод "uint" быть полезным в этом случае ?, @Subha Jeet Sikdar

Эти 16 бит в байте типа данных-это всего лишь небольшой пример, который я использовал, чтобы объяснить свою проблему, @Subha Jeet Sikdar

@SubhaJeetSikdar Я добавил абзац об этом в конце ответа., @chrisl


1

Функция shiftOut() работает только для 8-разрядных значений, как указано в документации.

Кроме того, byte может хранить только 8 бит. Не имеет значения, сколько битов вы пытаетесь присвоить. (Компилятор должен был предупредить вас, но IDE любит это скрывать.)

Вам нужно написать свою собственную функцию вывода, чтобы сдвинуть 16 бит, AFAIK.

,