2

so i am working on a project which needs a lots of bit manipulation and shifting out the bits to control the pins of shift registers individually.

So i am using 2 shift registers daisy chained with 16 LEDS. Now, what i want is that, i want to control the LEDs individually just by shifting out the bits

here is what i tried

first Attempt

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);
}

Does not work! the 2nd shift register seems to be copying the first shift register which i don't want

In second attempt, i tried the masking method with HEX data type. Here is it.

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);
}

This too makes same effect like the attempt 1 above.

Now here is what i want and need...

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.

but whenever i try this, it seems that one of the register is copying another one.

So, is there any way to shift out bits to control the shift register outputs individually?

if yes then please give a clear example code with a clear explanation.

if no then, please suggest me some alternative ways which can be used in the same way i want , of course with example code and explanation.

Schematic: arduino.cc/en/Tutorial/Foundations/ShiftOut

Thank You so much for your precious time.

Looking forward to your replies .

:)

4
  • Please show how you connected the shift registers. If you really have two of them daisy-chained they can’t be copying each other. Also, you seem to shift out just 1 byte (8 bits). For 16 LEDs connected to two 8-bit shift registers, you need to shift out 2 bytes.
    – StarCat
    Jul 22, 2021 at 6:01
  • arduino.cc/en/Tutorial/Foundations/ShiftOut here you may find the schematic Jul 22, 2021 at 6:39
  • Could you add that link to the question?
    – StarCat
    Jul 22, 2021 at 9:03
  • Ok added the link to the question through my mobile. Jul 22, 2021 at 13:16

2 Answers 2

2

You have two problems with your code:

  • byte is equal to unsigned char and can only hold exactly one byte, aka 8 bits (not 16 bits like your comment says). But you are trying to assign a 16bit number to it. The upper 8 bits are cut out in that process. They are lost. If you want to hold a 16bit number, you need to use a data type, that is at least 16 bits in its size, for example uint16_t (or you can use unsigned int, though in such situations it is often better to use a type, which has the same size on all platforms).

      uint16_t leds = 0b1000000000000001;
    
  • The shiftOut() function has this declaration in wiring_shift.c:

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

    You can see, that val (which is the data, that should be shifted out) is of type uint8_t, the same as byte, which also can only hold 8 bits. The upper 8 bits of a 16bit value would be cut off and the function also just transmits 8 bits, nothing more (When you look at its implemention in the mentioned file, you will see a for loop with 8 as limit).

    Instead you should call that function for every byte, that you want to transmit in a single transmission; 2 times in your case because you have 2 shift registers.

So the resulting program would look something like this:

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);
}

Note, that the masking with the bitwise AND operator is not really necessary here, but I like to do such things explicitly to make it more clear.


So I need to store almost 50 bits in the variable to control the columns so can 'uint' method be useful in this case ?

In that case I would use a byte array to hold the data. With 50 bits you are at 6.25 or 7 bytes (since you cannot have sub bytes). The declaration would be something like this:

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

And then you can shift that out with a for loop:

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);
}

Note that sizeof(leds) will return the size of the leds array in bytes. I also divided through the size of a single element of the array to get the number of elements in the array instead of bytes. In this case this is the same, but since datatypes might change while the code progresses it is better to be save than sorry.

i tried the masking method with HEX data type.

The data, that comes out is the same. The Arduino only knows of binary data. It doesn't know of different representions (like binary, HEX or decimal). The compiler will already convert that to the target value. So for the Arduino both ways are equivalent.

3
  • Actually, i am working on a 50x8 dot matrix project and writing up the library on my own instead of copying anyone's code. So I need to store almost 50 bits in the variable to control the columns so can 'uint' method be useful in this case ? Jul 22, 2021 at 6:43
  • Those 16 bits in the datatype byte is just a small example that I used to explain my problem Jul 22, 2021 at 6:44
  • @SubhaJeetSikdar I added a paragraph about that at the end of the answer.
    – chrisl
    Jul 22, 2021 at 6:55
1

The function shiftOut() only works for 8-bit values, as its documentation says.

Additionally, a byte can only store 8 bits. It doesn't matter how many bits you try to assign. (The compiler should have given you a warning, but the IDE likes to hide this.)

You need to write your own output function to shift out 16 bits, AFAIK.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.