Bluetooth signal for two digit 7-segment display only goes through half the multiplexing loop

Hello everyone, beginner here, I have a problem. I'm trying to use a 2-digit 7-segment display to display, say "A1", when receiving the message '1' from my phone, sent with the Serial Bluetooth Monitor app. I tried this with both switch case and if, and they both didn't solve it.

When I give the signal '1', it only displays 'A'. I then give it another signal of '1', and it displays '1' (the other part of "A1").

What can I do so that, upon receiving a singular '1' message, the display goes through the complete multiplexing loop? Thank you in advance!

The program is so written, so that, upon receiving '2', it would display "A2" and, with '3', "A3".

Below is the code:

#include <BluetoothSerial.h>

#define A 18

#define B 19

#define C 0

#define D 2

#define E 15

#define F 17

#define G 16

#define DP 4

#define DIG1 22

#define DIG2 23

unsigned long timp = millis();

long interval=5;

int dig;

BluetoothSerial ESP_BT;

byte state1=LOW;

byte state2=LOW;

byte state3=LOW;

byte state4=LOW;

char inc = '\0';

void display7(int nr)
{
  if(nr==1)
  {if(millis()-timp>=interval)
        {
        if(dig==1)
        {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, HIGH);
        dig=2;  
        aprindeCh1(dig);
        }
        
        else
        {
        digitalWrite(DIG1, HIGH);
        digitalWrite(DIG2, LOW);
        dig=1;
        aprindeCh1(dig);
        }
        timp=millis();
        }}


      if(nr==2)
      {
        if(millis()-timp>=interval)
        {
        if(dig==1)
        {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, HIGH);
        dig=2;  
        aprindeCh2(dig);
        }
        else
        {
        digitalWrite(DIG1, HIGH);
        digitalWrite(DIG2, LOW);
        dig=1;
        aprindeCh2(dig);
        }
        timp=millis();
      }
    }


    if(nr==3)
      {
        if(millis()-timp>=interval)
        {if(dig==1)
        {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, HIGH);
        dig=2;  
        aprindeCh2(dig);
        
        }
        else
        {
        digitalWrite(DIG1, HIGH);
        digitalWrite(DIG2, LOW);
        dig=1;
        aprindeCh3(dig);
        
        }
        timp=millis();
        
        }


    }
}

void setup() 
{
  Serial.begin(115200); 
  pinMode(A,OUTPUT);
  pinMode(B,OUTPUT);
  pinMode(C,OUTPUT);
  pinMode(D,OUTPUT);
  pinMode(E,OUTPUT);
  pinMode(F,OUTPUT);
  pinMode(G,OUTPUT);
  pinMode(DP,OUTPUT);
  pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT);
  dig=1;
  ESP_BT.begin("ESP32_T3");
  Serial.println("Ready to pair");
}

void loop() 

{  if(ESP_BT.available())
  {
    inc=ESP_BT.read();
    Serial.println("Paired");
    Serial.write(inc);
   
   switch(inc)
      {  
        case '1':
        display7(1);
        break;

        case '2':
        display7(2);
        break;

        case '3':
        display7(3);
        break;

        default:
        Serial.println("Invalid code");
        break;
      }
  }
1 Like

But I don't think it does what you think it does.

Can you please share a schematic of the circuit you've built as well as clear photos showing how all parts are connected, and also some information about the 7-segment displays you're using? Please also share the full code of your program; I have a strong feeling that what you've posted is incomplete.

Keep in mind that with bare 7-segment displays (without e.g. a TM1637 driver chip attached to the LED units), you need to switch each individual segment to make a character. Maybe that's what your "aprinde" functions are supposed to do - but they're not included in your post, so IDK.

Since this is defined even before setup(), I wonder what actual value it'll be assigned.

What do you intend with this?

This seems a bit superfluous since the next thing you do is do 'dig 2'; the if-statement and the whole business with storing the 'dig' variable seems unnecessary.

Are DIG1 and DIG2 common anode/cathode pins of your segment displays? If so, do you realize that in order to display a character on a 7-segment display, you need to keep the LEDs permanently on (or at least modulate them very rapidly)? Is this where the business surrounding the 'interval' stems from? Is it indeed supposed to be a multiplexer of some sort? If so, how long are the characters supposed to show on the display?

Perhaps it would help if you could make a simple flowchart of what your code is supposed to do.

1 Like

It is indeed not the full program and I messed up by trying to write only what I thought were "important" parts.

I use a common cathode two digit 7 segment display, I'll post the pinout in a screenshot.
Indeed, the `if(millis()-timp>=interval)' was a multiplexing loop. As you can see below, I set the interval at 5 ms. I will also post a circuit schematic and a flowchart later.

Thank you very much for your response!

Below is the full code:

#include <BluetoothSerial.h>
#define A 18
#define B 19
#define C 0
#define D 2
#define E 15
#define F 17
#define G 16
#define DP 4
#define DIG1 22
#define DIG2 23
unsigned long timp = millis();
long interval=5;
int dig;
BluetoothSerial ESP_BT;
char inc = '\0';

void display7(int nr)
{
  if(nr==1)
  {if(millis()-timp>=interval)
        {
        if(dig==1)
        {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, HIGH);
        dig=2;  
        aprindeCh1(dig);
        }
        
        else
        {
        digitalWrite(DIG1, HIGH);
        digitalWrite(DIG2, LOW);
        dig=1;
        aprindeCh1(dig);
        }
        timp=millis();
        }}


      if(nr==2)
      {
        if(millis()-timp>=interval)
        {
        if(dig==1)
        {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, HIGH);
        dig=2;  
        aprindeCh2(dig);
        }
        else
        {
        digitalWrite(DIG1, HIGH);
        digitalWrite(DIG2, LOW);
        dig=1;
        aprindeCh2(dig);
        }
        timp=millis();
      }
    }


    if(nr==3)
      {
        if(millis()-timp>=interval)
        {if(dig==1)
        {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, HIGH);
        dig=2;  
        aprindeCh2(dig);
        
        }
        else
        {
        digitalWrite(DIG1, HIGH);
        digitalWrite(DIG2, LOW);
        dig=1;
        aprindeCh3(dig);
        
        }
        timp=millis();
        
        }


    }
}



void clearSegments() {
    digitalWrite(A, LOW);
    digitalWrite(B, LOW);
    digitalWrite(C, LOW);
    digitalWrite(D, LOW);
    digitalWrite(E, LOW);
    digitalWrite(F, LOW);
    digitalWrite(G, LOW);
    digitalWrite(DP, LOW);
}
void aprindeCh1(byte dig)
{ clearSegments();
  if(dig==2)
  {
    digitalWrite(E, HIGH);
    digitalWrite(F, HIGH);
    digitalWrite(A, HIGH);
    digitalWrite(G, HIGH);
    digitalWrite(B, HIGH);
    digitalWrite(C, HIGH);
    digitalWrite(D, LOW);
    digitalWrite(DP, LOW);
    
  }
  if(dig==1)
  {
    digitalWrite(E, LOW);
    digitalWrite(F, LOW);
    digitalWrite(A, LOW);
    digitalWrite(B, HIGH);
    digitalWrite(C, HIGH);
    digitalWrite(D, LOW);
    digitalWrite(G, LOW);
    digitalWrite(DP, LOW);
    
  }
}
void aprindeCh2(byte dig)
{ clearSegments();
  if(dig==2)
  {
    digitalWrite(E, HIGH);
    digitalWrite(F, HIGH);
    digitalWrite(A, HIGH);
    digitalWrite(G, HIGH);
    digitalWrite(B, HIGH);
    digitalWrite(C, HIGH);
    digitalWrite(D, LOW);
    digitalWrite(DP, LOW);
    
  }
  if(dig==1)
  {
    digitalWrite(E, HIGH);
    digitalWrite(F, LOW);
    digitalWrite(A, HIGH);
    digitalWrite(B, HIGH);
    digitalWrite(C, LOW);
    digitalWrite(D, HIGH);
    digitalWrite(G, HIGH);
    digitalWrite(DP, LOW);
    
  }



}
void aprindeCh3(byte dig)
{ clearSegments();
  if(dig==2)
  {
    digitalWrite(E, HIGH);
    digitalWrite(F, HIGH);
    digitalWrite(A, HIGH);
    digitalWrite(G, HIGH);
    digitalWrite(B, HIGH);
    digitalWrite(C, HIGH);
    digitalWrite(D, LOW);
    digitalWrite(DP, LOW);
    
  }
  if(dig==1)
  {
    digitalWrite(E, LOW);
    digitalWrite(F, LOW);
    digitalWrite(A, HIGH);
    digitalWrite(B, HIGH);
    digitalWrite(C, HIGH);
    digitalWrite(D, HIGH);
    digitalWrite(G, HIGH);
    digitalWrite(DP, LOW);
    
  }


}
void setup() 
{
  Serial.begin(115200); 
  pinMode(Led1, OUTPUT);
  pinMode(Led2, OUTPUT);
  pinMode(Led3, OUTPUT);
  pinMode(Led4, OUTPUT);
  pinMode(A,OUTPUT);
  pinMode(B,OUTPUT);
  pinMode(C,OUTPUT);
  pinMode(D,OUTPUT);
  pinMode(E,OUTPUT);
  pinMode(F,OUTPUT);
  pinMode(G,OUTPUT);
  pinMode(DP,OUTPUT);
  pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT);
  dig=1;
  ESP_BT.begin("ESP32_T3");
  Serial.println("Ready to pair");
}

void loop() 

{  if(ESP_BT.available())
  {
    inc=ESP_BT.read();
    Serial.println("Paired");
    Serial.write(inc);
   
   switch(inc)
      {  
        case '1':
        display7(1);
        break;

        case '2':
        display7(2);
        break;

        case '3':
        display7(3);
        break;

        default:
        Serial.println("Cod invalid");
        break;
      }
  } 
 } 


This is the pinout for the 7 segment display

Screenshot 2024-05-18 213102
This is the circuit schematic.

Ok, I see; thanks for clarifying.

In terms of code structure, I think I'd change the setup a little.

Make a character map that has an entry for each character and that describes the pattern that needs to be displayed. You can iterate through this character map with a for-loop. This will cut back drastically on the redundancy of your code, reducing the endless blocks of digitalWrites to a single digitalWrite operation (but that's called for a different pin and with the appropriate HIGH/LOW value depending on which character is displayed).

If you indeed need to use some kind of multiplexing approach, then perhaps using a timer interrupt is a more suitable way to do this. Have the timer interrupt trigger every e.g. 10ms-20ms or so (50-100Hz refresh rate). Maintain a boolean that records which digit is being displayed; toggle it every time the interrupt service routine (ISR) runs. Store the digits in a small array so that the ISR always 'knows' which character needs to be displayed on which digit.

The above can run separately from the rest of your program. In the regular loop() you can wait for the serial/BT input and write the required input to the two-character array that the ISR uses to drive the 7-segment LEDs. Ideally you pause the timer-interrupt for the display routine as BT data comes in so that your data transfer process doesn't get interrupted (although you probably can get away without bothering about it).

By decoupling the display routine and the data receiver routine, and cutting back the redundancy, your code will become more robust, easier to maintain and most importantly, less confusing to debug.

Suggested reading would be on the following topics:

  • Interrupts and ISR's
  • Timers
  • Arrays
  • For-loops
  • At a conceptual level: model-view-controller architecture
1 Like

Hi,

Where are the current limit resistors?

Tom.. :smiley: :+1: :coffee: :australia:

2 Likes

Where are the current limit resistors?

I added these, thanks for pointing it out. They were there irl but missing in the schematic :joy:

Also, for anyone else having the same problem, I solved it. It consists of a while loop, with scanning for a new signal and breaking when the signal differs from the first one.

The reset() function simply turns off all the segments, to prevent any weird logic stuff from happening.

I also changed it from receiving chars with BT to receiving strings, which I think makes it more useful for anyone else who has a similar problem.

Below is the code:

void loop() 

{   
  if (ESP_BT.available()) 
  {
  String sig = ESP_BT.readStringUntil('\n');
      sig.trim(); 

      if (sig != currentGame) 
      {
        reset(); 
        currentGame = sig;
      }
      Serial.println("Paired");
      while (ESP_BT.available()==0) 
      {
        if (sig == "Joc 1") 
        {
          display7(1);
        } 
        else if (sig == "Joc 2") 
        {
          display7(2);
        } 
        else if (sig == "Joc 3") 
        {
          display7(3);
        }
        if (ESP_BT.available()) 
        {
          sig = ESP_BT.readStringUntil('\n');
          sig.trim();
          if (sig != currentGame) 
           {
             reset(); 
             currentGame = sig;
             break;
           }
        }
      }
   }

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.