Stopwatch using a 32 x 8 LED Matrix

I have adapted a sketch for a stopwatch using an I2C 16 x 2 LCD display but would like something bigger. I thought about a 32 x 8 LED matrix but can't find a sketch for a stopwatch. Has anyone done this already, or can anyone offer any help as to how to display a stopwatch on an LED matrix.

Any help would be much appreciated.

yes. Was done before:
a stopwatch to measure your reaction time: https://www.youtube.com/watch?v=Rq5XmUibkHU

Thanks for your reply, it's good to know that it has been done, I am hoping that someone can help with the programming to get the stopwatch working.

If a user is asking for pretty general help I look up his profile.

Joined in 2018, 1h read time, 25 topics created.
hm well my assumption is that you seem to be on a very basic level about programming-knowledge.

like any program a stop-watch has multiple functional parts
where each functional part can be coded on its own and then can be combined with other parts.

You wrote

Does this mean you have a stop-watch that displays the time on a 16 x 2 LCD up and running?

If yes: The next step is to write a test-program for the 32x8 LED-matrix.

If the test-program for the 32 x 8 LED-Matrix is running
the next step is to integrate the "display digits on 32 x 8 LED-Matrix-functionality in your stop-watch-code.

The propablity that there exists a library for 32 x 8 LED-matrix is pretty high.

From your former 25 threads with 64 posts you should now that it is essential to post a link to the datasheets of the components that you use.

As soon as you start to give more detailed informations the better the support will be.

best regards Stefan

Stefan,
Thank you for your reply and thank you for taking the time to look at my profile. Yes I have a stopwatch sketch up and running for a 16 x 2 LCD but have not yet purchased the 32 x 8 LED matrix as I didn't want to spend the money if I couldn't get it working.

I don't get a lot of time on Arduino, so yes my knowledge is limited. I will see about ordering what I need, get it tested and take it from there.
Steve

I have purchased an 8 x 32 LED MAX7219 matrix and have connected it up and can get it to display text no problem.

I have adapted a stopwatch sketch that works fine on a 16 x 2 LCD display. However when I connect up the LED matrix, it will only display two columns on the LHS of the display. Can anyone help me to get minutes, seconds and milliseconds to display on the LED Matrix. See below the code that I used.

/*
  Stopwatch
  Run stopwatch with arduino.
  
  Code based on: http://danthompsonsblog.blogspot.com/2008/11/timecode-based-stopwatch.html
  Coded by: arduinoprojects101.com
*/

// include the library code:

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

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4

#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    3

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary output pins

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



//int ledPin = 13;                    // LED connected to digital pin 13
int buttonPin = 2;                  // button on pin 2

int value = LOW;                    // previous value of the LED
int buttonState;                    // variable to store button state
int lastButtonState;                // variable to store last button state
int blinking;                       // condition for blinking - timer is timing
int frameRate = 100;                // the frame rate (frames per second) at which the stopwatch runs - Change to suit
long interval = (1000/frameRate);   // blink interval
long previousMillis = 0;            // variable to store last time LED was updated
long startTime;                     // start time for stop watch
long elapsedTime;                   // elapsed time for stop watch
int fractional;                     // variable used to store fractional part of Frames
int fractionalSecs;                 // variable used to store fractional part of Seconds
int fractionalMins;                 // variable used to store fractional part of Minutes
int elapsedFrames;                  // elapsed frames for stop watch
int elapsedSeconds;                 // elapsed seconds for stop watch
int elapsedMinutes;                 // elapsed Minutes for stop watch
char buf[10];                       // string buffer for itoa function

void setup()
{
  P.begin();                // intialise the LED Matrix.
  //P.clear();
  P.print("Test!");
  delay (2000);
  //pinMode(ledPin, OUTPUT);         // sets the digital pin as output
  pinMode(buttonPin, INPUT);       // not really necessary, pins default to INPUT anyway
  digitalWrite(buttonPin, HIGH);   // turn on pullup resistors. Wire button so that press shorts pin to ground.
}

void loop(){
  //digitalWrite(ledPin, LOW);            // Initiate LED and Step Pin States

  buttonState = digitalRead(buttonPin); // Check for button press, read the button state and store

// check for a high to low transition if true then found a new button press while clock is not running - start the clock    
   if (buttonState == LOW && lastButtonState == HIGH  &&  blinking == false){
    startTime = millis();                               // store the start time
      blinking = true;                                  // turn on blinking while timing
      delay(10);                                         // short delay to debounce switch
      lastButtonState = buttonState;                    // store buttonState in lastButtonState, to compare next time 
   }

// check for a high to low transition if true then found a new button press while clock is running - stop the clock and report
   else if (buttonState == LOW && lastButtonState == HIGH && blinking == true){
   blinking = false;                                    // turn off blinking, all done timing
   lastButtonState = buttonState;                       // store buttonState in lastButtonState, to compare next time

// Routine to report elapsed time            
   elapsedTime =   millis() - startTime;                // store elapsed time
   elapsedMinutes = (elapsedTime / 60000L);
   elapsedSeconds = (elapsedTime / 1000L);              // divide by 1000 to convert to seconds - then cast to an int to print
   elapsedFrames = (elapsedTime / interval);            // divide by 100 to convert to 1/100 of a second - then cast to an int to print
   fractional = (int)(elapsedFrames % frameRate);       // use modulo operator to get fractional part of 100 Seconds
   fractionalSecs = (int)(elapsedSeconds % 60L);        // use modulo operator to get fractional part of 60 Seconds
   fractionalMins = (int)(elapsedMinutes % 60L);        // use modulo operator to get fractional part of 60 Minutes
   //P.clear();                                         // clear the LDC

 if (fractionalMins < 10){                            // pad in leading zeros
      P.print("0");                                   // add a zero
      }

    P.print(itoa(fractionalMins, buf, 10));       // convert the int to a string and print a fractional part of 60 Minutes to the LCD
      P.print(":");                                 //print a colan. 

 if (fractionalSecs < 10){                            // pad in leading zeros
      P.print("0");                                 // add a zero
      }

 P.print(itoa(fractionalSecs, buf, 10));          // convert the int to a string and print a fractional part of 60 Seconds to the LCD
   P.print(":");                                    //print a colan. 

 if (fractional < 10){                                // pad in leading zeros 
      P.print("0");                                 // add a zero
      }     

 P.print(itoa(fractional, buf, 10));              // convert the int to a string and print a fractional part of 25 Frames to the LCD
   }

 else{
      lastButtonState = buttonState;                  // store buttonState in lastButtonState, to compare next time
   }

// run commands at the specified time interval
// blink routine - blink the LED while timing
// check to see if it's time to blink the LED; that is, the difference
// between the current time and last time we blinked the LED is larger than
// the interval at which we want to blink the LED.

 if ( (millis() - previousMillis > interval) ) {

    if (blinking == true){
       previousMillis = millis();                    // remember the last time we blinked the LED

       //digitalWrite(ledPin, HIGH);                   // Pulse the LED for Visual Feedback

       elapsedTime =   millis() - startTime;         // store elapsed time
         elapsedMinutes = (elapsedTime / 60000L);      // divide by 60000 to convert to minutes - then cast to an int to print
         elapsedSeconds = (elapsedTime / 1000L);       // divide by 1000 to convert to seconds - then cast to an int to print
         elapsedFrames = (elapsedTime / interval);     // divide by 40 to convert to 1/25 of a second - then cast to an int to print
         fractional = (int)(elapsedFrames % frameRate);// use modulo operator to get fractional part of 25 Frames
         fractionalSecs = (int)(elapsedSeconds % 60L); // use modulo operator to get fractional part of 60 Seconds
         fractionalMins = (int)(elapsedMinutes % 60L); // use modulo operator to get fractional part of 60 Minutes
         //P.clear();                                  // clear the LDC

       if (fractionalMins < 10){                     // pad in leading zeros
         P.print("0");                             // add a zero
         }

       P.print(itoa(fractionalMins, buf, 10));   // convert the int to a string and print a fractional part of 60 Minutes to the LCD
         P.print(":");                             //print a colan. 

       if (fractionalSecs < 10){                     // pad in leading zeros 
         P.print("0");                             // add a zero
         }

       P.print(itoa(fractionalSecs, buf, 10));   // convert the int to a string and print a fractional part of 60 Seconds to the LCD
         P.print(":");                             //print a colan. 

       if (fractional < 10){                         // pad in leading zeros 
         P.print("0");                             // add a zero
         }
          P.print(itoa((fractional), buf, 10));  // convert the int to a string and print a fractional part of 25 Frames to the LCD
         }

    else{
          //digitalWrite(ledPin, LOW);                 // turn off LED when not blinking 
          }
 }

}

You should take two an intermediate steps:

Does a demo-code show any numbers on your LED-marix at all?
This is for cross-checking:

if you have the hardware wired the correct way.
if calling the functions of the LED-Marix-library is working in principle.

The more lines of code you put into a test the more factors can be the bug and the number of possabilities rises exponentially
best regards Stefan

Thanks for getting back to me Stefan, when I load the sketch, then press the button to start, the count counts up very quickly ( I assume it's the milliseconds). When I press the button to stop the count, I get two digits showing at the left hand side of the LED matrix. I have tried other sample codes and the LED matrix is fully functional.

Best regards
Steve

From what I can glean, I need to change the variables to strings then print the strings but I cannot print multiple strings in a single command in MD_Parola and if I print them separately, the screen clears before each command.

Hi Steve,

I can't see your LED matrix. So from this discription i'm unsure what you see on the LED-Matrix.
Just post what you expect to see as digits
and post what you is shown by the LED-matrix.

If you replace the itoa-functions by different fixed strings what do you see then?

It might be that each p.print starts printing new at the left most digit.
Just for debugging purposes to find out about this
the function delay() could be used (one of the rare cases where delay() is handy to use)

If you insert a delay(2000);
after each p.print this does what the name says
delay program-execution for 2000 milliseconds. which in this case means
show LED-matrix for two seconds after each print instead run through all p.prints

If this is the case the solution is to concenate all numbers into one string and do only one p.print

Me personal I prefer using the SafeString-library because it makes handling with strings easier. You smple assign bytes, integers, longs and even float-variables to the safestring by writing "=" or concenating them by "+="

here is a demo-code how safestrings can be used.
The demo includes some useful functions

#include <SafeString.h>
createSafeString(myDemo_SS, 32);
createSafeString(mySecondDemo_SS, 32);

unsigned long myCounter;

// if program starts printout the source-code filename etc. to the serial monitor
void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println(__FILE__);
  Serial.print( F("  compiled ") );
  Serial.print(__DATE__);
  Serial.print( F(" ") );
  Serial.println(__TIME__);  
}

//useful function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();  
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 13; // Arduino-Uno Onboard-LED is IO-pin 13

// make onboard-LED blink to show: "program is running"
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);
  
  if ( TimePeriodIsOver(MyBlinkTimer,BlinkPeriod) ) {
    digitalWrite(IO_Pin,!digitalRead(IO_Pin) ); 
  }
}



void setup() {
  Serial.begin(115200);
  Serial.println( F("Setup-Start") );
  PrintFileNameDateTime();
  myCounter = 0;
  myDemo_SS = "Hello world!";
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED,500);
  myCounter++;
  
  // loop is running very fast counting up very fast
  // but only once every 1234 milliseconds print 
  if ( TimePeriodIsOver(MyTestTimer,1234) ) {
    mySecondDemo_SS = myDemo_SS;  // assigning a SafeString to another SafeString
    
    mySecondDemo_SS += " ";       // append a SPACE
    mySecondDemo_SS += myCounter; // append integer-number
    Serial.println(mySecondDemo_SS);    
  }  

}

you can install the SafeString-library through the library-manager of the Arduino-IDE
best regards Stefan

Stefan,

Thank you once again for taking the time to answer me, I will need to spend a bit of time trying to get my head around this, as you know my knowledge is limited. I will be away for the next week or so but will try all of your suggestions and see how I get on. What I am trying to achieve is a count up timer readout giving mm:ss:msmsms ie 00:00:000 then counting up, what I see is for example 56 in the left hand two columns and these are milliseconds. The digits are full size also, i will need to create smaller numbers.

Best regards
Steve

if you have your arduino-IDE handy
do a quick modification with how you think adding the delay() works and post the modified code again.

best regards Stefan

I will see what I can do.

Best regards
Steve

Parola will print the c-string you pass it. If you give it another string, you will clear the previous one and display the new one. This is something you have already discovered.

So you need to build up your message in the c-string and the display the complete message instead of doing a sequence of .print statements. I would suggest that you learn about the sprintf() function. Something like

char charBuffer[sizeOfBuffer];

sprintf(charBuffer, "%02d:%02d:%02d", hourVariable, minuteVariable, secondVariable);

is what you need to get to. This will print the time in hh:mm:ss with leading zeros on the digits. If you read the documentation for sprintf it will make sense.

You can then .print charBuffer or use one of the animations.

Thank you Marco I will look at that.

Stefan,

I have managed to get the display operating the way I want using SafeString, the only issue is that the font is too wide! Is it possible to get a smaller font to display? I tried searching and I did find something but was not sure how to install it! It had a file SmallDigits.h from Max Banton but I don't know what to do with it. Thank you for your assistance in getting me this far, it is very much appreciated.

Best regards

Steve

Hi Steve,

the general way to lookup such things is to do a google-search
using the word GitHub and the keyword for what you are looking for
You found

after that lookup
the examples of the main thing
In your case MD_Parola and there the example-codes

and there is an example Parola fonts

which has a demo-code and a demo-font-file
This example will guide you on how to use your small fonts.

That's what I did in the last 15 minutes.

If you have specific questions then write a posting that provides

direct links to all

the files that you looked at

You are the one that wants help so make it as easy as possible for other users to look up aditional information.

best regards Stefan

I tried to include Parola_Fonts_data.h but it would not compile yet the file is there when I open up the Parola Fonts example sketch.

My thoughts were to copy the SmallDigits code into the Parola_Fonts_data.h and then type in
MD_MAX79XX::fontType_t SmallDigits

Do I then need to set the font using P.setFont(SmallDigits); ?

It doesn't like the #include<Parola_Font_data.h> line so cannot go any further! The error reads "Error compiling for board Arduino Uno"

Not sure what the next step would be? As always any assistance will be much appreciated.

Steve

Hi Steve,

Did you install the library?

You should adjust compiler-warnings to "all" and show verbose output during compilation

in the preferences
grafik

If you have compiled and the compiler aborted with an error-message

  • click into this IDE-message-window with the error-message
  • press Ctrl-A for marking all all messages
  • press Ctrl-C for copying the marked messages into the clipboard
  • change to posting
  • click on the </>-Icon
  • press Ctrl-V to insert clipboard-content into the code-section.

If you have enabled all compiler-warnings and verbose output all details that might be important will be in the messages.

Yes you have to set the font by calling P.setFont(NameofTheFont);

You have to take a careful look at this name in the example-sketch

best regards Stefan

Stefan,

I have installed the MD_Parola library, one of the example sketches, Parola_Fonts, has the Parola_Fonts_data.h file attached. I did a search for Parola Fonts Library but nothing turned up in the manage libraries option. Is there a separate Parola_Fonts library?

Best regards

Steve