[SOLVED]Can't code for Robotdyn 7 segments, 6 Digits, 74hc595

Some time ago i bought a 7 segment display, with 6 digits, controlled by 2 74hc595 chips.
I looked for some examples on the internet how to hook up 7segs displays, but that didn't make it clear. then i checked a few libraries and still couldn't make it work.

Link to the shop: https://robotdyn.com/catalog/segment/6_digit_led_display_tube_7_segments_74hc595/

If somebody could help me understand how to code my arduino or give a sample how to display useful things on this display, i would appreciate it very much.

[SOLVED] UPDATE:

So, with some hints and advice, I managed to display useful information on this display.
This piece of code is not nearly in a good shape, and there are definitely things to improve (which I may improve, if I have time). But still, this is enough to get things going.

// ST_CP = SCK
// SH_CP = RCK
// SDI   = DIO
// Common anode
#define DS 10
#define STCP 11
#define SHCP 12
#define SPEED 500
boolean numbersDef[10][8] = 
{
  {1,1,1,1,1,1,0}, //zero
  {0,1,1,0,0,0,0}, //one
  {1,1,0,1,1,0,1}, //two
  {1,1,1,1,0,0,1}, //three
  {0,1,1,0,0,1,1}, //four
  {1,0,1,1,0,1,1}, //five
  {1,0,1,1,1,1,1}, //six
  {1,1,1,0,0,0,0}, //seven
  {1,1,1,1,1,1,1}, //eight
  {1,1,1,1,0,1,1}  //nine
};

boolean digitsTable[8][8] =
{
  {0,0,0,0,1,0,0,0}, // first digit
  {0,0,0,0,0,1,0,0}, // second
  {0,0,0,0,0,0,1,0}, // third
  {1,0,0,0,0,0,0,0}, // forth
  {0,1,0,0,0,0,0,0}, // fifth
  {0,0,1,0,0,0,0,0}  // sixth  
};

void setup() {
  pinMode(DS, OUTPUT);
  pinMode(STCP, OUTPUT);
  pinMode(SHCP, OUTPUT);
  digitalWrite(DS, LOW);
  digitalWrite(STCP, LOW);
  digitalWrite(SHCP, LOW);
}

boolean display_buffer[16];
void prepareDisplayBuffer(int number, int digit_order, boolean showDot)
{
  for(int index=7; index>=0; index--)
  {
    display_buffer[index] = digitsTable[digit_order-1][index];
  }
  for(int index=14; index>=8; index--)
  {
    display_buffer[index] = !numbersDef[number-1][index]; //because logic is sanity, right?
  }
  if(showDot == true)
    display_buffer[15] = 0;
  else
    display_buffer[15] = 1;
}

void writeDigit(int number, int order, bool showDot = false)
{
  prepareDisplayBuffer(number, order, showDot);
  digitalWrite(SHCP, LOW);
  for(int i=15; i>=0; i--)
  {
      digitalWrite(STCP, LOW);
      digitalWrite(DS, display_buffer[i]); //output LOW - enable segments, HIGH - disable segments
      digitalWrite(STCP, HIGH);
   }
  digitalWrite(SHCP, HIGH);
}

void loop() {
  writeDigit(0, 1);
  writeDigit(2, 2, true);
  writeDigit(3, 3);
  writeDigit(4, 4, true);
  writeDigit(5, 5);
  writeDigit(6, 6);
}

Code can be easily adjusted to output letters and other things. For me - digits from 0 to 9 is enough.
I would like to express my gratitude to the guys who helped me. And I hope somebody may find this post useful.

Schematic:
https://robotdyn.com/upload/PHOTO/0G-00004891==Mod-LED-Display-6D-74HC595/DOCS/Schematic==0G-00004891==Mod-LED-Display-6D-74HC595.pdf
That looks like it's setup to drive one segment at a time across the 42 segments of the 6 digits. You'll need to write a routine test if a segment is to be on - if yes, shiftout a high on one shift register and a low on the other.
Wait 1mS, then repeat for the next segment.
Can't tell if these are Common Anode or Common Cathode parts, you'll have to experiment a little to decide if the SEGx pins on U1 need to be high or low to turn on a specific digit. (and why are there 8 of them when there are only 6 digits?)

To me, it looks like it is set up to drive one digit at a time, although the diagram is not very clear. U2 has the current limiting resistors, so that handles the seven segments and decimal point. U1 must therefore drive (sink or source) the commons and is used to select the current one of the 6 digits to be displayed.
Edit.
It looks like the diagram is actually also intended to support two 4 digit displays. Confusingly also, they say seg (segment) when we would understand digit.
Depending on the power rating of the displays and the rating of the shift registers, it may be wiser to multiplex the displays at a granularity of less than 1 digit at a time, so that at any one moment, maybe only a maximum of 4 or even 2 segments would be lit. In the worst case, only one. If the part number is visible on the displays, refer to the data sheet.

The posts above gave me some ideas in which way to look and there is some progress on this display. I fiddled with another example I found for using 74HC595.
Because I have two of those, which extends each other, and there is a single serial input pin, i thought - if one chip is 8 bits, then 2 chips is 16 bit, right ?

I wrote a test function to experiments with register bits. And this is what i found out.
An extended 74HC595, indeed, has double the bits. 16 in this case.
Also, fiddling and the schematic confirms this, first 8 bits (first chip) are used to switch entire digits off or on. This design and wiring can hold up to two 4-digits displays, and this is two by 3-digits. Therefor, 4th and 8th bit doesn't do anything, they are responsible for missing digits.
Last 8 bits (second chip, with current limiting resistors) are used to light the individual segments of the digits.

This is my testing sketch. Now that the principle is somewhat clear, everything has to be structured.

// ST_CP = SCK
// SH_CP = RCK
// SDI     =DS = DIO
#define DS 10
#define STCP 11
#define SHCP 12
#define SPEED 0
boolean registers[16];

void setup() {
  pinMode(DS, OUTPUT);
  pinMode(STCP, OUTPUT);
  pinMode(SHCP, OUTPUT);
  digitalWrite(DS, LOW);
  digitalWrite(STCP, LOW);
  digitalWrite(SHCP, LOW);
  for (int i=0; i<16; i++)
  {
    registers[i] = LOW;
  }
}

void writeReg()
{
  digitalWrite(SHCP, LOW);

  for(int i=16; i>=0; i--)
  {
    
      if((i==0)||(i==1)||(i==2)) // choose digits to disable (0-7 - digits)
      {
        registers[i] = HIGH; //disable unwanted digits 
      }
      digitalWrite(STCP, LOW);
      if((i==8)||(i==13)||(i==14)||(i==10)||(i==11)||(i==12)) //choose wanted segments
      {    
        digitalWrite(DS, registers[i]); // will output LOW
      }
      else
      {
        digitalWrite(DS, !registers[i]); //disable all unwanted segments
      }
      digitalWrite(STCP, HIGH);
   }

  digitalWrite(SHCP, HIGH);
}

void loop() {
  writeReg();
  delay(SPEED);
}

The result output of the function, is "666" on first 3 digits. Screenshot of the sketch and result.

From what I can work out looking at your code, these are common anode devices.
To switch a digit on, you set it to 1. To switch a segment on , you set it to 0.

Yes. Since the two shift registers are daisy-chained together, you write out groups of 16 bits

The next step for you is to display a number consisting of 2 (or more) different digits.
Then you really start using multiplexing.

To extend you example of working with an array, it would look like this :

                    1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- - - - - - - - - - - - - - - -
0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1    // bits 0 - 7 turn on digit 1 only. bits 8 - 15 show a 6
0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1    // bits 0 - 7 turn on digit 2 only. bits 8 - 15 show a 3

In a loop, you'd write out line 1 first, then line two and it should display 63.
In your example, you are going off the end of the array with this: " for(int i=16; i>=0; i-- )"
because element 16 doesn't exist. The array subscripts are 0 to 15.

6v6gt:
From what I can work out looking at your code, these are common anode devices.
To switch a digit on, you set it to 1. To switch a segment on , you set it to 0.

I'm not quite sure about that. In my example i set the array values to HIGH to "disable" the digit. But in the next "if' statement, these array values falls under the "else" statement, and are outputted inverted. So you actually output a LOW on pin, to disable a digit, and a HIGH to enable it.
And for individual segments, you output LOW to enable, and HIGH to disable. Hope that makes sense. It is difficult to keep up with all these things in my head :smiley:

But indeed, printing something on the display will require to output things in a loop, digit by digit.
I may need to write an array of arrays of bits corresponding to numbers 0-9, and a function to parse the arrays, and send serial data to the display. I will fiddle with that when a have some time, and post here if i get anywhere.
Also, outputting numbers line by line of segments doesn't seem possible, because if i enable a segment, it will light up on every active digit. And if I set to light up all the digits, and all the segments at the same time, some segments are not as bright as others. Probably because of current limiting resistors.
If i get something wrong, please, correct me.

I see no difference between your first paragraph and my statement that a 1 (HIGH) enables a DIGIT and a 0 (LOW) enables a SEGMENT. The digits are set in bits 0 to 7 and the segments in bits 8 to 15 of the 16 bit data steam which you send to the shift registers,

The following is 100% true and the reason why, on a multiplexed display as you have, only one digit can be active at any one time:

Also, outputting numbers line by line of segments doesn't seem possible, because if i enable a segment, it will light up on every active digit.

The trick is to use a loop, displaying first digit one, then a few milliseconds later digit 2 etc. etc. through to digit 6. Then repeat endlessly. The human eye sees all six digits lit simultaneously and a high speed camera would see only one. The example I gave shows how this would be done for the first two digits.
Do a google search for "multiplexed display arduino with shift register" and maybe you find some ready usable code examples

6v6gt:
I see no difference between your first paragraph and my statement that a 1 (HIGH) enables a DIGIT and a 0 (LOW) enables a SEGMENT. The digits are set in bits 0 to 7 and the segments in bits 8 to 15 of the 16 bit data steam which you send to the shift registers,

I'm sorry, all this mess of bits is driving me crazy.

6v6gt:
Do a google search for "multiplexed display arduino with shift register" and maybe you find some ready usable code examples

I did searched for that before, I couldn't make anything work. Now that I got a grip, I will write my own pieces of code, while i have it in my head. So far, I created 2 bit tables: one for defining numbers 0-9, other one for defining active digit position.

boolean numbers[10][8] = 
{
  {1,1,1,1,1,1,0}, //zero
  {0,1,1,0,0,0,0}, //one
  {1,1,0,1,1,0,1}, //two
  {1,1,1,1,0,0,1}, //three
  {0,1,1,0,0,1,1}, //four
  {1,0,1,1,0,1,1}, //five
  {1,0,1,1,1,1,1}, //six
  {1,1,1,0,0,0,0}, //seven
  {1,1,1,1,1,1,1}, //eight
  {1,1,1,1,0,1,1}  //nine
};

boolean digitsTable[8][8] =
{
  {0,0,0,0,1,0,0,0}, // first digit
  {0,0,0,0,0,1,0,0}, // second
  {0,0,0,0,0,0,1,0}, // third
  {1,0,0,0,0,0,0,0}, // forth
  {0,1,0,0,0,0,0,0}, // fifth
  {0,0,1,0,0,0,0,0}  // sixth  
};

I'm writing a function, that will look like this:

void prepareDisplayBuffer(int number, int digit_order, boolean showDot)

that will create a 16bit data buffer, to be streamed to the display.
And another function - will call the one above, parse the buffer and do the streaming itself.

It looks like you've got the idea and can adapt if necessary after checking by displaying sample numbers.

I believe that in your array numbers[] you have to invert the ones and zeros and you have to add also the decimal point as the last segment (and set to 1 to turn it off).

Incidentally, it is usual to use bytes (8 bits) and bit manipulation instead of arrays for this purpose, but you can regard that as something for a later optimisation once you get it all working.

6v6gt:
I believe that in your array numbers[] you have to invert the ones and zeros and you have to add also the decimal point as the last segment (and set to 1 to turn it off).

I will keep them as it is in those arrays for now for the sake of logic, own sanity and peace of mind :D. I will invert everything that needs to be inverted on the fly, when updating the buffer.

6v6gt:
Incidentally, it is usual to use bytes (8 bits) and bit manipulation instead of arrays for this purpose, but you can regard that as something for a later optimisation once you get it all working.

I will definitely look into that at a latter point in the project, as i want to get things work for now. :slight_smile:
And a great Thank you for your input on this and keeping up with me! Couldn't come to this without your help!

[SOLVED] Updated original post.