1

I'm using the Max7219 (8 digits, 7bits) led display to try and make a timer. I have downloaded an example code from the following site to set the led digits:

https://www.brainy-bits.com/arduino-countdown-timer-using-the-max7219-display/

However the original code simply loops as fast as possible and decriment the timer so it is not a true time. I tried to add a 10 ms delay to make it decriment 10ms on the right most digit so the 3rd digit to the right would be seconds, however I found this to be inaccurate and taking slightly longer than 1 second .

My question is is it possible to make a timer with 1ms accuracy using led display and if so how do I do it?

/* CountDown Timer version 2 using Max7219
Created by Yvan / https://Brainy-Bits.com
This code is in the public domain...
You can: copy it, use it, modify it, share it or just plain ignore it!
Thx!
*/
#define Max7219DIN 7 // Pin 7 connected to DIN (DataIN)
#define Max7219CLK 6 // Pin 6 connected to CLK
#define Max7219CS 5 // Pin 5 connected to CS
#define Buzzer 8 // Pin 8 connected to Buzzer +positive pin
int BuzzTrigger=0; // Variable to store buzzer trigger value
#include "LedControl.h" // LedControl Library created by Eberhard Fahle at http://playground.arduino.cc/Main/LedControl
LedControl lc=LedControl(Max7219DIN,Max7219CLK,Max7219CS,1); // Last number represent the number of Max7219 Modules connected 
long int countnumber=24001000 ; // Countdown timer start value HH:MM:SSSS
// Variables to store individual numbers
int firstnum=0;
int secondnum=0;
int thirdnum=0;
int fournum=0;
int fivenum=0;
int sixnum=0;
int sevennum=0;
int eightnum=0;
void setup() {
 lc.shutdown(0,false); // Wake up the display
 lc.setIntensity(0,7); // Set Brightness 0-15
 lc.clearDisplay(0); // Clear display
 pinMode(Buzzer, OUTPUT);
 digitalWrite(Buzzer, LOW); //Buzzer Off at startup
}
void loop() {
 for (countnumber; countnumber != -1; countnumber--) {
 String mystring = String(countnumber); // Transform Counter Int to String for manipulation
 // Convert number to a time value
 for (int z = 0; z < 6; z++) {
 if (mystring.substring(z) == "999999") {
 countnumber = (countnumber - 400000);
 }
 if (mystring.substring(z) == "9999") {
 countnumber = (countnumber - 4000);
 }
 }
 // Display number on Display depending on number of digits remaining
 if (countnumber > 9999999) {
 firstnum = ((countnumber / 10000000) % 10);
 secondnum = countnumber / 1000000 % 10;
 thirdnum = countnumber / 100000 % 10;
 fournum = countnumber / 10000 % 10;
 fivenum = countnumber / 1000 % 10;
 sixnum = countnumber / 100 % 10;
 sevennum = countnumber / 10 % 10;
 eightnum = countnumber % 10;
 lc.setDigit(0, 7, firstnum, false);
 lc.setDigit(0, 6, secondnum, false);
 lc.setDigit(0, 5, thirdnum, false);
 lc.setDigit(0, 4, fournum, false);
 lc.setDigit(0, 3, fivenum, false);
 lc.setDigit(0, 2, sixnum, false);
 lc.setDigit(0, 1, sevennum, false);
 lc.setDigit(0, 0, eightnum, false);
 delay(10); //<<<<<<<<<<< I ADDED THIS
 } else {
 if (countnumber > 999999) {
 // firstnum = ((countnumber/10000000)%10);
 secondnum = countnumber / 1000000 % 10;
 thirdnum = countnumber / 100000 % 10;
 fournum = countnumber / 10000 % 10;
 fivenum = countnumber / 1000 % 10;
 sixnum = countnumber / 100 % 10;
 sevennum = countnumber / 10 % 10;
 eightnum = countnumber % 10;
 lc.setChar(0, 7, '-', false);
 lc.setDigit(0, 6, secondnum, false);
 lc.setDigit(0, 5, thirdnum, false);
 lc.setDigit(0, 4, fournum, false);
 lc.setDigit(0, 3, fivenum, false);
 lc.setDigit(0, 2, sixnum, false);
 lc.setDigit(0, 1, sevennum, false);
 lc.setDigit(0, 0, eightnum, false);
 delay(10); //<<<<<<<<<<< I ADDED THIS
 } else {
 if (countnumber > 99999) {
 // firstnum = ((countnumber/10000000)%10);
 // secondnum = countnumber/1000000%10;
 thirdnum = countnumber / 100000 % 10;
 fournum = countnumber / 10000 % 10;
 fivenum = countnumber / 1000 % 10;
 sixnum = countnumber / 100 % 10;
 sevennum = countnumber / 10 % 10;
 eightnum = countnumber % 10;
 lc.setChar(0, 7, '-', false);
 lc.setChar(0, 6, '-', false);
 lc.setDigit(0, 5, thirdnum, false);
 lc.setDigit(0, 4, fournum, false);
 lc.setDigit(0, 3, fivenum, false);
 lc.setDigit(0, 2, sixnum, false);
 lc.setDigit(0, 1, sevennum, false);
 lc.setDigit(0, 0, eightnum, false);
 delay(10); //<<<<<<<<<<< I ADDED THIS
 } else {
 if (countnumber > 9999) {
 // firstnum = ((countnumber/10000000)%10);
 // secondnum = countnumber/1000000%10;
 // thirdnum = countnumber/100000%10;
 fournum = countnumber / 10000 % 10;
 fivenum = countnumber / 1000 % 10;
 sixnum = countnumber / 100 % 10;
 sevennum = countnumber / 10 % 10;
 eightnum = countnumber % 10;
 lc.setChar(0, 7, '-', false);
 lc.setChar(0, 6, '-', false);
 lc.setChar(0, 5, '-', false);
 lc.setDigit(0, 4, fournum, false);
 lc.setDigit(0, 3, fivenum, false);
 lc.setDigit(0, 2, sixnum, false);
 lc.setDigit(0, 1, sevennum, false);
 lc.setDigit(0, 0, eightnum, false);
 delay(10);//<<<<<<<<<<< I ADDED THIS
 } else {
 if (countnumber > 999) {
 // firstnum = ((countnumber/10000000)%10);
 // secondnum = countnumber/1000000%10;
 // thirdnum = countnumber/100000%10;
 // fournum = countnumber/10000%10;
 fivenum = countnumber / 1000 % 10;
 sixnum = countnumber / 100 % 10;
 sevennum = countnumber / 10 % 10;
 eightnum = countnumber % 10;
 lc.setChar(0, 7, '-', false);
 lc.setChar(0, 6, '-', false);
 lc.setChar(0, 5, '-', false);
 lc.setChar(0, 4, '-', false);
 lc.setDigit(0, 3, fivenum, false);
 lc.setDigit(0, 2, sixnum, false);
 lc.setDigit(0, 1, sevennum, false);
 lc.setDigit(0, 0, eightnum, false);
 delay(10);//<<<<<<<<<<< I ADDED THIS
 } else {
 // firstnum = ((countnumber/10000000)%10);
 // secondnum = countnumber/1000000%10;
 // thirdnum = countnumber/100000%10;
 // fournum = countnumber/10000%10;
 // fivenum = countnumber/1000%10;
 sixnum = countnumber / 100 % 10;
 sevennum = countnumber / 10 % 10;
 eightnum = countnumber % 10;
a
 lc.setChar(0, 7, '-', false);
 lc.setChar(0, 6, '-', false);
 lc.setChar(0, 5, '-', false);
 lc.setChar(0, 4, '-', false);
 lc.setChar(0, 3, '-', false);
 lc.setDigit(0, 2, sixnum, false);
 lc.setDigit(0, 1, sevennum, false);
 lc.setDigit(0, 0, eightnum, false);
 delay(10);//<<<<<<<<<<< I ADDED THIS
 }
 }
 }
 }
 }
 }
}

new implementation using millis

#define Max7219DIN 7 // Pin 7 connected to DIN (DataIN)
#define Max7219CLK 6 // Pin 6 connected to CLK
#define Max7219CS 5 // Pin 5 connected to CS
#include "LedControl.h" // LedControl Library created by Eberhard Fahle at http://playground.arduino.cc/Main/LedControl
LedControl lc=LedControl(Max7219DIN,Max7219CLK,Max7219CS,1); // Last number represent the number of Max7219 Modules connected 
unsigned long countnumber;
// Variables to store individual numbers
int firstnum=0;
int secondnum=0;
int thirdnum=0;
int fournum=0;
int fivenum=0;
int sixnum=0;
int sevennum=0;
int eightnum=0;
void setup() {
 lc.shutdown(0,false); // Wake up the display
 lc.setIntensity(0,7); // Set Brightness 0-15
 lc.clearDisplay(0); // Clear display
 Serial.begin(9600);
}
void loop() {
 countnumber = millis();
 firstnum = countnumber / 10000000 % 10;
 secondnum = countnumber / 1000000 % 10;
 thirdnum = countnumber / 100000 % 10;
 fournum = countnumber / 10000 % 10;
 fivenum = countnumber / 1000 % 10;
 sixnum = countnumber / 100 % 10;
 sevennum = countnumber / 10 % 10;
 eightnum = countnumber % 10;
 lc.setDigit(0, 7, firstnum, false);
 lc.setDigit(0, 6, secondnum, false);
 lc.setDigit(0, 5, thirdnum, false);
 lc.setDigit(0, 4, fournum, false);
 lc.setDigit(0, 3, fivenum, false);
 lc.setDigit(0, 2, sixnum, false);
 lc.setDigit(0, 1, sevennum, false);
 lc.setDigit(0, 0, eightnum, false); 
}
asked Oct 31, 2019 at 4:31
4
  • You code also takes some time to execute. So your loop takes 10ms, plus the time the code takes. To make it 10ms independent of the amount of code, you store the value of millis() at the beginning of the loop, and them at the end of the loop, wait till the difference between millis() and the stored millis value is greater that, or equal to 10. Commented Oct 31, 2019 at 10:20
  • Requiring "1 ms accuracy" doesn't make any sense if you don't specify over what time span you want that accuracy. Getting 1 ms accuracy is trivial if you are measuring a 100 ms time interval. It is far from trivial if you are measuring a 1 year interval. The accuracy you can get on an Arduino out of the box depends on the measured interval, on whether your Arduino has a crystal or a resonator, and on whether you are willing to calibrate it. Please read jorisvr.nl/article/arduino-frequency to get a general idea on what "accuracy" can mean in respect to Arduino timing. Commented Oct 31, 2019 at 11:07
  • @EdgarBonet what about over 5min trivial or no? Commented Oct 31, 2019 at 21:19
  • 1 ms ÷ 5 min = 3.33 ppm. Not trivial but doable. You won't get that accuracy out of the Arduino's internal clock unless it is a crystal and you calibrate it against a reliable reference. Easiest solution would probably be using a high accuracy RTC, like the DS3231, which integrates a temperature-compensated crystal oscillator (TCXO). The ubiquitous DS1307 will likely not be accurate enough. Use either the 32kHz or the SQW output and one of your MCU's counters. Please, tag your question with the type of Arduino you are using. Commented Oct 31, 2019 at 23:01

1 Answer 1

1

You generally cannot rely on a processor for correct time keeping without a real time clock somewhere in your circuit. However, the best way of doing things at certain times, is to call millis() which will return the number of milliseconds since the program started. With that number you can determine how long something has taken (eg. 1 second) and then do something in response. You can, for example, print out how long your loop is taking by setting a long integer to millis() at the start of the sketch and then subtracting it from mills() at the end of the loop and printing out the result.

void loop() {
 long start_time = millis();
 delay(500);
 long end_time = mills();
 Serial.println(end_time - start_time);
}
answered Oct 31, 2019 at 5:18
3
  • What do you rekon is the accuracy without real time clock? within 20ms? Commented Oct 31, 2019 at 7:21
  • 1
    From this article I understand that millis is incremented each 1.024ms, but if the error approaches 1ms then value is automatically corrected. Therefore in span of 20 ms error could accumulate to be close to half of a millisecond. Commented Oct 31, 2019 at 7:47
  • 1
    @bakalolo Try micros()? Commented Oct 31, 2019 at 8:36

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.