Potentiometer controlled daisy chained shift registers

Hi everybody…

I’ve written a sketch which allows me to control the bits sent to two shift registers which are daisy chained together in order to control an array of 16 LED’s. It takes a value from the potentiometer and compares it against the indexes from two different arrays (one for the first half of the pot rotation and one for the second). it does this using two for loops. When the pot value goes above any index value it will take the value stored in the corresponding index from a third array which is filled with the binary values for the shift register… this is then sent using shiftOut.

The sketch is working nicely except for one issue… When I turn the pot downwards (anticlockwise) too fast, one or two of the LED’s don’t turn off. For some reason LED’s 9 and 10 and sometimes 11 (which are the first few indexes of the second array) stay lit.

Looking at it on the serial monitor I can see that when the value should drop to 0 on output2 they actually stay at 1 or 3 or even 7.

Can anybody see where I’m going wring here please?

here is my code: -

int div2 = 0;
int output1 = 0;                                              //store values from binary[] and send to shift register
int output2 = 0;                                              //store values from binary[] and send to shift register
int latchPin = 2;
int clockPin = 3;
int dataPin = 4;

int LED1[8] = {0, 32, 64, 96, 128, 160, 192, 224};            //to be compared against first half of pot rotation
int LED2[8] = {256, 288, 320, 352, 384, 416, 448, 480};       //to be compared against second half of pot rotation
    
int binary[16] = {0, 1, 3, 7, 15, 31, 63, 127};               //binary values to be sent to shift registers via output1 and output2

int val;                                                      //value read from pot
int lastVal;

void setup(){
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
}
void loop(){
      
      val = analogRead(A0);                                   //read the pot
      if(val - lastVal > 4 || lastVal - val > 8){             //stabilize the reading
        //Serial.println(val / 8);
        lastVal = val;
      }
      
      div2 = val / 2;                                         //divide the pot reading by 2

      for(int i = 0; i < 8; i++) {                            //compare value of div2 to the given indexes in LED1[]   
        if(div2 > LED1[i]){                                   //if div2 goes above the value stored in any index...
        output1 = binary[i];                                  //set output to the value stored in binary[i]
          if(div2 < 2){                                       //if div2 goes below 2 switch all LED's off
            output1 = 0;
          }
          if(div2 > 256){                                     //if dv2 is above 256 make sure LED's 1 - 8 are on
            output1 = 255;
      }
    }
  }
        for(int j = 0; j < 8; j++) {                          //repeat the process above for second half of pot rotation
        if(div2 > LED2[j]){
        output2 = binary[j];
          if(div2 < 256){
            output2 = 0; 
      } 
          if(div2 > 504){                                     //if div2 goes above 504 make sure LED's 9 - 16 are on (the number is slightly under 512 in order to compensate for poor connection on breadboard)
            output2 = 511;
      }
    }
  }

      digitalWrite(latchPin, LOW);                        
      shiftOut(dataPin, clockPin, LSBFIRST, output2);                       
      shiftOut(dataPin, clockPin, LSBFIRST, output1);          
      digitalWrite(latchPin, HIGH);      
      
      Serial.print(output1);
      Serial.print("------");
      Serial.print(output2);  
      Serial.print("------");
      Serial.println(div2);
       
delay(25);
}

also... here's a youtube video of the problem: -

Many thanks

1 Like

Thanks so much for using code tags, posting a proper schematic, even posting a video to demonstrate the problem. It's not often anyone has the decency to read the forum guide and provide what the forum needs to be able to help, instead of acting like the forum owes them something and everyone on the forum has amazing psychic powers!

1 Like

Do you really need to serial print every time through loop()?

If so, can you use a faster baud rate?

Why the delay()? Is it to slow printing down?

Try with no printing and no delay. Does it work better?

Would SPI be faster than pulseOut?

Try this (untested):

void loop() {
  int val = analogRead(A0);
  val = map(val, 0, 1023, 0, 16); // reduce val to 0..16
  if (val > 0) val = (1 << val) - 1; // calculate the bit pattern
  digitalWrite(latchPin, LOW);                        
  shiftOut(dataPin, clockPin, LSBFIRST, lowbyte(val));                       
  shiftOut(dataPin, clockPin, LSBFIRST, highbyte(val));          
  digitalWrite(latchPin, HIGH);      
  delay(25);
}
1 Like

I tried removing all Serial.prints and the delay but no difference.

not really sure what you mean by using SPI instead of pulseOut... I'm using shiftOut.

But thanks anyway

I'm a little confused by your suggestiong here... can't really get my head around this line: -

if (val > 0) val = (1 << val) - 1;

also... where and how would lowbyte and highbyte be declared? should they be arrays containing bytes?

Thanks for your help by the way.

The highByte() function and lowByte() function are Arduino functions (see the reference).

ahh right...
They didn't show up as function keywords in arduino IDE because i put lowbyte() and highbyte() which is what you wrote.
whereas it should have been lowByte() and highByte() .... with the capital B's .

now they're showing up in red text.
I'll try and again and see what i get.

thank you

I meant shiftOut(), sorry, brain fart.

SPI can be much faster than shiftOut(), but SPI needs certain pins where shiftOut can be used on any digital pin(s).

From the Sparkfun SPI tutorial.

  1. You can use the shiftIn() and shiftOut() commands. These are software-based commands that will work on any group of pins, but will be somewhat slow.
  2. Or you can use the SPI Library, which takes advantage of the SPI hardware built into the microcontroller. This is vastly faster than the above commands, but it will only work on certain pins.

Here is a thread using SPI on daisy chained 74595 shift registers.

Consult the SPI library reference for the SPI pins on the Mega.

okay so I tried that and it doesn't seem to be controlling the LED's however, I added some Serial.prints onto the end to see what I was getting in the serial monitor and it seems to be sending exactly the right values.
So the problem seems to be related to how the bytes are being sent to the shift registers.

here is the code with the serial.prints on the end: -


int latchPin = 2;
int clockPin = 3;
int dataPin = 4;

void setup(){
  Serial.begin(9600);

}

void loop(){
  int val = analogRead(A0);
  val = map(val, 0, 1023, 0, 16); // reduce val to 0..16
  if (val > 0) val = (1 << val) - 1; // calculate the bit pattern
  digitalWrite(latchPin, LOW);                        
  shiftOut(dataPin, clockPin, LSBFIRST, lowByte(val));                       
  shiftOut(dataPin, clockPin, LSBFIRST, highByte(val));          
  digitalWrite(latchPin, HIGH);      
  delay(25);
  Serial.print(lowByte(val));
  Serial.print(" ----- ");
  Serial.println(highByte(val));
}

and here is the readout from the serial monitor as I rotate the pot clockwise: -

21:09:37.978 -> 0 ----- 0
21:09:37.978 -> 0 ----- 0
21:09:38.025 -> 0 ----- 0
21:09:38.025 -> 0 ----- 0
21:09:38.071 -> 1 ----- 0
21:09:38.071 -> 1 ----- 0
21:09:38.118 -> 1 ----- 0
21:09:38.165 -> 1 ----- 0
21:09:38.165 -> 1 ----- 0
21:09:38.212 -> 1 ----- 0
21:09:38.212 -> 1 ----- 0
21:09:38.259 -> 1 ----- 0
21:09:38.259 -> 1 ----- 0
21:09:38.306 -> 1 ----- 0
21:09:38.306 -> 1 ----- 0
21:09:38.353 -> 1 ----- 0
21:09:38.353 -> 3 ----- 0
21:09:38.399 -> 3 ----- 0
21:09:38.446 -> 3 ----- 0
21:09:38.446 -> 3 ----- 0
21:09:38.493 -> 3 ----- 0
21:09:38.493 -> 3 ----- 0
21:09:38.540 -> 3 ----- 0
21:09:38.540 -> 3 ----- 0
21:09:38.587 -> 3 ----- 0
21:09:38.587 -> 3 ----- 0
21:09:38.634 -> 3 ----- 0
21:09:38.634 -> 3 ----- 0
21:09:38.681 -> 3 ----- 0
21:09:38.728 -> 3 ----- 0
21:09:38.728 -> 3 ----- 0
21:09:38.774 -> 3 ----- 0
21:09:38.774 -> 7 ----- 0
21:09:38.821 -> 7 ----- 0
21:09:38.821 -> 7 ----- 0
21:09:38.868 -> 7 ----- 0
21:09:38.868 -> 7 ----- 0
21:09:38.915 -> 7 ----- 0
21:09:38.915 -> 7 ----- 0
21:09:38.962 -> 7 ----- 0
21:09:39.009 -> 7 ----- 0
21:09:39.009 -> 7 ----- 0
21:09:39.056 -> 7 ----- 0
21:09:39.056 -> 7 ----- 0
21:09:39.103 -> 7 ----- 0
21:09:39.103 -> 7 ----- 0
21:09:39.149 -> 7 ----- 0
21:09:39.149 -> 7 ----- 0
21:09:39.196 -> 7 ----- 0
21:09:39.243 -> 15 ----- 0
21:09:39.243 -> 15 ----- 0
21:09:39.290 -> 15 ----- 0
21:09:39.290 -> 15 ----- 0
21:09:39.337 -> 15 ----- 0
21:09:39.337 -> 15 ----- 0
21:09:39.384 -> 15 ----- 0
21:09:39.384 -> 15 ----- 0
21:09:39.431 -> 15 ----- 0
21:09:39.431 -> 15 ----- 0
21:09:39.478 -> 15 ----- 0
21:09:39.524 -> 15 ----- 0
21:09:39.524 -> 15 ----- 0
21:09:39.571 -> 15 ----- 0
21:09:39.571 -> 15 ----- 0
21:09:39.618 -> 15 ----- 0
21:09:39.618 -> 31 ----- 0
21:09:39.665 -> 31 ----- 0
21:09:39.665 -> 31 ----- 0
21:09:39.712 -> 31 ----- 0
21:09:39.712 -> 31 ----- 0
21:09:39.759 -> 31 ----- 0
21:09:39.806 -> 31 ----- 0
21:09:39.806 -> 31 ----- 0
21:09:39.852 -> 31 ----- 0
21:09:39.852 -> 31 ----- 0
21:09:39.899 -> 31 ----- 0
21:09:39.899 -> 31 ----- 0
21:09:39.946 -> 31 ----- 0
21:09:39.946 -> 31 ----- 0
21:09:39.993 -> 31 ----- 0
21:09:39.993 -> 63 ----- 0
21:09:40.040 -> 63 ----- 0
21:09:40.087 -> 63 ----- 0
21:09:40.087 -> 63 ----- 0
21:09:40.134 -> 63 ----- 0
21:09:40.134 -> 63 ----- 0
21:09:40.181 -> 63 ----- 0
21:09:40.181 -> 63 ----- 0
21:09:40.228 -> 63 ----- 0
21:09:40.228 -> 63 ----- 0
21:09:40.274 -> 127 ----- 0
21:09:40.274 -> 127 ----- 0
21:09:40.321 -> 127 ----- 0
21:09:40.368 -> 127 ----- 0
21:09:40.368 -> 127 ----- 0
21:09:40.415 -> 127 ----- 0
21:09:40.415 -> 127 ----- 0
21:09:40.462 -> 127 ----- 0
21:09:40.462 -> 127 ----- 0
21:09:40.509 -> 127 ----- 0
21:09:40.509 -> 127 ----- 0
21:09:40.556 -> 127 ----- 0
21:09:40.602 -> 255 ----- 0
21:09:40.602 -> 255 ----- 0
21:09:40.649 -> 255 ----- 0
21:09:40.649 -> 255 ----- 0
21:09:40.696 -> 255 ----- 0
21:09:40.696 -> 255 ----- 0
21:09:40.743 -> 255 ----- 0
21:09:40.743 -> 255 ----- 0
21:09:40.790 -> 255 ----- 0
21:09:40.790 -> 255 ----- 0
21:09:40.837 -> 255 ----- 0
21:09:40.884 -> 255 ----- 0
21:09:40.884 -> 255 ----- 0
21:09:40.931 -> 255 ----- 0
21:09:40.931 -> 255 ----- 1
21:09:40.977 -> 255 ----- 1
21:09:40.977 -> 255 ----- 1
21:09:41.024 -> 255 ----- 1
21:09:41.024 -> 255 ----- 1
21:09:41.071 -> 255 ----- 1
21:09:41.118 -> 255 ----- 1
21:09:41.118 -> 255 ----- 3
21:09:41.165 -> 255 ----- 3
21:09:41.165 -> 255 ----- 3
21:09:41.212 -> 255 ----- 3
21:09:41.212 -> 255 ----- 3
21:09:41.259 -> 255 ----- 3
21:09:41.259 -> 255 ----- 3
21:09:41.306 -> 255 ----- 3
21:09:41.352 -> 255 ----- 7
21:09:41.352 -> 255 ----- 7
21:09:41.399 -> 255 ----- 7
21:09:41.399 -> 255 ----- 7
21:09:41.446 -> 255 ----- 7
21:09:41.446 -> 255 ----- 7
21:09:41.493 -> 255 ----- 7
21:09:41.493 -> 255 ----- 7
21:09:41.540 -> 255 ----- 7
21:09:41.540 -> 255 ----- 15
21:09:41.587 -> 255 ----- 15
21:09:41.634 -> 255 ----- 15
21:09:41.634 -> 255 ----- 15
21:09:41.681 -> 255 ----- 15
21:09:41.681 -> 255 ----- 15
21:09:41.727 -> 255 ----- 15
21:09:41.727 -> 255 ----- 15
21:09:41.774 -> 255 ----- 31
21:09:41.774 -> 255 ----- 31
21:09:41.821 -> 255 ----- 31
21:09:41.868 -> 255 ----- 31
21:09:41.868 -> 255 ----- 31
21:09:41.915 -> 255 ----- 31
21:09:41.915 -> 255 ----- 31
21:09:41.962 -> 255 ----- 63
21:09:41.962 -> 255 ----- 63
21:09:42.009 -> 255 ----- 127
21:09:42.009 -> 255 ----- 127
21:09:42.056 -> 255 ----- 127

they are the correct decimal figure for the bytes it requires.

hmmm

I suggest to turn off all LEDs by Shiftout 0, before writing the new bits to the shift registers.

Thank you groundFungus (nice name by the way)...
This looks really interesting. I will certainly have a look.
Thank you

void setup(){
  Serial.begin(9600);

}

Huh?

What happened to

void setup(){
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
}

???

ahhhh..... haha... yeah good point.

what did happen to that??

:roll_eyes:
thanks

PaulRB.... you sir are a legend.
It's working nicely now.

Thank you so much.

I am still a little confused by how this line is converting val to bytes.

 if (val > 0) val = (1 << val) - 1;

do you think you could point in the direction of somewhere where I can learn about this type of if(statement) syntax...

Thank you again

You're welcome, and apologies for the missing capitals in lowByte() and highByte(). I was in the middle of cooking dinner!

The "if" is nothing magic. The "<<" is shift left. For example "1 << 13" is the same as 2^13 = 8192. Subtract 1 from that and you get the 8191, which is 0b111111111111 in binary.

I Just had a little look at bitwise operators here: -
https://www.arduino.cc/reference/tr/language/structure/bitwise-operators/bitshiftleft/
and it makes sense now...

I just got a little confused because also... I've always structured if statements with the conditions on one line and then the actions on the line below inside curly brackets.

anyways... I guess every day is a school day isn't it.

Thank you again.
enjoy your dinner
:slightly_smiling_face:

I did, thankyou.

That's a good habit to have. But strictly speaking, you only need the curly brackets when you want to put 2 or more statements that will be executed together depending on the condition being true. Putting those statements on a different line can make it easier to read for us humans, but the C compiler does not care. That isn't true in all languages. Look at a python sketch and you can see that there are no curly brackets, and what you put on a different line, and how you indent it, is vitally important.

I just realised something.

if (val > 0) val = (1 << val) - 1;

can just be

val = (1 << val) - 1;

The if() wasn't needed because 1 << 0 is 1...