Help with 7 seg display countdown timer code

I am having some problems with a code I am trying to use for a CA seven set display 4 digits long (Kindly available from tinkercad).My wiring is as show on the attached image. I am having an issue with the start button (countdown)

When editing the code to debug with the serial monitor everything appears to work fine apart from the start button itself (to activate the timer) (serial monitoring output test attached). The code itself is a bit strange as it has been written for both a seven seg display with shift register (which I'm using) and a I2C display using IF statement to determine between the two components within the code.

I cannot fathom why the start button does not work - on the seven seg display it just shows one digit usually a 1 or 0 (dependant on the time I put in) after pressing the start button. setting the time etc works fine.

Admittedly the code it quite a stretch for my current skill level but I thought I would be able to debug it. I have tried removing all the IF statements and having the code purely suited just to the seven seg display but same issue. its been a few days not and I am wondering if I am overlooking something very simple

any help really appreciated

here is the code


#define I2C_DISPLAY 0 //Set it to 1 if you are using arduino UNO with I2C LCD
//Set it to 0 if you are using 74HC595 LCD
//74HC595 uses 7 pins. I2C display only uses 2 pins.
//Alarm pins at 8, 12, 11, A2, A3 can only be used for alarms in I2C mode. Because 74HC595 also uses these same pins.
#define ENABLE_SERIAL 0 //if you ENABLE serial port then you will not be able to use button on pin 0 and 1 correctly.
//But you can see data on serial monitor which will help while debugging. In final code, change it to 0.


#if I2C_DISPLAY
#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
Adafruit_7segment matrix = Adafruit_7segment();
#endif



//I2C pins: ‎Arduino UNO A4 (SDA), A5 (SCL), on Mega2560‎: ‎20 (SDA), 21 (SCL)

//Pin numbers:
const int reset_btn_pin = 1;

const int minutes_tens_pin = 5;
const int minutes_units_pin = 4;
const int seconds_tens_pin = 3;
const int seconds_units_pin = 2;


const int speed2x_pin = 6;
const int speed3x_pin = 7;
const int piezo_pin = 9;
const int speed4x_pin = 10;
const int freeze_btn_pin = A0; //freeze button
const int freeze_led_pin = A1;
const int start_pin = 13;

const int total_alarms = 5;

#if !I2C_DISPLAY
byte digit[4] = {A5, A4, A3, A2};
int latchPin = 8;//Pin connected to ST_CP of 74HC595
int clockPin = 12;//Pin connected to SH_CP of 74HC595
int dataPin = 11;////Pin connected to DS of 74HC595
#else
const int alarm_pins[total_alarms] = {8, 12, 11, A2, A3}; //pin numbers for alarm LED
#endif
const int alarm_at_minute[total_alarms] = {0, 5, 10, 15, 20};  //minutes remaining at which to turn on alarm pin

static boolean pause = 1;
unsigned long speeder = 1000;
int seconds = 0;
int minutes = 0;
static int counter = 0;


void setup()
{
#if !I2C_DISPLAY
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  for (int i = 0; i < 4; i++)
  {
    pinMode(digit[i], OUTPUT);
  }
#else
  for (int i = 0; i < 7; i++)
  {
    pinMode(alarm_pins[i], OUTPUT);
  }
#endif

  pinMode(reset_btn_pin, INPUT_PULLUP);
  pinMode(start_pin, INPUT_PULLUP);

  pinMode(minutes_tens_pin, INPUT_PULLUP);
  pinMode(minutes_units_pin, INPUT_PULLUP);
  pinMode(seconds_tens_pin, INPUT_PULLUP);
  pinMode(seconds_units_pin, INPUT_PULLUP);

  pinMode(speed2x_pin, INPUT_PULLUP);
  pinMode(speed3x_pin, INPUT_PULLUP);
  pinMode(speed4x_pin, INPUT_PULLUP);
  pinMode(freeze_btn_pin, INPUT_PULLUP);
  pinMode(freeze_led_pin, OUTPUT);
  pinMode(piezo_pin, OUTPUT);


  digitalWrite(piezo_pin, 0);

#if !I2C_DISPLAY
  print_serial("Mode: Shift74HC595 IC\n");
#else

  matrix.begin(0x70);
  print_serial("Mode: I2C\n");
#endif


  reset_countdown();
  print_serial("Ready\n");
}

static unsigned long last_mills = 0;
boolean drawDots = false;



boolean beep = 0;
unsigned char serial_tick = 0;
int last_alarm = -1;

void loop()
{
  unsigned long now_mills = millis();
  if ((now_mills - last_mills) >= speeder)
  {
    last_mills = now_mills;

    if (!pause)
    {
      drawDots = false;
      seconds--;
      if (seconds < 0)
      {
        if (minutes > 0)
        {
          seconds = 59;
          minutes--;
          if (minutes < 0)
          {
            minutes = 0;
          }
        }
        else
        {
          countdown_reached();
        }
      }

      beep = !beep;
      if (beep)
        analogWrite(piezo_pin, 10);
    }
#if ENABLE_SERIAL
    //show clock on serial monitor every 2 seconds
    serial_tick++;
    if (serial_tick >= 2)
    {
      serial_tick = 0;
      Serial.begin(9600);
      Serial.print(minutes); Serial.print(':'); Serial.println(seconds);
      Serial.end();
    }
#endif

  }
  else if (now_mills > (last_mills + (speeder / 2)))
  {
    drawDots = true;
    digitalWrite(piezo_pin, 0);
  }

  counter = (minutes * 100) + seconds;

#if I2C_DISPLAY
  matrix.writeDigitNum(0, (counter / 1000), drawDots);
  matrix.writeDigitNum(1, (counter / 100) % 10, drawDots);
  matrix.drawColon(drawDots);
  matrix.writeDigitNum(3, (counter / 10) % 10, drawDots);
  matrix.writeDigitNum(4, counter % 10, drawDots);
  matrix.writeDisplay();
  delay(10);
#else
  displayRefresh(counter);
#endif

  check_pins();
}




void countdown_reached()
{
  seconds = 0;
  minutes = 0;
  pause = true;
#if I2C_DISPLAY
  for (int i = 0; i < total_alarms; i++)
  {
    digitalWrite(alarm_pins[i], LOW);
  }
  digitalWrite(alarm_pins[0], HIGH);
#endif
  print_serial("Countdown Reached\n");
}

void reset_countdown()
{
  print_serial("Countdown reset\n");
  seconds = 0;
  minutes = 0;
  pause = true;
  speeder = 1000;
  last_alarm = -1;
#if I2C_DISPLAY
  for (int i = 0; i < total_alarms; i++)
  {
    digitalWrite(alarm_pins[i], LOW);
  }
#endif
  digitalWrite(freeze_led_pin, 0);
}

void start_countdown()
{
  print_serial("Countdown started\n");
  pause = false;
  speeder = 1000;
  last_alarm = -1;
#if I2C_DISPLAY
  for (int i = 0; i < total_alarms; i++)
  {
    digitalWrite(alarm_pins[i], LOW);
  }
#endif
  digitalWrite(freeze_led_pin, 0);
}






void check_pins()
{
  if (read_pin(reset_btn_pin))
  {
    reset_countdown();
  }
  if (read_pin(minutes_tens_pin))
  {
    minutes += 10;
  }
  if (read_pin(minutes_units_pin))
  {
    minutes++;
  }
  if (read_pin(seconds_tens_pin))
  {
    seconds += 10;
  }
  if (read_pin(seconds_units_pin))
  {
    seconds++;
  }
  if (read_pin(start_pin))
  {
    start_countdown();
  }
  if (read_pin(speed2x_pin))
  {
    speeder = 500;
    print_serial("Speed 2x\n");
  }
  if (read_pin(speed3x_pin))
  {
    speeder = 250;
    print_serial("Speed 3x\n");
  }
  if (read_pin(speed4x_pin))
  {
    speeder = 125;
    print_serial("Speed 4x\n");
  }
  if (read_pin(freeze_btn_pin))
  {
    pause = true;
    digitalWrite(freeze_led_pin, 1);
    print_serial("Freeze\n");
  }


  while (seconds >= 60)
  {
    seconds = seconds - 60;
    minutes++;
    if (minutes > 99)
    {
      minutes = 0;
      seconds = 0;
    }
  }

  if (!pause)
  {
#if I2C_DISPLAY
    for (int i = 0; i < total_alarms; i++)
    {
      digitalWrite(alarm_pins[i], LOW);
    }
#endif
    for (int i = 0; i < 7; i++)
    {
      if ((minutes == alarm_at_minute[i]) && ((seconds == 0)))
      {
        if(last_alarm != i)
        {
        print_serial("Alarm\t" + String(alarm_at_minute[i]) + " mins\n");
        last_alarm = i;
        }
#if I2C_DISPLAY
        digitalWrite(alarm_pins[i], HIGH);
#endif
        break;
      }
    }
  }

}

int last_btn = -1;

boolean read_pin(int pin_no)
{
  if (last_btn != -1)
  {
    if ((digitalRead(last_btn) == LOW) && (digitalRead(last_btn) == LOW))
    {
      return false;
    }
    else
      last_btn = -1;
  }

  if ((digitalRead(pin_no) == LOW) && (digitalRead(pin_no) == LOW))
  {
    unsigned long count_press = 0;
    while (count_press < 10)
    {
      if (digitalRead(pin_no) == HIGH)
      {
        return false;
      }
      count_press++;
      delay(1);
    }
    print_serial("Pin " + String(pin_no) + " LOW\n");
    last_btn = pin_no;
    return true;
  }
  return false;
}

void print_serial(String toprint)
{
#if ENABLE_SERIAL
  Serial.begin(9600);
  Serial.print(toprint);
  Serial.end();
#endif
}



#if !I2C_DISPLAY
int last_digit = 0;
void displayRefresh(int count)
{
  last_digit++;
  if (last_digit >= 4)
    last_digit = 0;
  for (int i = 0; i < 4; i++)
  {
    if (i == last_digit)
    {
      displayDigit(extractDigit(count, i + 1));
      digitalWrite(digit[i], HIGH);
    }
    else
    {
      digitalWrite(digit[i], LOW);
    }
  }
  delay(5);
}
void displayDigit(int d)
{
  char number[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
  digitalWrite(latchPin, LOW);
  // shift out the bits:
  shiftOut(dataPin, clockPin, MSBFIRST, ~number[d]);

  //take the latch pin high so the LEDs will light up:
  digitalWrite(latchPin, HIGH);
}

int extractDigit(int V, int P)
{
  return int(V / (pow(10, P - 1))) % 10;
}
#endif

Hi and welcomeTo the forum.

Please edit your post above and put code tags around your code. I'm not sure what kind of tags you put around the code, but they were not code tags - you can see that the formatting such as indentation had been lost in many parts. You may need to re-copy the code from the IDE, because what you pasted before has now been altered by the forum. I recommend clicking Tools-->Auto format, then Edit-->Copy to forum which will add the correct tags automatically.

thanks Paul I have followed your steps and now a weird bit comes in the middle of the code - it did this before so I put it in quote marks. is there abetter way to put the code for everyone to read - sorry this is my first post I did try to include everything!

It's no better, I'm afraid. Are you sure you followed my instructions?

hanks Paul I am following your instructions very bizarre eh IDE confirms no changes necessary and I can't possibly see how I can mess up a copy and paste lol!

Screen Shot 2021-04-29 at 19.31.19|397x159

I will have a play around with I and see if I can ge it any better

I think its working now :slight_smile: do let me know if any issues or any other info needed

Yes, auto format won't do anything if your code is already properly formatted. If course, I couldn't tell if it was or not, until you posted it correctly with the code tags. No idea what you did different this time, but it worked. Thanks, it's a little easier to read now.

Your diagram has disappeared. Not that it was a great diagram. I'm not familiar with tinkercad, but I am familiar with breadboards, so I know you can't push two wires into the same hole. At least not without damaging it!
A proper schematic is much better, even if it's hand-drawn.

From what I remember of your diagram, I was worried about the way the buttons were connected. Those 4-pin buttons are tricky. 2 pairs are permanently connected internally. When you press the button, one pair is connected to the other pair. But it's not easy to tell which pin is connected to which by looking at them. Connect to the wrong pins, and that might explain why one of your buttons is not working. The simple trick to avoid that problem is to always use a diagonally opposite pair of pins and leave the other pair unconnected. You don't need resistors if using INPUT_PULLUP mode. Just connect one button pin to the Arduino input and the diagonally opposite pin to ground.

Hey Paul glad its easier to read now.

I will add the diagram again - but you're right its not very clear on the wiring, tinkercad tends to cover up the wires with the components which is irritating. I think the buttons are okay you can only really fit them in one way over the gap in the breadboard making it easier to identify he linked pins. Ive adding photos of the actual wiring - not sure if that is helpful (I haven't rammed two wires in the same hole.)

That is a great tip re resister on INPUT_PULLUP thank you

I'm minded to think that its ore of a Code problem than a wiring one because on pressing the button it does make a change to the seven seg displays - just not the change I want!

I have added two pictures one showing me setting the time using the push buttons to 1.50s and then wha displays after pressing start - sometimes it displays a 1 other times a 0.

I can try and draw the wiring diagram however, this will take a bit of time

apparently I can only add one image duet to being anew user

setting the time with pushbuttons

error when pushing he start button

I'm trying to absorb your code. It's not easy, the code is quite convoluted. I haven't spotted the problem yet.

Please confirm: while you are setting the time, all 4 digits of the display are illuminated at all times, each showing a digit from 0 to 9. As soon as you press start, 3 digits go out and only the digit that normally shows tens-of-minutes displays 0 or 1?

Some comments on your circuit, before I forget to mention them. These things are not causing the problem, but they should be fixed anyway.

I already mentioned the pull-up resistors are not needed if you are using INPUT_PULLUP. However, if you decide to connect your buttons with long wires (e.g. a metre or more) so they can be mounted away from the circuit, then the external pull-up resistors may be helpful to prevent the long wires picking up interference which could cause phantom button presses.

You should have a 0.1uF ceramic capacitor close to the Vcc & ground pins of the '595 chip. This is called a bypass capacitor and any bare chip you use in a circuit should have one. Without these caps, chips can cause circuits to misbehave.

The 470R series resistors for the display segments are a little too low. The LEDs in the display segments could have a forward voltage as low as 1.8V., leaving the series resistors to drop 3.2V which means nearly 7mA will flow through them when the segment is illuminated. This in itself isn't a problem, but if a digit displays "8", 7 x 7 = 49mA will flow into the common anode from 5V through an Arduino pin. The absolute maximum current for an Uno pin is 40mA, so you are breaking that maximum which could damage the Uno. Increase to resistors to 680R for example. If that makes the display too dim, you could add 4 ordinary PNP transistors like bc327 to switch the anode current. Then you can reduce the series resistors down to 160R, making the display much brighter. Connect the PNP bases to Arduino pins with 1K resistors, and flip the setting of HIGH and LOW on those pins in the code.

I was thinking that, generally I would advise 1k resistors, but I did not comment because in fact, there is significant voltage drop in the mega328 output drivers equivalent to about a 50 Ohm resistance.

So when you put it all together, the common current for 8 segments will be more like 25 mA. Of course, I would still advise using 1k resistors.

I did have to inspect the photos carefully to figure out the resistors used were indeed 470 Ohm 1% resistors - yellow purple black black. :grinning:

That is correct.

Thankyou for all the information about resistors etc - the eventual project will span over more than 1 meter distance if i ever get the countdown timer to work. At this stage im tempted try and rewrite it using just seven seg library :frowning:

I am so close to figuring out what the bug in the code is here, but I can't quite grasp it yet...

When the start button is pressed, the Boolean variable 'paused' gets set to false. Somehow this stops the display getting refreshed, the multiplexing freezes at digit 3. It's like displayRefresh() is no longer getting called. Maybe there's a missing 'else' or a { or } out of place somewhere...

Any minute now, one of us is going to spot it and then the others will kick themselves for not seeing it sooner. That's the way bugs are found.

1 Like

ohhh PaulRB thank you at least I'm one step closer as to where the problem lies! I will have little play around with this bit and see if I can get any progress - If I do I shall let you know asap - I do really appreciate all help from you so far :slight_smile:

additionally, sometimes the multiplexing digit faults at digit three other times its digit 4.

for example if I set the timer to 1, 1, 1, 1, then press start it errors at showing 1, nothing, nothing, nothing. - if that helps whatsoever

sorry if it was hard to read I should have stipulated that in my project I am using the same value resisters as shown on the wiring (tinkercad) diagram on the original post to allow you not to have to zoom in on the pictures. I do appreciate that and feel the pain I cant see the ones I used by eye either used the multimeter to determine - ultimately I have currently used the ones In the Tinkercad picture on original post - hopefully that is helpful. I will be updating but this is just a 50% stage of the overall project and it will be including a lot of lengths of wire 6m long so the resister will probably need to be recalculated and changed, ultimately I just want to make sure the countdown timer is working before I get to that stage however, when I do get to that stage I will be incorporating all your useful tips thank you

Try this:

      drawDots = false;
      seconds--;
      if (seconds < 0)
      {
        seconds = 0; //add this line
        if (minutes > 0)
        {

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