Shift register limitations???

Hello all,

I am working on a project and I am intending to display live data/string data from a software program using shift registers. Currently I am running two registers but I have come what I have perceived as a limitation but I don't know if its a limitation of my knowledge or of the actual component. Shift register limitation questions:

  1. Can I display continuous independant live data on two separate end points through two linked shift registers at the same time? E.g. Have live data/string pushing out to one end point (LEDs) and a different live data/string pushing out to another end point (segment display) while linking the shift registers (only to save pins).

  2. Are there certain digital pins that a shift register has to use and or in a particular order? Or, can I assign any 3 digital pins as long as I state them as would be expected at the start of the sketch?

I can and have created a sketch to isolate each end point so they display test data but its a step by step output rather than independent data running each at their own wish.

Help please and thank you.

There are two ways of running shift registers.

One is to use the SPI hardware which is often recommended as being faster - generally quite irrelevant for a visual display. This uses particular pins for the clock and data and there is a library function, SPI.transfer() to support it.

The alternative is to "bit-bang" any pins you like to output the data and clock it, again there is a library function, shiftOut() if you do not fancy DIY.

In either case, you can use successive calls to the shifting function to ripple out multiples of 8 bits into cascaded shift registers. It is only when you strobe the latch pin of your shift registers - using any Arduino pin you choose - that they will update with the aggregate data shifted in.

Paul__B:
This uses particular pins for the clock and data and there is a library function, shiftOut() to support it.

No, its SPI.transfer()

Paul__B:
The alternative is to "bit-bang" any pins you like to output the data and clock it.

That is shiftOut()

JamesRobbie:
I can and have created a sketch to isolate each end point so they display test data but its a step by step output rather than independent data running each at their own wish.

I don't understand what you mean by "it is a step by step output".

One way to do what (I think) you want is to declare an array in your sketch holding a byte for each shift register. Then any part of your sketch can update the appropriate array element, then call a function which re-sends the entire array using SPI.transfer() or shiftOut() and finally trigger the latch pins on the registers to load the new data into their output buffers.

Paul

PaulRB:
No, its SPI.transfer()

Clearly I have never used it. :astonished:

Either, actually. :grinning:

6:13 This uses particular pins for the clock and data and there is a library function, shiftOut() to support it.
7:08 This uses particular pins for the clock and data and there is a library function, SPI.transfer() to support it.

Now how did this happen :wink:

LarryD:
Now how did this happen :wink:

Well, because Paul__B corrected his error. Its the sensible thing to do, otherwise at a later date someone might come along and read his original post, not notice the later corrections, and get confused as a result. I have made similar corrections to my posts in the past when I have posted something in error.

Maybe this would have been better.
This uses particular pins for the clock and data and there is a library function, shiftOut() SPI.transfer() to support it.

  1. Can I display continuous independant live data on two separate end points through two linked shift registers at the same time?

Not at the same time but so quickly one after the other that it looks like it is the same time.

can I assign any 3 digital pins as long as I state them as would be expected at the start of the sketch?

Yes if you use the shift out but not for the SPI method. But using the SPI pins you can drive two shift registers.

I can and have created a sketch to isolate each end point so they display test data but its a step by step output rather than independent data running each at their own wish.

Yes

PaulRB:
Well, because Paul__B corrected his error. Its the sensible thing to do, otherwise at a later date someone might come along and read his original post, not notice the later corrections, and get confused as a result. I have made similar corrections to my posts in the past when I have posted something in error.

Yes, I "Corected as advised by PaulRB" it.

Oops! :roll_eyes:

(I am not going to go back and correct the correction ...)

Thanks all for the help and advice. Following on from what everybody has said, I have managed to run 2 x 10 LED arrays and 1 x segment display individually of one register each using different Arduino pins and stating at the start of the sketch latchPinA, latchPinB etc. Seems to do the job for now.

In follow on from this, I dont understand how/if I can display a changing string of data via one shift out command...

The code I am copying from and attempting to change is:

if (gear == 0) 
        			    module.setDisplayToString("r", 0, 0);
                                else if (gear == 1)
                                    module.setDisplayToString("n", 0, 0);
                                else
                                    module.setDisplayToString(String(gear - 1, DEC), 0, 0);

which leaves me wanting to display this string shiftOut(dataPin, clockPin, MSBFIRST, XXXGEARSTRINGXXX);

Is somebody able to help me convert the code and suggest how i point the actual data value to strings?

Struggling with this shift register business... :sob:

Putting out a string variable to a shift register makes little sense. In fact it shows how mixed up you are.

A string is a sequence of bytes that have an ASCII interpretation as an alpha / numeric message.
A shift register outputs 8 binary bits, you could only ever get one character of a string to a shift register, and then what are you going to do with that?

James, we can't make much sense of what you are wanting to do. Can you post a schematic diagram please, showing your shift registers and leds/displays? Hand drawn on paper and scanned, or take pic on your phone, will be fine. Also draw an example of what you want to see on your displays and how it would change. Include a description in layman's terms of what the purpose of the circuit is.

Sorry all for being vague but I am trying to hide my inexperience and lack of understanding.

Project:
To display live telemetry data from the PC game iRacing Simulator. This software has an API which people have tapped into and have windows coding (C#/C++) that is pushing requested data to the Arduino. I have working C# coding and I am trying to call and display the data through the Arduino to a bunch of LED's and a single segment display.

There are numerous similar projects around but due to accessibility of parts and my lack of patience for waiting to order from oversea's, I have attempted to manipulate existing projects.

For my project, I have got two sets of 8 LED's (mirroring) running off the 1st shift register and a single segment display running off the 2nd shift register. The first register and LED's are to display the live RPM values/string and the 2nd register and segment display is displaying what gear the vehicle is in.

This is a project somebody has completed and shared for the world but is using I/O expanders. But this what my project is based on. I was intending to user shift registers because they were available at my local store.
http://fergotech.net/diy-dashboard/

Schematic is based off Arduino Shift Out tutorial:

I can display output on the LED's and segment display by inputting random numbers etc but I am struggling how to output continuous changing data that is being called from the windows coding/game API.

Thanks James, that's how this thread should have started. Now post the Arduino code you have so far (using code tags) and we can advise how to run your shift registers in series.

PaulRB:
Thanks James, that's how this thread should have started. Now post the Arduino code you have so far (using code tags) and we can advise how to run your shift registers in series.

There is plenty of information that isn't required in the sketch for this help request but its where I'm up to at the moment. I have proven both concepts work in the fact I can output dummy data.

This is the first concept using two shift registers link/in series:

int latchPin = 8;
int clockPin = 12;
int dataPin = 11;

byte REVERSE = 17;
byte NEUTRAL = 81;
byte ONE = 72;
byte TWO = 61;
byte THREE = 109;
byte FOUR = 75;
byte FIVE = 103;
byte SIX = 119;
byte SEVEN = 76;

byte gear, spd, rpm_h, rpm_l, shift, engine, SessionLapsRemain_h, SessionLapsRemain_l, Position, WaterTemp, OilPress; 
int fuel;

word rpm;
word laps;

void setup() {     
  pinMode(8, OUTPUT);  
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);

Serial.begin(38400);

}

void loop() {
  
if (Serial.available() > 0) {
		if (Serial.available() > 9) {
			if (Serial.read() == 255) {
				gear = Serial.read();
				spd = Serial.read();
				rpm_h = Serial.read();
				rpm_l = Serial.read();
				fuel = Serial.read();
                                shift = Serial.read();
				engine = Serial.read();
                                SessionLapsRemain_h = Serial.read();
                                SessionLapsRemain_l = Serial.read();
                                Position = Serial.read();
                                WaterTemp = Serial.read();
                                OilPress = Serial.read();
                                
				rpm = (rpm_h << 8) | rpm_l;
                                laps = (SessionLapsRemain_h << 8) | SessionLapsRemain_l;
			}
		}
	} 

digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, ***GEAR INDICATOR***);    // Gear indicator output to segment display
shiftOut(dataPin, clockPin, MSBFIRST, ***RPM LEDS***);    // RPM output on LEDs
digitalWrite(latchPin, HIGH);

}

This is the second concept using two shift registers independant of each other:

int latchPinA = 5;  //shift register A pin 12
int clockPinA = 6;  //shift register A pin 11
int dataPinA = 4;  //shift register A pin 14

int latchPinB = 8;  //shift register B pin 12
int clockPinB = 12;  //shift register B pin 11
int dataPinB = 11;  //shift register B pin 14

byte REVERSE = 17;
byte NEUTRAL = 81;
byte ONE = 72;
byte TWO = 61;
byte THREE = 109;
byte FOUR = 75;
byte FIVE = 103;
byte SIX = 119;
byte SEVEN = 76;

byte gear, spd, rpm_h, rpm_l, shift, engine, SessionLapsRemain_h, SessionLapsRemain_l, Position, WaterTemp, OilPress; 
int fuel;

word rpm;
word laps;

void setup() {     
  pinMode(latchPinA, OUTPUT);  
  pinMode(clockPinA, OUTPUT);
  pinMode(dataPinA, OUTPUT);
  pinMode(latchPinB, OUTPUT);
  pinMode(clockPinB, OUTPUT);
  pinMode(dataPinB, OUTPUT);

Serial.begin(38400);

}

void loop() {

if (Serial.available() > 0) {
		if (Serial.available() > 9) {
			if (Serial.read() == 255) {
				gear = Serial.read();
				spd = Serial.read();
				rpm_h = Serial.read();
				rpm_l = Serial.read();
				fuel = Serial.read();
                                shift = Serial.read();
				engine = Serial.read();
                                SessionLapsRemain_h = Serial.read();
                                SessionLapsRemain_l = Serial.read();
                                Position = Serial.read();
                                WaterTemp = Serial.read();
                                OilPress = Serial.read();
                                
				rpm = (rpm_h << 8) | rpm_l;
                                laps = (SessionLapsRemain_h << 8) | SessionLapsRemain_l;
			}
		}
	} 


digitalWrite(latchPinA, LOW);
shiftOut(dataPinA, clockPinA, MSBFIRST, ***RPM LEDS***);    // RPM output on LEDs
digitalWrite(latchPinA, HIGH);

digitalWrite(latchPinB, LOW);
shiftOut(dataPinB, clockPinB, MSBFIRST, ***GEAR INDICATOR***);   // Gear indicator output to segment display
digitalWrite(latchPinB, HIGH);

}

Clearly neither of those will compile. Do you have one that you have managed to get running on the Arduino yet?

EDIT: wait I think I understand. You have been putting fixed values in place of "GEAR INDICATOR" and "RPM LEDS" and running that - the 'test data' you were talking about.

First impressions of your sketch:

if (Serial.available() > 0) {
		if (Serial.available() > 9) {

If there are more than 9 bytes/characters of serial data avilable, there must be more than zero, so no point doing that first check!

Why 9? The data packet seems to be 13 bytes long: a value of 255 followed by 12 bytes of telemetry. Is that right? If so, you should be checking for 13 bytes.

Also that initial 255 byte check isn't foolproof - one of the other values might genuinely contain a 255 value (such as one of the "_l" fields) and this could throw the whole thing off the rails.

Do you have a link to any description of the data format that the game hack sends?

See if this has helped:

int latchPin = 8;
int clockPin = 12;
int dataPin = 11;

const byte gearPattern[9] = {
  17,  //REVERSE
  81,  //NEUTRAL 
  72,  //ONE
  61,  //TWO
  109, //THREE
  75,  //FOUR
  103, //FIVE
  119, //SIX
  76   //SEVEN
};

byte gear, spd, rpm_h, rpm_l, shift, engine, SessionLapsRemain_h, SessionLapsRemain_l, Position, WaterTemp, OilPress; 
int fuel;

word rpm;
word laps;

void setup() {     
  pinMode(8, OUTPUT);  
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);

  Serial.begin(38400);

}

void loop() {
  if (Serial.available() > 9) {
    if (Serial.read() == 255) {
      gear = Serial.read();
      spd = Serial.read();
      rpm_h = Serial.read();
      rpm_l = Serial.read();
      fuel = Serial.read();
      shift = Serial.read();
      engine = Serial.read();
      SessionLapsRemain_h = Serial.read();
      SessionLapsRemain_l = Serial.read();
      Position = Serial.read();
      WaterTemp = Serial.read();
      OilPress = Serial.read();

      rpm = (rpm_h << 8) | rpm_l;
      laps = (SessionLapsRemain_h << 8) | SessionLapsRemain_l;
      
      byte rpmLedCount = map(rpm, 0, 15000, 0, 8);
      byte rpmPattern = bit(rpmLedCount) - 1;

      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, gearPattern[gear]);    // Gear indicator output to segment display
      shiftOut(dataPin, clockPin, MSBFIRST, rpmPattern);    // RPM output on LEDs
      digitalWrite(latchPin, HIGH);
    }
  }
}

PaulRB:
EDIT: wait I think I understand. You have been putting fixed values in place of "GEAR INDICATOR" and "RPM LEDS" and running that - the 'test data' you were talking about.

That's correct, I just inserted that text so you could see where I had been inputting fake data. I was sending random number values to the RPM LED's and sending "REVERSE", "ONE", "TWO" etc to the segment display. Sorry, should have been more clear with that.

PaulRB:
First impressions of your sketch:

if (Serial.available() > 0) {

if (Serial.available() > 9) {



If there are more than 9 bytes/characters of serial data avilable, there must be more than zero, so no point doing that first check!

Why 9? The data packet seems to be 13 bytes long: a value of 255 followed by 12 bytes of telemetry. Is that right? If so, you should be checking for 13 bytes.

This is a left over/incorrect value from some code I had originally copied that serial read group from. I agree, it should be 13 and in another version of the sketch, I had 13 instead of 9 like the sketch I quoted from.

I apologise for these two mistakes which have added to the confusion.

I will upload your revised sketch later tonight and give it a test then report back. I really, REALLY appreciate the help, time and advice given.

PaulRB:
See if this has helped:

int latchPin = 8;

int clockPin = 12;
int dataPin = 11;

const byte gearPattern[9] = {
  17,  //REVERSE
  81,  //NEUTRAL
  72,  //ONE
  61,  //TWO
  109, //THREE
  75,  //FOUR
  103, //FIVE
  119, //SIX
  76  //SEVEN
};

byte gear, spd, rpm_h, rpm_l, shift, engine, SessionLapsRemain_h, SessionLapsRemain_l, Position, WaterTemp, OilPress;
int fuel;

word rpm;
word laps;

void setup() {   
  pinMode(8, OUTPUT); 
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);

Serial.begin(38400);

}

void loop() {
  if (Serial.available() > 9) {
    if (Serial.read() == 255) {
      gear = Serial.read();
      spd = Serial.read();
      rpm_h = Serial.read();
      rpm_l = Serial.read();
      fuel = Serial.read();
      shift = Serial.read();
      engine = Serial.read();
      SessionLapsRemain_h = Serial.read();
      SessionLapsRemain_l = Serial.read();
      Position = Serial.read();
      WaterTemp = Serial.read();
      OilPress = Serial.read();

rpm = (rpm_h << 8) | rpm_l;
      laps = (SessionLapsRemain_h << 8) | SessionLapsRemain_l;
     
      byte rpmLedCount = map(rpm, 0, 15000, 0, 8);
      byte rpmPattern = bit(rpmLedCount) - 1;

digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, gearPattern[gear]);    // Gear indicator output to segment display
      shiftOut(dataPin, clockPin, MSBFIRST, rpmPattern);    // RPM output on LEDs
      digitalWrite(latchPin, HIGH);
    }
  }
}

Magic, magic MAGIC!!! Thank you so very, very much for your help, patience and advice. It is working and working a treat. Thanks again.

It has highlighted what I think is a C# problem that I have to work on but it proves the Arduino code is working. When the C# is in debug, Arduino works as expected yet when it runs normally, the Arduino has no output but this forum isnt for C#/windows coding!

So, so chuffed! That much closer to the finished project!

Glad to help. But what's important to me is: do you understand the changes I made? Feel free to ask any questions. (I'm quite surprised it worked so well without alot of further tweaking.)

Not sure what to suggest for your C#/debug problem. You need to capture the serial output somehow, with & without debug, and compare the two.