3 of my 4 digit 7 segment display are very dim

Hello,

I'm using a 4 digit 7 segment display for a countdown timer to display minutes and seconds.
The program is running as intended, and the hardware is pretty much working as intended except that the first 3 digits are very dim and only the 4th digit is bright. Other than being very dim, the digits are displaying correctly. I'm using a 4-digit 7 segment common cathode display.

I've hooked up pins a~g with a 150 ohm resistor to pins 2~8 on the arduino.
I'm using a 2222a NPN transistors for each of the digits.

  • Emitters connect to GND
  • Bases connect to pins 10~13 on the arduino with a 1k resistor
  • Collector connects to their respective digit pins on the display

I've switched around the pins in all sorts of combinations and played around with the code to make sure it's not a hardware defect, and I can get all the digits to shine brightly (without running the timer correctly). I'm thinking it must be my code and/or a lack of some part.

The idea is to pick a digit by switching it to HIGH and switching the other 3 to LOW, display the number, the repeat.

Any help would be greatly appreciated.

/*

*/
long int time = 1565000;
int startTime;
int minute1;
int minute2;
int second1;
int second2;
int elapsedTime;

int a = 2;
int b = 3;
int c = 4;
int d = 5;
int e = 6;
int f = 7;
int g = 8;
int d1 = 10;
int d2 = 11;
int d3 = 12;
int d4 = 13;


void setup() {
  Serial.begin(9600);
  pinMode(a, OUTPUT);
  pinMode(b, OUTPUT);
  pinMode(c, OUTPUT);
  pinMode(d, OUTPUT);
  pinMode(e, OUTPUT);
  pinMode(f, OUTPUT);
  pinMode(g, OUTPUT);
  pinMode(d1, OUTPUT);
  pinMode(d2, OUTPUT);
  pinMode(d3, OUTPUT);
  pinMode(d4, OUTPUT);
}

void loop() {
    startTime = millis();
  
  do{
    
    elapsedTime = millis() - startTime;
    time = time - elapsedTime;
    
    minute1 = ((time/1000)/60)/10;
    minute2 = ((time/1000)/60)%10;
    second1 = ((time/1000)%60)/10;
    second2 = ((time/1000)%60)%10;
    
    clearLEDs();
    pickDigit(1);
    pickNumber(minute1);
    delayMicroseconds(55);
    
    clearLEDs();
    pickDigit(2);
    pickNumber(minute2);
   // delay(10);
   delayMicroseconds(55);
    
    clearLEDs();
    pickDigit(3);
    pickNumber(second1);
   // delay(10);
   delayMicroseconds(55);
    
    clearLEDs();
    pickDigit(4);
    pickNumber(second2);
    //delay(10);
    delayMicroseconds(55);
    
    
    startTime = millis();
   delay(20);
    
  } while (time>0);
}

void pickDigit(int x) //changes digit
{

 
  switch(x)
  {
  case 1: 
    digitalWrite(d1, HIGH); 
    digitalWrite(d2, LOW);
    digitalWrite(d3, LOW);
    digitalWrite(d4, LOW);
    break;
  case 2: 
    digitalWrite(d1, LOW); 
    digitalWrite(d2, HIGH);
    digitalWrite(d3, LOW);
    digitalWrite(d4, LOW);
    break;
  case 3: 
    digitalWrite(d1, LOW); 
    digitalWrite(d2, LOW);
    digitalWrite(d3, HIGH);
    digitalWrite(d4, LOW); 
    break;
  case 4: 
    digitalWrite(d1, LOW); 
    digitalWrite(d2, LOW);
    digitalWrite(d3, LOW);
    digitalWrite(d4, HIGH); 
    break;
  default:
  digitalWrite(d1, LOW);
  digitalWrite(d2, LOW);
  digitalWrite(d3, LOW);
  digitalWrite(d4, LOW);
  }
}

void pickNumber(int x) //changes value of number
{
  switch(x)
  {
  default: 
    zero(); 
    break;
  case 1: 
    one(); 
    break;
  case 2: 
    two(); 
    break;
  case 3: 
    three(); 
    break;
  case 4: 
    four(); 
    break;
  case 5: 
    five(); 
    break;
  case 6: 
    six(); 
    break;
  case 7: 
    seven(); 
    break;
  case 8: 
    eight(); 
    break;
  case 9: 
    nine(); 
    break;
  }
}


void clearLEDs()
{
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}
 
void zero()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, LOW);
}
 
void one()
{
  digitalWrite(a, LOW);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}
 
void two()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, LOW);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, LOW);
  digitalWrite(g, HIGH);
}
 
void three()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, HIGH);
}
 
void four()
{
  digitalWrite(a, LOW);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}
 
void five()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, LOW);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, LOW);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}
 
void six()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, LOW);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}
 
void seven()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}
 
void eight()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}
 
void nine()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, LOW);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}

The problem seemed to have been as a result of having too short of a delay between the digits. Not exactly sure why, but staying on for a shorter period makes it dimmer, and longer makes it brighter.

The 4th digit basically stayed on for much longer because of the delay after startTime = millis() at the end of the loop.

I increased delayMicroseconds from 55 to 3000. delaying for 5000 does make it brighter, but I started noticing the flickering.
I also moved up the the startTime = millis() to the top so that all 4 digits will stay on for the same duration. Also, it does make more sense for it to be at the top.

Here's the revised code for anyone that it might be helpful for.

 do{
    
    elapsedTime = millis() - startTime;
    time = time - elapsedTime;
    startTime = millis(); //reset start time so that there is elapsed time while executing everything
    
    minute1 = ((time/1000)/60)/10; //calculating each digit
    minute2 = ((time/1000)/60)%10;
    second1 = ((time/1000)%60)/10;
    second2 = ((time/1000)%60)%10;
    
    clearLEDs();
    pickDigit(1);
    pickNumber(minute1);
    delayMicroseconds(3000);
    
    clearLEDs();
    pickNumber(minute2);
   //delay(20);
   delayMicroseconds(3000);
    
    clearLEDs();
    pickDigit(3);
    pickNumber(second1);
   delayMicroseconds(3000);
    
    clearLEDs();
    pickDigit(4);
    pickNumber(second2);
    delayMicroseconds(3000);
    clearLEDs(); 
    
      
    Serial.print(minute1);
    Serial.print(minute2);
    Serial.print(" : ");
    Serial.print(second1);
    Serial.println(second2);
    
  
    
  } while (time>0);

Ah! Yet another enthusiastic head-banger mistaking an Arduino for a display driver. :astonished:

This is an unfortunately disorganised program.

You have a "do" loop within the main loop() which contains delays. Of course, delays are themselves going to be a problem, but after racing through all four digits, you leave the last one showing while you muck around doing something which I cannot figure out.. No wonder the last digit is so bright! :roll_eyes:

Start again. No delays, this is what you use millis() for. Design a loop which displays one digit and only steps to the next when millis() tells you (checking each time you pass through loop()) that 5 ms has passed.

Not exactly sure why, but staying on for a shorter period makes it dimmer, and longer makes it brighter.

What is the mystery?
When you are blinking an LED so fast it looks in all the time, the longer it is on the brighter it looks.
This is because as the time is longer it is able to pump more photons into your retina. The more light you have the brighter it looks. It’s just the way the eye works.

Paul__B:
Start again. No delays, this is what you use millis() for. Design a loop which displays one digit and only steps to the next when millis() tells you (checking each time you pass through loop()) that 5 ms has passed.

Note sure if this is the most efficient way, but I recoded without using delays as you suggested and it's working. Thank you!

void loop() {
    startTime = millis();
    
    
    if((startTime - previousTime >= interval) && (digitalRead(d4) == HIGH)) {
      time = time - (startTime - previousTime);
      previousTime = startTime;
      minute1 = ((time/1000)/60)/10;
      minute2 = ((time/1000)/60)%10;
      second1 = ((time/1000)%60)/10;
      second2 = ((time/1000)%60)%10;
      
      pickDigit(1);
      pickNumber(minute1);
      clearLEDs();
        }
  
    if((startTime - previousTime >= interval) && (digitalRead(d1) == HIGH)) {
      time = time - (startTime - previousTime);
      previousTime = startTime;
      minute1 = ((time/1000)/60)/10;
      minute2 = ((time/1000)/60)%10;
      second1 = ((time/1000)%60)/10;
      second2 = ((time/1000)%60)%10;
      
      pickDigit(2);
      pickNumber(minute2);
      clearLEDs();

        }
        
    if((startTime - previousTime >= interval) && (digitalRead(d2) == HIGH)) {
      time = time - (startTime - previousTime);
      previousTime = startTime;
      minute1 = ((time/1000)/60)/10;
      minute2 = ((time/1000)/60)%10;
      second1 = ((time/1000)%60)/10;
      second2 = ((time/1000)%60)%10;
      
      pickDigit(3);
      pickNumber(second1);
      clearLEDs();

        }
        
    if((startTime - previousTime >= interval) && (digitalRead(d3) == HIGH)) {
      time = time - (startTime - previousTime);
      previousTime = startTime;
      minute1 = ((time/1000)/60)/10;
      minute2 = ((time/1000)/60)%10;
      second1 = ((time/1000)%60)/10;
      second2 = ((time/1000)%60)%10;
      
      pickDigit(4);
      pickNumber(second2);
      clearLEDs();

        }

Note sure if this is the most efficient way,

I am, it’s not.

When you have lots and lots of the same instructions over and over you are doing it wrong. Also it will not work because each digit will light up in a random order because you keep testing if the timeout has expired and if not just repeat this until at some point when time out will have expired and then you light up that digit. A bit like a roulette wheel.

Just have one time out and increment the variable which shows what digit to light up then light it.

When posting your attempt from a suggestion it is expected you will say what the code does, and you should post all the code.

Grumpy_Mike:
I am, it’s not.

When you have lots and lots of the same instructions over and over you are doing it wrong. Also it will not work because each digit will light up in a random order because you keep testing if the timeout has expired and if not just repeat this until at some point when time out will have expired and then you light up that digit. A bit like a roulette wheel.

Just have one time out and increment the variable which shows what digit to light up then light it.

When posting your attempt from a suggestion it is expected you will say what the code does, and you should post all the code.

Thank you for your suggestions! I've done what you recommended and now I only have 1 time out, and I increment through the digits using a for loop. Is this correct approach? It's displaying nicely and evenly bright, but it's a bit dim (maybe around 50~60% brightness). If I add in a small delay in each iteration of the for loop, it does get brighter, but it seems like it defeats the purpose of trying to only use millis to keep track of time.

long int time = 1565000; //start time in ms
unsigned long currentTime; //variables for countdown timer
int timerDigit[4]; // array to store individual timer digits 

int a = 2; // pins for timer 7-segment
int b = 3;
int c = 4;
int d = 5;
int e = 6;
int f = 7;
int g = 8;
int d1 = 10;
int d2 = 11;
int d3 = 12;
int d4 = 13;

unsigned long previousTime = 0; //used to calculate elapsed time
int interval = 5; //interval to check start - previous

void setup() {
  Serial.begin(9600);
  pinMode(a, OUTPUT); //pinModes for 7segment timer
  pinMode(b, OUTPUT);
  pinMode(c, OUTPUT);
  pinMode(d, OUTPUT);
  pinMode(e, OUTPUT);
  pinMode(f, OUTPUT);
  pinMode(g, OUTPUT);
  pinMode(d1, OUTPUT);
  pinMode(d2, OUTPUT);
  pinMode(d3, OUTPUT);
  pinMode(d4, OUTPUT);
}

void loop() {
    currentTime = millis();
        
    if (currentTime - previousTime >= interval) {
      time = time - (currentTime - previousTime); //update countdown timer by subtracting elapsed time
      previousTime = currentTime; //update previous time to current time 
      
      timerDigit[0] = ((time/1000)/60)/10; //calculating each digit of MM:SS individually and storing the values into array
      timerDigit[1] = ((time/1000)/60)%10;
      timerDigit[2] = ((time/1000)%60)/10;
      timerDigit[3] = ((time/1000)%60)%10;
      
      for (int i = 1; i <= 4; i++) { //cycling through each digit to be displayed
        pickDigit(i); //picking digits 1~4
        pickNumber(timerDigit[i-1]); //calling values stored in array for each digit
        clearLEDs(); //clear individual digits for equal brightness
       
        
      }
      
    }
}


void pickDigit(int x) //changes digit
{
 
  switch(x)
  {
  case 1: 
    digitalWrite(d1, HIGH); 
    digitalWrite(d2, LOW);
    digitalWrite(d3, LOW);
    digitalWrite(d4, LOW);
    break;
  case 2: 
    digitalWrite(d1, LOW); 
    digitalWrite(d2, HIGH);
    digitalWrite(d3, LOW);
    digitalWrite(d4, LOW);
    break;
  case 3: 
    digitalWrite(d1, LOW); 
    digitalWrite(d2, LOW);
    digitalWrite(d3, HIGH);
    digitalWrite(d4, LOW); 
    break;
  case 4: 
    digitalWrite(d1, LOW); 
    digitalWrite(d2, LOW);
    digitalWrite(d3, LOW);
    digitalWrite(d4, HIGH); 
    break;
  default:
  digitalWrite(d1, HIGH);
  digitalWrite(d2, HIGH);
  digitalWrite(d3, HIGH);
  digitalWrite(d4, HIGH);
  break;
  }
}

void pickNumber(int x) //changes value of number
{
  switch(x)
  {
  default: 
    zero(); 
    break;
  case 1: 
    one(); 
    break;
  case 2: 
    two(); 
    break;
  case 3: 
    three(); 
    break;
  case 4: 
    four(); 
    break;
  case 5: 
    five(); 
    break;
  case 6: 
    six(); 
    break;
  case 7: 
    seven(); 
    break;
  case 8: 
    eight(); 
    break;
  case 9: 
    nine(); 
    break;
  }
}


void clearLEDs()
{
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
  //digitalWrite(p, LOW);
}
 
void zero()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, LOW);
}
 
void one()
{
  digitalWrite(a, LOW);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}
 
void two()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, LOW);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, LOW);
  digitalWrite(g, HIGH);
}
 
void three()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, HIGH);
}
 
void four()
{
  digitalWrite(a, LOW);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}
 
void five()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, LOW);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, LOW);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}
 
void six()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, LOW);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}
 
void seven()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}
 
void eight()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}
 
void nine()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, LOW);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}

scruffnut:
I've done what you recommended and now I only have 1 time out, and I increment through the digits using a for loop. Is this correct approach?

Ahem. :grin:

No!

Using a "for" loop implies that you are going to cycle through all the digits in the one timeframe which is just the original blunder all over.

You need a counter. Each time though the loop() (you use that loop, not any other), you see if the time has passed and if so, you advance the counter and display that digit. The counter of course needs to loop back either using "%" or zeroing it the moment it increases to four.

Notice that you use an array to store the digits? Our concern is that you need to use arrays to store the pin numbers for the digits and the segments as well. Also the segment bit patterns for the font. Then instead of using a "switch" statement - clever thought that be - you use the array index to switch the digit on after you first turned them all off (using a "for" loop which is OK since it involves no delay at all) and only then - to prevent ghosting - set the new segment pattern.

Paul__B:
You need a counter. Each time though the loop() (you use that loop, not any other), you see if the time has passed and if so, you advance the counter and display that digit. The counter of course needs to loop back either using "%" or zeroing it the moment it increases to four.

Notice that you use an array to store the digits? Our concern is that you need to use arrays to store the pin numbers for the digits and the segments as well. Also the segment bit patterns for the font. Then instead of using a "switch" statement - clever thought that be - you use the array index to switch the digit on after you first turned them all off (using a "for" loop which is OK since it involves no delay at all) and only then - to prevent ghosting - set the new segment pattern.

I hope I'm getting closer. Storing everything into the array definitely does condense the code significantly. The timer is counting down correctly, and the brightness is much better. However there is a slightly noticeable flickering, which I can't seem to get rid of.

The counter will loop 4 times, then reset. Every time it enters,

  1. turns off all the digit pins,
  2. turns off all the segment pins
  3. turns on the digit pin it needs to
  4. then turns on the segment pins by iterating through the arrays.
long int time = 1565000; //start time in ms
unsigned long currentTime; //variables for countdown timer
int timerDigit[4]; // array to store individual timer digits
unsigned long previousTime = 0; //used to calculate elapsed time
int interval = 5; //interval to check start - previous

byte digitPins[] = {10,11,12,13}; //d1,d2,d3,d4
byte segmentPins[] = {2,3,4,5,6,7,8}; //abcdefg

const byte pickNumber[10][7] = {
  { 1,1,1,1,1,1,0 } , // 0 
{ 0,1,1,0,0,0,0 }, // 1 
{ 1,1,0,1,1,0,1 }, // 2 
{ 1,1,1,1,0,0,1 }, // 3 
{ 0,1,1,0,0,1,1 }, // 4 
{ 1,0,1,1,0,1,1 }, // 5 
{ 1,0,1,1,1,1,1 }, // 6
{ 1,1,1,0,0,0,0 }, // 7 
{ 1,1,1,1,1,1,1 }, // 8 
{ 1,1,1,0,0,1,1 },  // 9 
}; 

int n = 0; //counter for timer loop


void setup()
{
  Serial.begin(9600);
  for (int i = 0; i < sizeof(segmentPins); i++){
    pinMode(segmentPins[i], OUTPUT);
  }
  for (int i = 0; i < sizeof(digitPins); i++) {
  	pinMode(digitPins[i], OUTPUT);
  }
}

void loop()
{
  currentTime = millis();
        
    if ((currentTime - previousTime >= interval) && (time > 0)) {
      time = time - (currentTime - previousTime); //update countdown timer by subtracting elapsed time
      previousTime = currentTime; //update previous time to current time
	  
      timerDigit[0] = ((time/1000)/60)/10; //calculating each digit of MM:SS individually and storing the values into array
      timerDigit[1] = ((time/1000)/60)%10;
      timerDigit[2] = ((time/1000)%60)/10;
      timerDigit[3] = ((time/1000)%60)%10;
      
        for (int i = 0; i < sizeof(digitPins); i++){ //turning off all digit pins
        	digitalWrite(digitPins[i], LOW); 
        }
     
        
        for (int i = 0; i< sizeof(segmentPins); i++){ //turns off all the segment pins
          digitalWrite(segmentPins[i], LOW);
        }
         
        
        digitalWrite(digitPins[n], HIGH); //select digit to turn on
        
        for(int i = 0; i < sizeof(segmentPins); i++){ //iterating through segment pins to turn on/off
            digitalWrite(segmentPins[i], pickNumber[timerDigit[n]][i]); //turns each segment on/off . timerDigit[n] selects the number in pickNumber array. 
        }

      if(n == 3){ //reset counter after iterating through 4 digits
          n = -1;}
      
      n++;
    }
  	
}

The flickering seems to have been due to a 5ms interval being too long. Setting it to 1ms seems to have resolved the issue.

OK, doing well, but you misunderstood my instructions. :grinning:

Paul__B:
You use the array index to switch the digit on after you first turned them all off (using a "for" loop which is OK since it involves no delay at all) and only then - to prevent ghosting - set the new segment pattern.

Which is to say:

  • Turn all digits off
  • Set the new segment pattern
  • Then turn the new digit on.Note: n = (++n) % 4;

or n = (n + 1) % 4;

Not sure why it would still flicker as 5 ms should be absolutely fine - 50 scans per second - but haven't completely analysed the code. Try 3 ms?

I'm not sure at what frequency the flicker or shimmer goes away, but if you say that's 60 Hz, then for four digits you would need to refresh every 4.2mS. So if 5 doesn't work, try stepping it down one mS at a time until it's steady. Shouldn't need to go to 1. But it probably would work at less than 60 Hz, so I too am a bit surprised 5mS doesn't work.

And I guess I'll give my suggestion too on the code. You don't have to turn off all the digits. You just have to turn off the current one, which will be the only one that's on.

ShermanP:
You don't have to turn off all the digits. You just have to turn off the current one, which will be the only one that's on.

That is of course true.

However, as this code is presently written, when you start the update cycle, you are using the index of the new digit so to turn off the previous one, you have to figure out which one that is. There are three ways of doing that. One is to take the current index and reverse the incrementing process, including the foldback function. A second is to have a second, copy variable made before you incremented it while the third is to perform the increment after turning off the previous digit.

While all three are perfectly valid, simply turning off all digits to start with is in may ways, easier and ensures correct initialisation on the first pass or if the process is for any reason, later re-started. :grinning:

Paul__B:
That is of course true.

However, as this code is presently written, when you start the update cycle, you are using the index of the new digit so to turn off the previous one, you have to figure out which one that is. There are three ways of doing that. One is to take the current index and reverse the incrementing process, including the foldback function. A second is to have a second, copy variable made before you incremented it while the third is to perform the increment after turning off the previous digit.

While all three are perfectly valid, simply turning off all digits to start with is in may ways, easier and ensures correct initialisation on the first pass or if the process is for any reason, later re-started. :grinning:

I'll take door #3, Monty.

Paul__B:
OK, doing well, but you misunderstood my instructions. :grinning: Which is to say:

  • Turn all digits off
  • Set the new segment pattern
  • Then turn the new digit on.Note: n = (++n) % 4;

or n = (n + 1) % 4;

Not sure why it would still flicker as 5 ms should be absolutely fine - 50 scans per second - but haven't completely analysed the code. Try 3 ms?

I've done as you suggested and now turn all digits off, set the new pattern, then turn on the correct digit. Everything's working! Thank you.

ShermanP:
I'm not sure at what frequency the flicker or shimmer goes away, but if you say that's 60 Hz, then for four digits you would need to refresh every 4.2mS. So if 5 doesn't work, try stepping it down one mS at a time until it's steady. Shouldn't need to go to 1. But it probably would work at less than 60 Hz, so I too am a bit surprised 5mS doesn't work.

It has an almost unnoticeable flicker at 3ms. I don't notice it at 2ms. Out of curiosity, is there a reason for trying to set it at the largest possible interval? Why choose a 2ms over a 1ms interval?

long int time = 655000; //start time in ms
unsigned long currentTime; //variables for countdown timer
int timerDigit[4]; // array to store individual timer digits
unsigned long previousTime; //used to calculate elapsed time
int interval = 2; //interval to check start - previous
int blinkInterval = 1000; //interval for timer blink when time=0


byte digitPins[] = {10,11,12,13}; //d1,d2,d3,d4
byte segmentPins[] = {2,3,4,5,6,7,8}; //abcdefg

const byte pickNumber[10][7] = {
{ 1,1,1,1,1,1,0 }, // 0 
{ 0,1,1,0,0,0,0 }, // 1 
{ 1,1,0,1,1,0,1 }, // 2 
{ 1,1,1,1,0,0,1 }, // 3 
{ 0,1,1,0,0,1,1 }, // 4 
{ 1,0,1,1,0,1,1 }, // 5 
{ 1,0,1,1,1,1,1 }, // 6
{ 1,1,1,0,0,0,0 }, // 7 
{ 1,1,1,1,1,1,1 }, // 8 
{ 1,1,1,0,0,1,1 }, // 9 
}; 

int n = 0; //counter for timer loop
int m = 0; //counter for blinking timer when time=0
bool startButtonPressed = false;
bool previousTimeLogged = false;


void setup()
{
  Serial.begin(9600);
  for (int i = 0; i < sizeof(segmentPins); i++){ //sets segment pinMode
    pinMode(segmentPins[i], OUTPUT);
  }
  for (int i = 0; i < sizeof(digitPins); i++) { //sets digit pinModes
  	pinMode(digitPins[i], OUTPUT);
  }
  pinMode(22, INPUT_PULLUP); //for start button 
}

void loop()
{
  
  if(digitalRead(22) == LOW){ //waiting for start button to be pressed. to be replaced with hall effect 
    startButtonPressed = true;
  }
  
  if(startButtonPressed && !previousTimeLogged){ //once start button is pressed, it will log the previous time and not enter this if again
    previousTime = millis();
    previousTimeLogged = true;
  }
  
  currentTime = millis();
    
    /* Core timer function */
    if ((currentTime - previousTime >= interval) && (time > 0) && (previousTimeLogged)) {
      time = time - (currentTime - previousTime); //update countdown timer by subtracting elapsed time
      previousTime = currentTime; //update previous time to current time
	  
      timerDigit[0] = ((time/1000)/60)/10; //calculating each digit of MM:SS individually and storing the values into array
      timerDigit[1] = ((time/1000)/60)%10;
      timerDigit[2] = ((time/1000)%60)/10;
      timerDigit[3] = ((time/1000)%60)%10;
      
        for (int i = 0; i < sizeof(digitPins); i++){ //turning off all digit pins
        	digitalWrite(digitPins[i], LOW); 
        }

        for(int i = 0; i < sizeof(segmentPins); i++){ //iterating through segment pins to turn on/off
            digitalWrite(segmentPins[i], pickNumber[timerDigit[n]][i]); //turns each segment on/off . timerDigit[n] selects the number in pickNumber array. 
        }
        
        digitalWrite(digitPins[n], HIGH); //select digit to turn on
      
      if(time <= 0) { //changing all digits to display 0 when time = 0
        
        for(int i = 0; i < sizeof(segmentPins); i++){ //iterating through segment pins to select 0
          digitalWrite(segmentPins[i], pickNumber[0][i]);  
        }
        
        for (int i = 0; i < sizeof(digitPins); i++){ //turning on all digits
        	digitalWrite(digitPins[i], HIGH);
        }

      }
      n = (++n) % 4;
    }
    
    /* Blinker once time = 0
    */
    if((currentTime - previousTime >= blinkInterval) &&(time <= 0)){ //blink in 1sec interval when time = 0
      previousTime = currentTime; //update previous time to current time
      
      for (int i = 0; i < sizeof(digitPins); i++){ //turning on/off all digit pins
          	digitalWrite(digitPins[i], m);
      }
      m = (++m) % 2;
    }
  
}

scruffnut:
It has an almost unnoticeable flicker at 3ms. I don't notice it at 2ms. Out of curiosity, is there a reason for trying to set it at the largest possible interval? Why choose a 2ms over a 1ms interval?

It may not matter in this case, but in general if your loop is doing other things besides refreshing the display, you would spend the least amount of time refreshing that still works, and then if the brightness wasn't quite right you could adjust the value of the resistors.

I'm still puzzled by the need to go down to 2ms to eliminate the flicker.

ShermanP:
It may not matter in this case, but in general if your loop is doing other things besides refreshing the display, you would spend the least amount of time refreshing that still works, and then if the brightness wasn't quite right you could adjust the value of the resistors.

I'm still puzzled by the need to go down to 2ms to eliminate the flicker.

I swapped out the segment display with another one and though there is a very feint flicker at 4~5ms, it's not as bad as before. There is no flicker with the new one at 3ms, whereas the previous one had a slightly noticeable one.

So I'm guessing it's ultimately due to a faulty/crappy segment display.

So I'm guessing it's ultimately due to a faulty/crappy segment display.

I don’t see how that could be.

Yeah, the only thing a different display should effect is brightness. Well, maybe someone will have an explanation.

By the way, have you said which Arduino you're using?

Hrm...weird. At least it working. Thank you all for you help!

ShermanP:
Yeah, the only thing a different display should effect is brightness. Well, maybe someone will have an explanation.

By the way, have you said which Arduino you're using?

I started off with a uno, but am currently using a mega as I'm planning on adding more stuff into the timer.