Parola, MAX7219, Count-up Stopwatch

Hi, I am working on to make a count-up stopwatch for my physical experiment. This is my first arduino project which is so exciting but also nervous about it. My research experiment is going to be more than 400 hours, and I would like to make "HHH:MM:SS" format stopwatch. It would be great if I can control this stopwatch through "Serial Monitor" & "Bluetooth" + "64X16 doubled height display" since it will be difficult to access to stopwatch during my experiment.

But since I am new to this Arduino world, I would like to start with a simple and easy timer project and move forward from there.

I'm currently dealing with Arduino UNO controller, MAX7219 display, Parola library. A simple counter practice was successful only with seconds. However, I'm having trouble with HHH:MM:SS format timer and would like to have suggestion for this code. I tried this but code is not stable and timer seems off by few seconds.

I would like to hear any suggestion with this code! Thanks in advace!

Here is my code:

#include <MD_MAX72xx.h>
#include <MD_Parola.h>
#include <SPI.h>
//#include "Font_Data.h"
//#include <LibPrintf.h>

#define MAX_DEVICES 8
#define CS_PIN 10
#define CLK_PIN 13
#define DATA_PIN 11

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW

MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

char Buffer[3] = " ";  // create a buffer to hold the numbers
int seconds = 00; // the counter will start from 0 you can set any value
int minutes = 00;
int hours = 00;

//unsigned long startTime = 0;
//unsigned long elapsedTime = 0;

void setup() {
  Serial.begin(9600);
  P.begin();
  P.setIntensity(4);
  
}

void loop() {

  if (P.displayAnimate()) {

    sprintf(Buffer, "%03u:%02u:%02u", hours, minutes, seconds);
    P.displayText(Buffer, PA_RIGHT, 0, 0, PA_PRINT, PA_NO_EFFECT);

    seconds++;
    delay(1000);

  }

  if (seconds == 61) {
    seconds = 00;
    minutes++;
    seconds++;
  }

  if (minutes >= 60) {
    minutes = 0;
    hours++;
    seconds++;
  }

  if (hours == 400) {
    hours = 0;
  }

  if (P.displayAnimate()) {

    sprintf(Buffer, "%03u:%02u:%02u", hours, minutes, seconds);
    P.displayText(Buffer, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);

    delay(1000);
  }
}

This is a big mistake. Your buffer will need to be bigger, otherwise you will run into problems, and it is impossible to predict what exactly those problems will be ("undefined behavior" is the technical term).
Change it to

char Buffer[10];  // create a buffer to hold the numbers

Why size 10? Let me show you:

0123456789
HHH:MM:SS is 9 characters

plus you need 1 extra character after the string for the null terminator,
so 10 characters is the bare minimum you need for your Buffer here.

See if that helps things work better.

Besides, the Arduino is not made to be an accurate clock over long intervals of time. If this line

is not giving you the timing that you want, you can always change it to delay(999); or delay(998); or delay(1001); or whatever number seems to make the timing more accurate. But the real solution is to get a DS3231. If you don't know what a DS3231 is, google it. It is a chip designed for accurate timekeeping. If you are making an Arduino-based clock project, it is exactly what you need. Sort of.

A DS3231 is designed to keep track of calendar date and time, like for example Tuesday, February 20, 2024, 21:40:25. The date can be anything from January 1, 2000 to December 31, 2099. When you first start the clock, it starts from January 1, 2000, 00:00:00. So, for seconds, minutes, and hours up to 23 hours, you will be able to use the DS3231 to keep time the way you are looking for. For 24 hours through to 743 hours, you will be able to use the trick of
total_hours = ((day_of_month - 1) * 24) + hours
to get the behavior you seek. Then, to reset the stopwatch to zero, you will need to write the date and time January 1, 2000, 00:00:00 to the DS3231.

1 Like

Thank you very much for your comments
And really appreciate your kind explanation!!

I have DS1307 RTC. Would this DS1307 chip good for keep tracking time?

From what I have heard, it is not as good as a DS3231, but it is better than nothing.

1 Like

Are you practicing with the following Module (Fig-1) -- two in casecade?
image
Figure-1:

1 Like

yes MAX72xx. I bought total 4 display (each 8X32 matrix) modules. I am practicing with 8X64 (two modules are connected), and then trying to move forward to 16X64 dmd.

Please, post the pictures of your modules; I am facing difficulties to apprehend those modules -- what is the meaing of "4 display (each 8x32)"?

I would term the Module of Fig-1 of post #5 as: 4x64 (4 Modules each containing 8x8 = 64 LEDs).

Sorry about confusion. Here are photos!

8X32 dot matrix module (I combined two modules):
thumbnail_IMG_4280

total (16X64 module)
thumbnail_IMG_4281

Thank you for the pictures.
Usually, the LED 8x8 LED matrix Moduls come as 4x64. Anyway, you have 16x64 LED Matrix Display Unit. You want to make them bigger by stacking 8x64 Unit over another 8x64 unit.

I would suggest that you statrt with a 8x64 unit (Fig-1) to display the time from DS1307 RTC in the following format: HRR:MIN:SEC (HH:MM:SS). After that play with 2x8x64 unit (Fig-2).

image
Figure-1:

image
Figure-2:

1 Like

Thank you for your suggestion!
I am currently working on to connect DS1307 RTC and Arduino UNO.
I do have ESP32 and ESP8266 chips. Do you have recommendation which chip is better for stopwatch?

Thank you!!

Thanks again for your suggestion! This is so exciting!!

I have following questions regarding your approach.

Since it is a very long experiment, I need to "stop/pause" and/or "resume" my experiment as well as this clock. Do you think I can "resume" this clock at the time I stopped?

Or, am I able to manually set up the starting time of this clock?

Thank you !

1. Start with Arduino UNO and DS1307 RTC; show the time of the day on the Serial Monitor.
Sketch:

#include "RTClib.h"
#include<Wire.h>
//byte prSec = 0;
byte lastReadSecond = 0;

RTC_DS1307 rtc;  //RTC_DS3231 rtc; //user data type RTC_DS3231    variable rtc or object
DateTime nowDT;
//char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

void setup ()
{
  Serial.begin(115200);
  rtc.begin();


  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  //rtc.adjust(DateTime(2021, 12, 31, 12, 59, 57));//set date-time manualy:yr,mo,dy,hr,mn,sec
}

void loop ()
{
  nowDT = rtc.now();
  if (lastReadSecond != nowDT.second())
  {
    showTime();
  }
 
}

//===================================================
void showTime()
{
  nowDT = rtc.now();  //nowDT hold Date and Time
  lastReadSecond = nowDT.second();
  //---------------------------
  byte myHour = nowDT.hour();   //myHour holds Hour of time of daya
  myHour = myHour - 12;
  Serial.print(myHour); //12:58:57     12:4:56
  Serial.print(':');
  //-------------------------------------------------
  byte myMin = nowDT.minute(); //to show leading zero of minute
  if (myMin < 10)
  {
    Serial.print('0');
  }
  Serial.print(nowDT.minute()); Serial.print(':');
  //--------------------------------------------------
  byte mySec = nowDT.second();
  if (mySec < 10)
  {
    Serial.print('0');
  }
  Serial.println(mySec);//(nowDT.second(), DEC);
}

Output:

3:44:58
3:44:59
3:45:00
3:45:01
3:45:02

2. Now connect your 4x64 LED Matrix Display Unit with UNO using SPI Port:

UNO          Display Unit
DPin-10 ---> CS
DPin-11 ---> DIN
DPin-13 ---> CLK
5V --------> VCC
GND -------> GND

3. Create sketch for the 8x64 Display Unit to interface the time of the day of Step-1. (This is an example/tutorialfor you.)

// Including the required Arduino libraries
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 8
#define CS_PIN 10
MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

#include "RTClib.h"
RTC_DS1307 rtc;
DateTime nowDT;
byte lastReadSecond = 0;
char myBuffer[20];
byte myHour, myMin, mySec;

void setup()
{
  Serial.begin(115200);
  rtc.begin();
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));//take time form PC
  myDisplay.begin();
  myDisplay.setIntensity(0);
  myDisplay.displayClear();
  myDisplay.setTextAlignment(PA_LEFT);
}

void loop()
{
  getTime();
  sprintf(myBuffer, "%02u:%02u:%02u", myHour, myMin, mySec);
  myDisplay.print(myBuffer);
}
//=============================
void getTime()
{
  nowDT = rtc.now();
  if (lastReadSecond != nowDT.second())
  {
    nowDT = rtc.now();  //nowDT hold Date and Time
    lastReadSecond = nowDT.second();
    //---------------------------
    myHour = nowDT.hour() - 12;
    myMin = nowDT.minute();
    mySec = nowDT.second();
  }
}
//=========================

Output:
image

OK, maybe the approach I suggested is not the right approach for you. Maybe a different approach is needed.

I don't have your hardware in front of me, so I can't do testing. But what I would do if I were you is something like this:

It will be OK to have the DS1307 keep track of the real date and time: February 21, 2024, etc.

For code, I would start with your original stopwatch sketch. (But remember what I said about the Buffer size and making the Buffer big enough!) But get rid of the delay(1000). Instead of the delay(1000), write code to read the seconds from the DS1307, and check to see if the seconds have changed. (For this, you will need to keep track of old seconds to compare to the new seconds.) If the seconds from the DS1307 have changed, then add 1 to the stopwatch seconds.

Let me try to explain what I mean with an example.
Suppose that your stopwatch starts from 000:00:00, and the DS1307 says that the time is 12:05:23. Then, you wait until the seconds from the DS1307 are 24, and then change your stopwatch to show 000:00:01. Then, you wait until the seconds from the DS1307 are 25, and then change your stopwatch to show 000:00:02. And so forth.

To pause your stopwatch, add 0 to the seconds instead of adding 1. Then to resume, just add 1 again. You can have a variable be 0 for paused and 1 for running, and have this number be added to the stopwatch seconds each second to give the behavior you are looking for.

1 Like

Instead of using the clock (unless you want to) the DS1307 has a signal output SQW/OUT which can be set to one Hz (once per second). You can monitor this on a Digital Input and when it changes you can use it to trigger your internal counter. This is just like you intention at the beginning but with an accurate 1 second signal. Pausing and restarting becomes very easy.

1 Like

Thanks for your help!

I tried your code (Step1.) but I wasn't able to display on the Serial Monitor. Do you have any idea what I've missed?

Thank you!

Hi,

Thanks for your suggestion!!
I've tried to compare my stopwatch vs. phone stopwatch, and it seems like delay has to be 993 for accurate arduino stopwatch!

your second suggestion (feedback with DS1307 time) would be interesting and challenging to me. But I would give it a try!

I've finally got DS3231 and button cell battery! Thanks for your suggestion!

Thank you for your help!

I don't know much about 1Hz signal output setting, triggering internal counter, and how to do this but I will try to work on it!

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