4-digit 7-segment LED counter

Hi

I need following modifications in the code below which I came across while googling:

a) Counting to be done with a Push-Button connected to pin A0.

b) The trailing zeros to be removed (e.g. if the number is 567, the display should be 567 instead of 0567).

I shall be grateful for the help.

/*
 * Author: Rafael Zaleski
 *
 * The selector pin (common anode for each digit) changes every 5ms to display 
 * different numbers using the common pins 'a' to 'g' in the display. 
 *
 * Don't forget that you have to change the code if your display is common cathode
 */

int a = 6, b = 7, c = 8, d = 9, e = 10, f = 11, g = 12, dp = 13; //Display pins

int d1 = 5, d2 = 4, d3 = 3, d4 = 2; //Common pins

int time = 500; //speed of the counter in ms
int buttonPin = 14;

void setup() {
  int i = 1;
  for(; i<13; i++)
    pinMode(i, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
    
}

void loop() {
  offd(d1);
  offd(d2);
  offd(d3);
  offd(d4);
  
  int i, j;
    
  //The counter
  for(i = 0; i<10000; i++) 
  {
    for(j = 0; j <= (time/20); j++) 
    {
      ond(d1);
      num(i%10);
      delay(5);
      offd(d1);
      
      ond(d2);
      num(i/10 - 10*(i/100));
      delay(5);
      offd(d2);
      
      ond(d3);
      num(i/100 - 10*(i/1000));
      delay(5);
      offd(d3);
      
      ond(d4);
      num(i/1000);
      delay(5);
      offd(d4);   
          
    }    

  } 
  
}

void on(int i) {
  digitalWrite(i, LOW);
}

void off(int i){
 digitalWrite(i, HIGH); 
}

void ond(int i) {
  digitalWrite(i, HIGH);
}

void offd(int i){
 digitalWrite(i, LOW); 
}

void num(int n) {
 
 if(n < 0)
  n = 0; 
  
 switch(n) {
 
   case 0:
     on(a);
     on(b);
     on(c);
     on(d);
     on(e);
     on(f);
     off(g);
     break;
   case 1:
     off(a);
     on(b);
     on(c);
     off(d);
     off(e);
     off(f);
     off(g);
     break;
   case 2:
     on(a);
     on(b);
     off(c);
     on(d);
     on(e);
     off(f);
     on(g);
     break;
   case 3:
     on(a);
     on(b);
     on(c);
     on(d);
     off(e);
     off(f);
     on(g);
     break;
   case 4:
     off(a);
     on(b);
     on(c);
     off(d);
     off(e);
     on(f);
     on(g);
     break;
   case 5:
     on(a);
     off(b);
     on(c);
     on(d);
     off(e);
     on(f);
     on(g);
     break;
   case 6:
     on(a);
     off(b);
     on(c);
     on(d);
     on(e);
     on(f);
     on(g);
     break;
   case 7:
     on(a);
     on(b);
     on(c);
     off(d);
     off(e);
     off(f);
     off(g);
     break;
   case 8:
     on(a);
     on(b);
     on(c);
     on(d);
     on(e);
     on(f);
     on(g);
     break;
   case 9:
     on(a);
     on(b);
     on(c);
     on(d);
     off(e);
     on(f);
     on(g);
     break;
 
   
 }
 
  
}

If you do not want to learn to code, try posting in Gigs and Collaborations.

Perehama:
If you do not want to learn to code, try posting in Gigs and Collaborations.

I am sorry, if my post gave some indication that I simply wanted a modified code.
Frankly speaking, I have been working on this code and a few other since 2 days but I could not get it working for my need. May be I am missing some important point which I could not trace.

abuhafss:
I am sorry, if my post gave some indication that I simply wanted a modified code.
Frankly speaking, I have been working on this code and a few other since 2 days but I could not get it working for my need. May be I am missing some important point which I could not trace.

Googling code and copying and pasting without understanding it is a start in the wrong place. I would rather help you write your own code than help you fix someone else's work. I google code too, and it's not a bad place to start, but I only adopt what I can understand. Let's start over. Tell me a little about your project and what you are making, what your background is and what prompted you to search for this code. Tell me why you thought it would be good to use for your project. That will give the context to the code that you have that I need to be able to help you answer your question.

Perehama:
Googling code and copying and pasting without understanding it is a start in the wrong place. I would rather help you write your own code than help you fix someone else's work. I google code too, and it's not a bad place to start, but I only adopt what I can understand. Let's start over. Tell me a little about your project and what you are making, what your background is and what prompted you to search for this code. Tell me why you thought it would be good to use for your project. That will give the context to the code that you have that I need to be able to help you answer your question.

Thanks for positive response.
I plan to use a pair of IR LED tx/rx and Arduino Counter as counting facility in my production unit.

As far as the codes are concerned, I have understood almost all the codes. The easiest approach is using the SevSeg library but, I am just stuck figuring out how to hold the display and wait for the button push (which would actually be a HIGH signal from the receiving IR LED).

Electronics is my hobby, I have some decent experience. I am good at programming but my experience with Arduino and other microcontrollers is very quite limited.

I worked on the code in my spare time last night to get my head around it. I've tackled the leading (not trailing) zeros. I've got the button down, but in order to put it where it needs to go, I need to understand what you want. To me, the word "counter" refers to counting units cardinally (1, 2, 3, 4 etc. to 9999). I make a distinction between counter and timer in that "timer" refers to counting units of time as it elapses (incrementing from zero or decrementing from a start value). What the code is now is a timer. I need to remove all the delays and restructure the counter loop arguments in order to add the push-button, but that will look different if the push button is a start/stop button vs if it is incrementing the count by 1. I will post the modified code when I am done and explain how I got from here to there. What I need to know is to you want the unit to count each button press or do you want the unit to count "automatically" which is some interval of time?

Perehama:
I worked on the code in my spare time last night to get my head around it.

Thanks for sparing time for me.

What I need to know is to you want the unit to count each button press

Yes.

1. Is your 4-digit 7-segment display unit is of the following category -- cc-type multiplexed display unit being driven by port lines of UNO?

atemp4y.png
Figure-1A: 4-digit cc-type multiplexed display unit

If so, you can nicely develop the counter (range: 0 - 9 - 99 - 999 - 9999 - 0) using Arduino UNO.

Sketch Summary:
(1) Declare a 4-digit counter with initial value 0: unsigned int counter = 0x0000;.

(2) Declare a look up table (array) named lupTable[10] which will hold 10 cc-codes for the 10 decimal digits: 0 to 9:

byte lupTable[10] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; //0, 1, ..., 9

(3) For each of the digits (starting from right-most position) of the counter, get the decimal index (0b00000000 to 0b00001001) using modulus (%) and division ( / ) operators. Save these indices as inDex[0], inDex[1], inDex[2], and inDex[3] in a 4-byte wide array named byte inDex[4];. Member inDex[0] holds the index value for the display position DP3; member inDex[1] holds the index value for the display position DP2; member inDex[2] holds the index value for the display position DP1; member inDex[3] holds the index value for the display position DP0;

for(int i=0; i<4; i++)
{
   inDex[i] = counter % 10;
   counter = counter / 10;
}

(4) Use the indices of Step-3 as pointer and collect the corresponding cc-codes from the loop up table of Step-2. Save the cc-codes in a 4-byte wide array named byte ccCode[4];.

for(int i = 0; i<4; i++)
{
   ccCode[i] = lupTable[inDex[i]];
}

(5) Suppress the leading zeros of the ccCode[4] array of Step-4.

x = ccCode[3]
if(x == 0x3F)
{
   ccCode[3] = 0x00;  //suppress; DP0 is blanked
   x = ccCode[2]
   if(x == 0x3F)
   {
      ccCode[2] = 0x00; //blank DP1
      x = ccCode[1];
      if(x == 0x3F)
      {
          ccCode[1] = 0x00; //blank DP2
      }  
    }
}

(6) Transfer the contents of the updated ccCode[4] array of Step-5 onto display devices DP0-DP3 of Fig-1.

byte x = ccCode[3];   //data for DP0 Position
PORTB = x;
digitalWrite(6, bitRead(x, 6));
digitalWrite(7, bitRead(x, 7));
PORTC = 0b111110;
delay(1);

2. If you wish, you can also develop the 4-digit cc-type 7-segment multiplexed display unit using MAX7219 driver. All the programming information for the chip is given below. (The physical placement of the 0.1uF (104) capacitor (C1) is very crucial; it has to be placed very close to Pin-19 (Vcc) and Pin-4(GND) of MAX7219 chip.)

Figure-1B: MAX7219 driven 4-digit cc-type 7-segment display unit

(2) Programming Charts of MAX7219
pch7219-1.png

pch7219-2.png

pch7219-3.png

pch7219-4.png

3 Programming Procedures of the Display Unit of Fig-1B
(1) Let us place the MAX7219 chip and 4xcc-type 7-segment display devives (DP0-DP3) on the breadboard. Place the 0.1uF (104) capacitor (C1) between Pin-19 (Vcc) and Pin-4 (GND) having a ride over the chip. Establish all connections among the display devices, MAX7219, and Arduino UNO.

(2) Open an IDE and create the following sketch

atemp4y.png

pch7219-1.png

pch7219-2.png

pch7219-3.png

pch7219-4.png

The reason I don't like working with creepypasta from the internet is that most of the code I've seen is written with a scope so narrow that to expand or modify it's use requires a lot of rewriting the code. For you, I've done just that. I've kept the pins and HIGH/LOW behavior the same(excusing my own human error), with the exception of the button. If you need it to go HIGH to count, you will NOT want to use the internal pullup resistor, which holds it HIGH. instead, you will need an external pull-down resistor from the pin to ground. 10 KOhms should work. I've written the code in a way I hope you can easily follow and modify for your future need.

/*  Display Control for 4 anodes and 8 cathodes (for common cathode, see inline comments in displayRefresh())
    signal for segments controlled by Arduino Pin Numbers 6-13 as follows
       ___
      | a |
    f |___| b
    e | g | c
      |___| .
        d   dp
    a = 6, b = 7, c = 8, d = 9, e = 10, f = 11, g = 12, dp = 13

    signal for commons controlled by Arduino Pin Numbers 2-5 as follows
     _   _   _   _
    |_| |_| |_| |_|
    |_| |_| |_| |_|
    d4  d3  d2  d1
    d1 = 5, d2 = 4, d3 = 3, d4 = 2;
*/

const byte NumbersLUT[11] = {0xFC, 0x60, 0xDA, 0xf2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xF6, 0x00};// segment data for numbers 0-9 and blank
const byte SegmentsLUT[8] = {6, 7, 8, 9, 10, 11, 12, 13};// pin numbers for segments
const byte CommonsLUT[4] = {2, 3, 4, 5};// pin numbers for commons
const unsigned long refreshRate = 1000UL;
unsigned long refreshTimestamp;
byte displayData[4] = {0x00, 0x00, 0x00, 0xFC};// stores data from NumbersLUT for each digit
byte digitIndex = 3;// indexes displayData and CommonsLUT to multiplex display

const byte ButtonPin = 14;
int lastButtonState;
unsigned long buttonDebounceTimestamp;
byte ones;
byte tens;
byte hundreds;
byte thousands;


void setup() {
  for (byte i = 2; i <= 13; i++) pinMode(i, OUTPUT);// sets pins 2-13 as outputs
  pinMode(ButtonPin, INPUT);
}

void loop() {
  if (pollbutton()) incrementCount();
  displayData[0] = (thousands == 0) ? 0x00 : NumbersLUT[thousands];
  displayData[1] = (thousands == 0 && hundreds == 0) ? 0x00 : NumbersLUT[hundreds];
  displayData[2] = (thousands == 0 && hundreds == 0 && tens == 0) ? 0x00 : NumbersLUT[tens];
  displayData[3] = NumbersLUT[ones];
  displayRefresh();
}

bool pollbutton() {
  int buttonState = digitalRead(ButtonPin);
  if (buttonState != lastButtonState && buttonState == HIGH) {// transition is LOW to HIGH
    if (millis() - buttonDebounceTimestamp >= 50UL) {// 50UL = 50ms = time for debounce
      lastButtonState = buttonState;
      buttonDebounceTimestamp = millis();
      return true;
    }
  }
  else {
    lastButtonState = buttonState;
    return false;
  }
}

void incrementCount() {
  if (ones >= 9) {
    ones = 0;
    if (tens >= 9) {
      tens = 0;
      if (hundreds >= 9) {
        hundreds = 0;
        if (thousands >= 9) {
          thousands = 0;
        }
        else thousands++;
      }
      else hundreds++;
    }
    else tens++;
  }
  else ones++;
}

void displayRefresh() {
  if (micros() - refreshTimestamp >= refreshRate) {
    digitalWrite(CommonsLUT[digitIndex], LOW);// HIGH for common cathode
    for (int i = 0; i < 8; i++) digitalWrite(SegmentsLUT[i], ((displayData[digitIndex] & (0x01 << i)) ? LOW : HIGH));// swap HIGH and LOW for common cathode
    digitIndex = (digitIndex >= 3) ? 0 : (digitIndex + 1);
    digitalWrite(CommonsLUT[digitIndex], HIGH);// LOW for common cathode
    refreshTimestamp = micros();
  }
}

Thanks once again for sparing time for me.

However, your code is give strange results on the display module. The segments of a digit are not lighting up correctly. Also the pins for the digits are not defined in correct order.

By the way, have you tested or simulated your code?

abuhafss:
Thanks once again for sparing time for me.

However, your code is give strange results on the display module. The segments of a digit are not lighting up correctly. Also the pins for the digits are not defined in correct order.

By the way, have you tested or simulated your code?

I have not tested my code. I have no idea what the rest of your circuit is. What are the results you are seeing? Do you understand my code? I can say that my code is closer to your goal than the OP code, and very modular. I was hoping you could much more easily follow my code to be able to see what I am doing with the "button" and the count and the display. I was hoping you might see how I am "holding" the display between counts. Do you see how I've eliminated the use of delay(), which will forever plague your ability to capture the press of a button?

It took me some time but, I understood your code.
I rectified some small mistakes to make the code run as programmed.
The segment data which you declared in NumbersLUT array is not correct, the digits being displayed are as attached.

digits.png

I replaced the segment data with the one provided by brother Gholam Mostafa, in post #7

const byte NumbersLUT[11] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x00}; //0, 1, ..., 9

that worked perfectly.

Thanks both of you.

In the meantime, I also managed to work out my code using SevSeg library.

The button at pin A0 is to replace with NEGATIVE pulse (not positive) from IR sensor module.

#include "SevSeg.h"

SevSeg sevseg; //Initiate a seven segment controller object
int n = 0;
int buttonPin = 14;    // Connected to the output of IR sensor module


void setup() 
{
  pinMode(buttonPin, INPUT_PULLUP);
  byte numDigits = 4;
  byte digitPins[] = {2, 3, 4, 5};
  //                    A   B   C   D  E  F  G  dp
  byte segmentPins[] = {12, 11, 10, 9, 8, 7, 6, 13};

  sevseg.begin(COMMON_ANODE, numDigits, digitPins, segmentPins);

  sevseg.setBrightness(90);
  sevseg.setNumber(n);
}

void loop() 
{ 
  
  while (digitalRead(buttonPin) == HIGH)
  {
    sevseg.refreshDisplay(); // Must run repeatedly
  }
   n++;
   sevseg.setNumber(n);
   delay(200);
   
}

Can you please, post the wiring diagram of your display unit?

abuhafss:
The segment data which you declared in NumbersLUT array is not correct, the digits being displayed are as attached.

NumbersLUT is a look up table that I probably should have typed in binary to better illustrate what I was doing. Hex sort of obfuscates the purpose. Basically, instead of the switch cases, which I never liked. I am storing the segments for each number in a bit mask, which is in turn stored in an array which is indexed by the very number represented. The reason I did this was because maybe at some point someone will need a few more I/O for other push-buttons or whatever, and want to move the segments and commons to shift registers. Having the code as I have it, makes the move to shift registers easy. The incorrect values in my look up table are correct for one order of segments, if not yours. I am glad you were able to fix them.

I learned a lot from your code, thank you.

But one thing I don't understand.
Physically, I connected
D1 to Arduino D2,
D2 to 3,
D3 to 4,
D4 to 5

If use this code:

const byte CommonsLUT[4] = {2, 3, 4, 5};// pin numbers for commons

unit is displayed at position D1
tens is displayed at position D4
hundreds is displayed at D3
thousand at D2

If I change the code:

const byte CommonsLUT[4] = {5, 2, 3, 4};// pin numbers for commons

the problem is solved but physical connections does not match this order.

GolamMostafa:
Can you please, post the wiring diagram of your display unit?

Are you asking for the pinouts of my display module? It is attached.

If you want to know my connections to Arduino, refer to my post above.

abuhafss:
If I change the code:

const byte CommonsLUT[4] = {5, 2, 3, 4};// pin numbers for commons

the problem is solved but physical connections does not match this order.

What happens if you leave CommonsLUT in the matching order and change

byte digitIndex = 3;// indexes displayData and CommonsLUT to multiplex display

to 0 or 1 or 2?

No change, same result.