Countdown

 
Countdown.png
 

My last project presented a problem; trying to find a simple solution for an Arduino countdown timer that uses multiple chained LED matrix displays. Searching the Internet yielded no helpful results, so I ended up creating my own.

My first attempt was to create an array of three hundred characters (“05:00”, “04:59”, “04:58”, etc) and increment the pointer in the array every second. I didn't realise that this array would greatly exceed the memory on the Arduino. Next I tried setting up zones for the four displays I was using and push the values, as integers, on each one (0 for the first display, 5 for the second, 0 for the third and 0 again for the fourth). The libraries I found only accepted characters, not integers.

I toyed with the idea of creating a custom font, but that was going to take a long time. Instead I wrote the code below. It's a combination of the first two ideas, but instead of using an array of three hundred characters, it has four arrays of either six or ten characters (to represent the tens value and unit value for minutes and seconds) and has each digit mapped to a display.

#include <MD_Parola.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW  // This is the hardware setting that works for the MAX7219 8x32 LED matrix
#define CLK_PIN   13                       // LED Matrix CLK pin to Arduino 13
#define DATA_PIN  11                       // LED Matrix DIN pin to Arduino 11
#define CS_PIN    10                       // LED Matrix CS  pin to Arduino 10

uint8_t frameDelay = 25;  // Sets the frame delay for the displays to 25ms (default value)

MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, 4);  // The "4" here is the number of displays connected

char* Digit0[] = {"5", "4", "3", "2", "1", "0"};                                // Values for the left most display (i.e. the tens of minutes)   - X0:00
char* Digit1[] = {"9:", "8:", "7:", "6:", "5:", "4:", "3:", "2:", "1:", "0:"};  // Values for the second display (i.e. the units of minutes)     - 0X:00
char* Digit2[] = {"5", "4", "3", "2", "1", "0"};                                // Values for the third display (i.e. the tens of seconds)       - 00:X0
char* Digit3[] = {"9", "8", "7", "6", "5", "4", "3", "2", "1", "0"};            // Values for the right most display (i.e. the units of seconds) - 00:0X

int Pointer0 = 6;     // Pointer for the tens of minute array - Set to postition six in the array for the example - 0
int Pointer1 = 5;     // Pointer for the unit of minute array - Set to position five in the array for the example - 5
int Pointer2 = 6;     // Pointer for the tens of second array - Set to position six in the array for the example  - 0
int Pointer3 = 10;    // Pointer for the unit of second array - Set to position ten in the array for the example  - 0

int Count = 0;    // Counter for the number of increments in the timer (i.e. the number of seconds passed)
int Timer = 300;  // Sets the timer to five minutes

long LastTime = 0;  // For use with the millis function

// ---------------------------------------- Setup ----------------------------------------
void setup()
{
  P.begin(4);           // Starts the display
  P.setZone(0, 0, 0);   // Assigns the zone number, first display in the zone, and last display in the zone
  P.setZone(1, 1, 1);
  P.setZone(2, 2, 2);
  P.setZone(3, 3, 3);
  P.setIntensity(0);    // Sets the display brightness

  LastTime = millis();  // Once the setup has completed, set the time reference
}

// -------------------------------------- Main Loop --------------------------------------
void loop()
{
  if(Count == Timer)  // If the counter has finished
  {
    P.setZone(0, 0, 3); // Set the display to act as one zone
    P.displayText("STOP", PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);  // Display the word "STOP"
    P.displayAnimate();
  }
  else  // If the counter hasn't finished
  {
    P.displayZoneText(3, Digit0[Pointer0], PA_CENTER, 0, 0, PA_PRINT);  // Display the time remaining
    P.displayZoneText(2, Digit1[Pointer1], PA_CENTER, 0, 0, PA_PRINT);
    P.displayZoneText(1, Digit2[Pointer2], PA_CENTER, 0, 0, PA_PRINT);
    P.displayZoneText(0, Digit3[Pointer3], PA_CENTER, 0, 0, PA_PRINT);
    P.displayAnimate();
    if(millis() - LastTime >= 1000)  // If a second has passed since the last update, increment the counter - Be careful here if you run code that takes more than a second to perform
    {
      Pointer3 ++;
      Count ++;
      LastTime = millis();
    }
    if(Pointer3 == 10)  // In this section, if any of the arrays reaches the last value, set the pointer back to the first value and increment the array.  For example, if the countdown is at 01:50, instead of having the 0 become -1, set it to 9, and set the tens to 4.
    {
      Pointer3 = 0;
      Pointer2 ++;
      if(Pointer2 == 6)
      {
        Pointer2 = 0;
        Pointer1 ++;
        if(Pointer1 == 10)
        {
          Pointer1 = 0;
          Pointer0 ++;
        }
      }
    }
  }
}

I don't assume this is a common problem, but if it can help someone, all the better.