Chaining 4-digit displays to 8 or 12 digit display

Hello

I have been wondering if it is possible to chain 4-digit display so you control them over only 3 wires.

Now I have been using 3 digital io-pins / display and with 4 displays it uses 12 digital io-pins.

There seems to be extra holes at the other of the led's pcb and I have been trying to find out if they are for chaining the displays but I have not found anything concrete about the matter.

This is the link to the sellers webside

https://www.aliexpress.com/item/10pcs-4-Bits-0-36-Common-Anode-LED-Display-Board-Digital-Tube-Display-Module-freeshipping/32328885616.html

Yes, I think that is the purpose of the connectors and you should be able to chain 2 or 3 of these displays without problems.

Scion:
I have been wondering if it is possible to chain 4-digit display so you control them over only 3 wires.

It should be. But first, these displays require you to multiplex them in code - how did you find the code since it is not on the website?

Scion:
Now I have been using 3 digital io-pins / display and with 4 displays it uses 12 digital io-pins.

No, it would need six pins for four displays connected in parallel.

Scion:
There seems to be extra holes at the other of the led's PCB and I have been trying to find out if they are for chaining the displays but I have not found anything concrete about the matter.

They certainly should be.

OK, two approaches to this.

Firstly, these displays have no resistors. This in turn has two consequences; one is that the brightness of individual digits or segments changes according to how many digits or segments are lit at the time. The other is that the 74HC595s are being operated beyond their ratings and may degrade over time and fail either progressively or suddenly.

You can connect them without chaining using six pins, two for all the clock and data pins and one for each latch pin or commoned clock and latch pins and four separate data pins. The second way requires you to use different code, the first requires you only to change the four "instances" of the driver code for the appropriate pins.

Or you should be able to chain them, but again, the code needs to be adjusted to suit and it would indeed require just three pins. Where is your code? (Note the instructions for posting code.)

I would consider the better approach to use properly designed modules using MAX7219s such as these:

These are most certainly designed to be chained to just three control pins and do not require multiplexing in your code. And they are (but controllable in software so that they can be if you choose) much brighter.

This is what I have now. An experiment with two arduino nanos. One has DS1307 clock and bme280 sensor. The other has 4 displays and uses pins d2-d13 for those. Pins d0-d1 are for serial connection between the nanos.

The reason for two nanos is that reading the sensor and converting the time and sensor readings to displays format takes so much time that displays blink off when calculating those.

Now the first nano handles clock and sensor reading and for converting the numbers to display format. And the second is only checking for incoming serial data and showing it on displays. Because the time is displayed only in minutes so are the displays also updated only once in a minute. When minute changes in the first nanos clock it will send new display string to the other nano.

What I want, is to free digital io pins from the second nano because now they are all reserved for the displays. I want two pins free so I can change the wired serial connection to bluetooth connection. So I can keep the sensor (and the clock) out on the balcony and the displays in the house.

Code for the display nano is

/*
 * uses 4 displays to show time, temperature, air pressure and humidity
 * program reads display formatted readings from the serial port send here by another nano
 *
 * Scion Riverson 2018	
 */

// 1. display pins
int SCLK_1 = 4;
int RCLK_1 = 3;
int DIO_1 = 2;

// 2. display pins
int SCLK_2 = 7;
int RCLK_2 = 6;
int DIO_2 = 5;

// 3. display pins
int SCLK_3 = 10;
int RCLK_3 = 9;
int DIO_3 = 8;

// 4. display pins
int SCLK_4 = 13;
int RCLK_4 = 12;
int DIO_4 = 11;

// Each port represents one digit in the led display. 
// Ports in the array are in the order as the digits are in the display, from left to right
unsigned char ports[4] = {0b1000, 0b0100, 0b0010, 0b0001};

// Set initial display strings for the displays. 
// Each display shows first it's own ordinal number when powered up
// 1. display's string in led display format
unsigned char luku_1[4] = {0xF9, 0xF9, 0xF9, 0xF9}; // 1111

// 2. display's string in led display format
unsigned char luku_2[4] = {0xA4, 0xA4, 0xA4, 0xA4}; // 2222

// 3. display's string in led display format
unsigned char luku_3[4] = {0xB0, 0xB0, 0xB0, 0xB0}; // 3333

// 4. display's string in led display format
unsigned char luku_4[4] = {0x99, 0x99, 0x99, 0x99}; // 4444

// buffer where to get the readings from the serial port
unsigned char bufStr[16];

void setup() {
  // open serial port
  Serial.begin(9600);

  //initialize 1. displays pins
  pinMode(SCLK_1, OUTPUT);
  pinMode(RCLK_1, OUTPUT);
  pinMode(DIO_1, OUTPUT);

  //initialize 2. displays pins
  pinMode(SCLK_2, OUTPUT);
  pinMode(RCLK_2, OUTPUT);
  pinMode(DIO_2, OUTPUT);

  //initialize 3. displays pins
  pinMode(SCLK_3, OUTPUT);
  pinMode(RCLK_3, OUTPUT);
  pinMode(DIO_3, OUTPUT);

  //initialize 4. displays pins
  pinMode(SCLK_4, OUTPUT);
  pinMode(RCLK_4, OUTPUT);
  pinMode(DIO_4, OUTPUT);

} //setup()

void loop() {
  
  // get readings from the serial port and split retrieved string to display strings
  if (Serial.available() > 0) {
    Serial.readBytes(bufStr, 16);
    for (int i = 0; i < 4; i++) {
    luku_1[i] = bufStr[i];
    }
    for (int i = 4; i < 8; i++) {
    luku_2[i - 4] = bufStr[i];
    }
    for (int i = 8; i < 12; i++) {
    luku_3[i - 8] = bufStr[i];
    }
    for (int i = 12; i < 16; i++) {
    luku_4[i - 12] = bufStr[i];
    }
  }
  // display retrieved strings
  dspStr_1(luku_1);
  dspStr_2(luku_2);
  dspStr_3(luku_3);
  dspStr_4(luku_4);

} //loop()

/*
    1. display routines
*/

// sends a byte to displays controller bit by bit

void send_1(unsigned char X)
{

  for (int i = 8; i >= 1; i--)
  {
    if (X & 0x80)
    {
      digitalWrite(DIO_1, HIGH);
    }
    else
    {
      digitalWrite(DIO_1, LOW);
    }
    X <<= 1;
    digitalWrite(SCLK_1, LOW);
    digitalWrite(SCLK_1, HIGH);
  }
}

// you must send 2 bytes to the led display controller
// first byte for the character to be displayed
// second  byte to choose the port which defines which one of four led digits should show it

void sendDigit_1(unsigned char X, unsigned char port)
{
  send_1(X);
  send_1(port);
  digitalWrite(RCLK_1, LOW);
  digitalWrite(RCLK_1, HIGH);
}

// send led format string to display controller
// this one is to show time so it adds a desimalpoint to the second digit

void dspStr_1(unsigned char[]) {
  luku_1[1] = luku_1[1] - 0x80; //add desimalpoint to second digit
  for (int i = 0; i < 4; i++) {
    sendDigit_1(luku_1[i], ports[i]);
  }
  sendDigit_1(0xFF, 3); //Have to turn the last character off, otherwise it burns brighter then others
}

/*
    2. display routines

    all the same things are here as are in 1. displays routines
    except desimalpoint is in the 3. digit to show temperature with one desimal
*/

void send_2(unsigned char X)
{

  for (int i = 8; i >= 1; i--)
  {
    if (X & 0x80)
    {
      digitalWrite(DIO_2, HIGH);
    }
    else
    {
      digitalWrite(DIO_2, LOW);
    }
    X <<= 1;
    digitalWrite(SCLK_2, LOW);
    digitalWrite(SCLK_2, HIGH);
  }
}

void sendDigit_2(unsigned char X, unsigned char port)
{
  send_2(X);
  send_2(port);
  digitalWrite(RCLK_2, LOW);
  digitalWrite(RCLK_2, HIGH);
}

void dspStr_2(unsigned char[]) {
  luku_2[2] = luku_2[2] - 0x80; //desimalpoint for the temperature
  for (int i = 0; i < 4; i++) {
    sendDigit_2(luku_2[i], ports[i]);
  }
  sendDigit_2(0xFF, 3); //Have to turn the last character off, otherwise it burns brighter then others
}

/*
    3. display routines

    All the same things are here as are in 1. and 2. displays routines
    except there is no desimalpoint. Same goes with the 4. display.
*/

void send_3(unsigned char X)
{

  for (int i = 8; i >= 1; i--)
  {
    if (X & 0x80)
    {
      digitalWrite(DIO_3, HIGH);
    }
    else
    {
      digitalWrite(DIO_3, LOW);
    }
    X <<= 1;
    digitalWrite(SCLK_3, LOW);
    digitalWrite(SCLK_3, HIGH);
  }
}

void sendDigit_3(unsigned char X, unsigned char port)
{
  send_3(X);
  send_3(port);
  digitalWrite(RCLK_3, LOW);
  digitalWrite(RCLK_3, HIGH);
}

void dspStr_3(unsigned char[]) {
  for (int i = 0; i < 4; i++) {
    sendDigit_3(luku_3[i], ports[i]);
  }
  sendDigit_3(0xFF, 3); //Have to turn the last character off, otherwise it burns brighter then others
}

/*
    4. display routines
*/

void send_4(unsigned char X)
{

  for (int i = 8; i >= 1; i--)
  {
    if (X & 0x80)
    {
      digitalWrite(DIO_4, HIGH);
    }
    else
    {
      digitalWrite(DIO_4, LOW);
    }
    X <<= 1;
    digitalWrite(SCLK_4, LOW);
    digitalWrite(SCLK_4, HIGH);
  }
}

void sendDigit_4(unsigned char X, unsigned char port)
{
  send_4(X);
  send_4(port);
  digitalWrite(RCLK_4, LOW);
  digitalWrite(RCLK_4, HIGH);
}

void dspStr_4(unsigned char[]) {
  for (int i = 0; i < 4; i++) {
    sendDigit_4(luku_4[i], ports[i]);
  }
  sendDigit_4(0xFF, 3); //Have to turn the last character off, otherwise it burns brighter then others
}

Most of the essential parts of the code are borrowed from V. Kostarev's TM74HC595Display library.

I'm not a great programming wizard so please don't be too cruel when judging that code.

I just understood that there is an error in my thinking. I can connect that bluetooth module to pins d0-d1 instead of the serial connection.

I have only started to learn about the bluetooth modules and every BT connection I have tried, has been on software serial so I can use normal serial for monitoring and debugging. That practise has blurred my thinking how I can make this work.