Display (4 digits 7 seg.) : Different brightness of digits, Problem in the Code

Hey Arduino-Crew,

I need some urgent help for a project.
We built a device that detects empty beer cups and shows the number on a display.
This is our project page if you want to know more: Garbage Bar Arco do Cego

This is the sensor we use:

Thats the Display we use:

The problem that we have is, that the last digit of the 4 is much brighter than the other ones. We are pretty sure that the problem is related to the code and is not a hardware problem.
This is the first time for me writing a code for an arduino so I apologize if its too messy or too long.I shortend it a little, the whole code is attached.
I think that the problem is in the switch statement in the pickDigit function. We tried changing it and made the default case related to another digit and then that one would be the brightest.
If you just set all digits to HIGH in the pickdigit function, the display shows 4 times the same digit.
I am gonna attach some pictures, so you see what I mean.

We would be really grateful if anyone could help us!
We are launching tomorrow (even if we don't get the displays perfect), so if you are in Lisbon, come by and have a beer with us :wink:

Thanks a lot!
Mona

Here is the code:

#include <EEPROM.h>
///LEFT////
//segments
int a = 11;
int b = 7;
int c = 4;
int d = 3;
int e = 13;
int f = 10;
int g = 5;
//digitos
int d1 = 12;
int d2 = 9;
int d3 = 8;
int d4 = 6;

//EEPROM
int ncups_left;

int b1=0;
int b2=1;


//Sensors
int ls = 40; //left sensor pin

int l_sensorCounter = 0;   // counter for the left sensor
int l_sensorState = 0;         // current state of the left sensor
int l_lastsensorState = 0;     // previous state of the left sensor



void setup()
{
  Serial.begin(9600);
  ncups_left = 256*EEPROM.read(b1)+EEPROM.read(b2);

  ///LEFT SIDE///
  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);
  pinMode(ls,INPUT); //SENSOR

  
 
}

void loop()
{
////////////////////Left Hole/////////////////// 
l_sensorState = digitalRead(ls);
// compare the sensorState to its previous state
  if (l_sensorState != l_lastsensorState) {
    // if the state has changed, increment the counter
    if (l_sensorState == HIGH) {
      // if the current state is HIGH then the sensor
      // went from off to on:
       l_sensorCounter++;
       ncups_left++;    

    } else {
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state,
  //for next time through the loop
  l_lastsensorState = l_sensorState;
  //ncups_left=l_sensorCounter;
  //Serial.println(ncups_left);

  //EEPROM - stuff
  //left hole
  int val1 = ncups_left / 256;
  int val2 = ncups_left % 256;
  EEPROM.write(b1, val1);
  EEPROM.write(b2, val2);

  clearLEDs();
  pickDigit(1);
  pickNumber((ncups_left/1000)%10);
  
  clearLEDs();
  pickDigit(2);
  pickNumber((ncups_left/100)%10);
  
  clearLEDs();
  pickDigit(3);
  pickNumber((ncups_left/10)%10);
  
  clearLEDs();
  pickDigit(4);
  pickNumber((ncups_left)%10);

 
}  
  void pickDigit(int x)
{

  
  digitalWrite(d1, LOW);
  digitalWrite(d2, LOW);
  digitalWrite(d3, LOW);
  digitalWrite(d4, LOW);
  
  switch(x)
  {
    case 1: 
    digitalWrite(d1, HIGH); 
    break;
    
    case 2: 
    digitalWrite(d2, HIGH); 
    break;
    
    case 3: 
    digitalWrite(d3, HIGH); 
    break;
    
    default: 
    digitalWrite(d4, HIGH); 
    break;
  }
  }
void pickNumber(int x)
{
  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, HIGH);
  digitalWrite(b, HIGH);
  digitalWrite(c, HIGH);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}

void zero()
{
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, HIGH);
}

void one()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}

void two()
{
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, HIGH);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, HIGH);
  digitalWrite(g, LOW);
}

void three()
{
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, LOW);
}

void four()
{
  digitalWrite(a, HIGH);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}

void five()
{
  digitalWrite(a, LOW);
  digitalWrite(b, HIGH);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, HIGH);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}

void six()
{
  digitalWrite(a, LOW);
  digitalWrite(b, HIGH);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}

void seven()
{
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
}

void eight()
{
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}

void nine()
{
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, HIGH);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
}

meea_testex_grupo7.ino (9.35 KB)

After pick digit 4, your code goes back to the of loop, does all that stuff, maybe has a delay (50) in there, then blast thru 3 digits, and leaves digit 4 up while it does al the stuff in loop again - so 4 looks brigher.
You can add a little delay to the other digits, maybe a mS or 2, see if that evens the brightness out.
Or use blink without delay to ensure they are all on the same amount of time, and while you want for that time to pass you can be checking the quantities for updates.

Thank you for your quick answer!
What you say seems logic to me, but I am still not sure how to change the code. Where in the code do I add the delay to the other digits? Just after calling pickDigit(1) I put delay(2) ? Or do I put the delay in the definition of pickDigit ?
And what do you mean by blink?

"Just after calling pickDigit(1) I put delay(2) ?" Yes, try like this, see if if helps

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

Sketch:Basic:Blink, somewhere in there. May depend what version of IDE you have.

Okay, the delay of 2 ms didn't change anything.
If I want to try your other suggestion with blink I do something like this: ?

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

But then they will only be on really short, won't they?
Or what do you mean by "and while you want for that time to pass you can be checking the quantities for updates."?
Sorry for understanding so slowly...

Try inserting one more clearLEDs(); just before the } at the end of your loop().
That should fix it, I think.

Mona, i think i may have spotted a serious mistake in your sketch. The EEPROM memory in the Arduino has a limited life of around 10 or 100 thousand writes. After that it will start to fail and the only fix would be to replace the Arduino or its atmega chip.

The mistake is to update the EEPROM every time in loop(), even when the value of ncups_left has not changed. You should move those lines of code to just after the line that increases the value of ncups_left. That way the EEPROM will only get written to when the value has changed.

Paul

Hey everyone,

thank you so much for your answers!
The advice of odometer saying to put a clearLEDS() in the end of the loop helped to make the brightness even in every digit. But they were a little dim still...

Then I tried what PaulRB said.
Actually we kept getting an error the last days saying:
avrdude: verification error, first mismatch at byte 0x0000
0x14 != 0x26
avrdude: verification error; content mismatch
So I think it means that we already ruined the first byte of our eeprom.
I changed the bytes that the eeprom is using and put the code inside the if-loop as Paul suggested.
And surprise, it even made the digits brighter, perfectly bright actually!

I still get the same error. Should I be concerned with it? And if we get the same error for the bytes that I am using now, should I just use the next ones, until we used them all? (We are using an Arduino Mega, so we have some time... ) Or will this not only harm the bytes I am using, but the whole Arduino?

The problem is understanding the nature of the "loop()".

It is rather tempting to think of it as a sequence of tasks that you complete one after the other.

This is not how real computing works, and using microcontrollers is real computing. :grinning:

You cannot afford to wait for things, just as you cannot wait for things in real life. If I order a part on eBay, I do not wait at the post office until it arrives; that would be totally absurd.

Well, computing is actually just like that. It is called "polling", just as in real life. I have many parcels ordered from eBay, but even if I know the sequence in which I ordered them, that is not necessarily the sequence in which they arrive, so what do I do?

Of course, I go to the post-box and "poll" - that is, see if there is anything there. If there is, then I collect it and take it back to work, often to put aside till I have time to open it and do something with it.

If there is nothing to collect, I do not wait at the post-box - I again go back to work and do something else. And of course, what I do, depends substantially on what time it is.

So it is with computing.

In your loop(), you check things including the clock (a function called "millis()"). If it is time to do something - such as moving on to the next digit - then you do that but if not, then you check all of your other tasks - in order - such as checking your sensors. But again, you only ever do what you can without delay(). If you need to wait a certain time - such as a debounce - then you set a time for it and within the never-stopping loop(), keep checking the time until it has elapsed, then do what is necessary.

Here is some example code. It de-bounces a button to toggle a LED, and flashes two other LEDs independently. It contains the elements you require - de-bouncing of an input event, and regular timely execution of a process such as you need (by adapting your code) to strobe from one display digit to the next.

// Blink without "delay()" - multi!

const int led1Pin =  13;    // LED pin number
const int led2Pin =  10;
const int led3Pin =  11;
const int button1 =  4;
int led1State = LOW;        // initialise the LED
int led2State = LOW;
int led3State = LOW;
char bstate1 = 0;
unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long bcount1 = 0; // button debounce timer.  Replicate as necessary.

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check 
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far, 
    if (button == HIGH) return false; // Nothing happening!
    else { 
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far, 
    if (button == LOW) return false; // Nothing happening!
    else { 
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else 
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else 
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
  pinMode(led2Pin, OUTPUT);      
  pinMode(led3Pin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
}

void loop() {
  // Toggle LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW; 
    } 
    digitalWrite(led1Pin, led1State);
  } 

  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count2, 300UL )) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW; 
    } 
    digitalWrite(led2Pin, led2State);
  } 

  if (timeout(&count3, 77UL )) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW; 
    } 
    digitalWrite(led3Pin, led3State);
  } 
}

As to your EEPROM, it is as you have been advised before - you only ever write to the EEPROM if the value you wish to write is different and also clearly stable.

mon-na:
Actually we kept getting an error the last days saying:
avrdude: verification error, first mismatch at byte 0x0000
0x14 != 0x26
avrdude: verification error; content mismatch
So I think it means that we already ruined the first byte of our eeprom.

I'm not sure if that is what the error means. Can anyone confirm this for Mona?

mon-na:
I changed the bytes that the eeprom is using and put the code inside the if-loop as Paul suggested.
And surprise, it even made the digits brighter, perfectly bright actually!

Not sure why that would have fixed your brightness problem. My suggestion was not intended to fix the brightness problem, just avoid wearing out the EEPROM.

mon-na:
if we get the same error for the bytes that I am using now, should I just use the next ones, until we used them all? (We are using an Arduino Mega, so we have some time... ) Or will this not only harm the bytes I am using, but the whole Arduino?

The EEPROM memory is divided into a number of pages. It is the page that wears out. To figure out which byte of EEPROM to move to, you need to know the page size for a mega. You could just try using the last EEPROM byte instead of the first.

mon-na:
Actually we kept getting an error the last days saying:
avrdude: verification error, first mismatch at byte 0x0000
0x14 != 0x26
avrdude: verification error; content mismatch

What has that to do with the EEPROM?

That is an uploading error.