I developed and adapted this sketch with valuable help from forum members so that when switched on the message would read "Start!". I thought I would try a father adaptation to display a scrolling message while waiting for the start button to be pressed. I have tried "while" and the "do while" and the scrolling message appears but nothing happens when the start button is pressed, the message just keeps scrolling. Not sure if it is where I have placed the "do while" although I did try a couple of places, and I have tried it using startbuttonPin and start buttonState. I am obviously missing something can anyone spot my error(s) and point me in the right direction. As always, any help would be much appreciated.
// Scrolling Message Stopwatch
// include the library code:
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include "SmallDigits.h"
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4 // Number of 8 x 8 LED Matrix Modules used
#define DATA_PIN 11 // Pin for Arduino Nano 11
#define CS_PIN 3 // Pin for Arduino Nano 3
#define CLK_PIN 13 // Pin for Arduino Nano 13
// 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 startbuttonPin = 2; // start button on pin 2
int stopbuttonPin = 4; // stop button on pin 4
int startbuttonState; // variable to store button state
int stopbuttonState; // variable to store button state
int laststartButtonState; // variable to store last button state
int laststopButtonState; // 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
uint32_t interval = (1000/frameRate); // blink interval
uint32_t previousMillis = 0; // variable to store last time LED was updated
uint32_t startTime; // start time for stop watch
uint32_t 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
uint32_t elapsedFrames; // elapsed frames for stop watch
uint32_t elapsedSeconds; // elapsed seconds for stop watch
uint32_t elapsedMinutes; // elapsed Minutes for stop watch
char buff[10]; // a buffer that will contain the string to be displayed
uint8_t scrollSpeed = 25; // default frame delay value
textEffect_t scrollEffect = PA_SCROLL_LEFT;
textPosition_t scrollAlign = PA_LEFT;
uint16_t scrollPause = 2000; // in milliseconds
#define BUF_SIZE 100
char curMessage[BUF_SIZE] = { "" };
char newMessage[BUF_SIZE] = { "If you are ready to begin, press the start button!" };
bool newMessageAvailable = true;
void setup()
{
Serial.begin(57600);
P.begin(); // intialise the LED Matrix.
P.setIntensity(5); // Set LED Matrix Brightness
//P.print("Start!");
P.displayText(curMessage, scrollAlign, scrollSpeed, scrollPause, scrollEffect, scrollEffect); // print opening message
//P.setFont(SmallDigits);
pinMode(startbuttonPin, INPUT); // not really necessary, pins default to INPUT anyway
pinMode(stopbuttonPin, INPUT); // not really necessary, pins default to INPUT anyway
digitalWrite(startbuttonPin, HIGH); // turn on pullup resistors. Wire button so that press shorts pin to ground.
digitalWrite(stopbuttonPin, HIGH); // turn on pullup resistors. Wire button so that press shorts pin to ground.
}
void loop(){
do {
CallScrolling();
}
while (startbuttonState = HIGH);
startbuttonState = digitalRead(startbuttonPin); // Check for button press, read the button state and store
stopbuttonState = digitalRead(stopbuttonPin); // 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 (startbuttonState == LOW && laststartButtonState == HIGH && blinking == false){
startTime = millis(); // store the start time
blinking = true; // turn on blinking while timing
delay(10); // short delay to debounce switch
laststartButtonState = startbuttonState; // 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 (stopbuttonState == LOW && laststopButtonState == HIGH && blinking == true){
blinking = false; // turn off blinking, all done timing
laststopButtonState = stopbuttonState; // store buttonState in lastButtonState, to compare next time
// Routine to report elapsed time
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 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.setFont(SmallDigits);
sprintf(buff, "%2d:%02d.%02d", fractionalMins, fractionalSecs, fractional);
P.print(buff);
delay(10);
}
else{
laststartButtonState = startbuttonState; // store buttonState in lastButtonState, to compare next time
laststopButtonState = stopbuttonState; // 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
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.setFont(SmallDigits);
sprintf(buff, "%2d:%02d.%02d", fractionalMins, fractionalSecs, fractional);
P.print(buff);
delay(10);
}
}
}
void CallScrolling(){
if (P.displayAnimate())
{
if (newMessageAvailable)
{
strcpy(curMessage, newMessage);
newMessageAvailable = false;
}
P.displayReset();
}
}
You need to place the read of the button inside the loop, otherwise startbuttonState cannot change. And you need to learn to use == for comparison, not =
Thank you for taking the time to reply, I have put a digitalRead statement inside the loop and the timer starts fine. However when I press the stop button, the display goes blank rather than displaying the finish time and I cannot see why this is happening. I have taken on board the == instead of the =.
void loop(){
do {
CallScrolling();
digitalRead(startbuttonPin); // **This was the only change I made to the code**
}
while (startbuttonPin == HIGH);
startbuttonState = digitalRead(startbuttonPin); // Check for button press, read the button state and store
stopbuttonState = digitalRead(stopbuttonPin); // Check for button press, read the button state and store
Thank you for your replies and please excuse my inexperience. I am not quite sure what you mean, the pin is set to HIGH and is waiting for a button press, making it LOW, is that not what I should be doing? The start button part is now working though, will this affect the stop button part of the code.
startbuttonPin is a number, the number of the pin, absolutely nothing to do with the state of the pin itself, it just names the pin. HIGH is an alias for the number 1, so your loop is waiting for the pin number to magically change to 1, which it won't as the variable isn't being changing in the (empty) loop body.
Perhaps you meant:
while (digitalRead(startbuttonPin) == HIGH)
{}
This reads the pin each time round the loop. Unless you call digitalRead your program isn't looking at the pin itself at all.
BTW this is an example of blocking code (the processor is jammed waiting for the pin to change and can't do other stuff). Often this leads to problems.
I have changed to a "while" loop and used your suggestion. If I contain all of the void loop code within the while loop, the scrolling message displays then when the start button is pressed, the timer begins displaying the increasing time. When I press the stop button the display goes blank rather than displaying the time when the stop button was pressed. Something is stopping the stop time being displayed, I must still be blocking but can't see where. I did try excluding the last part of the code which displays the stop time from the while loop but that made it worse.
// Scrolling Message Stopwatch
// include the library code:
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include "SmallDigits.h"
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4 // Number of 8 x 8 LED Matrix Modules used
#define DATA_PIN 11 // Pin for Arduino Nano 11
#define CS_PIN 3 // Pin for Arduino Nano 3
#define CLK_PIN 13 // Pin for Arduino Nano 13
// 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 startbuttonPin = 2; // start button on pin 2
int stopbuttonPin = 4; // stop button on pin 4
int startbuttonState; // variable to store button state
int stopbuttonState; // variable to store button state
int laststartButtonState; // variable to store last button state
int laststopButtonState; // 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
uint32_t interval = (1000/frameRate); // blink interval
uint32_t previousMillis = 0; // variable to store last time LED was updated
uint32_t startTime; // start time for stop watch
uint32_t 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
uint32_t elapsedFrames; // elapsed frames for stop watch
uint32_t elapsedSeconds; // elapsed seconds for stop watch
uint32_t elapsedMinutes; // elapsed Minutes for stop watch
char buff[10]; // a buffer that will contain the string to be displayed
uint8_t scrollSpeed = 25; // default frame delay value
textEffect_t scrollEffect = PA_SCROLL_LEFT;
textPosition_t scrollAlign = PA_LEFT;
uint16_t scrollPause = 2000; // in milliseconds
#define BUF_SIZE 100
char curMessage[BUF_SIZE] = { "" };
char newMessage[BUF_SIZE] = { "If you are ready to begin, press the start button!" };
bool newMessageAvailable = true;
void setup()
{
Serial.begin(57600);
P.begin(); // intialise the LED Matrix.
P.setIntensity(5); // Set LED Matrix Brightness
//P.print("Start!");
P.displayText(curMessage, scrollAlign, scrollSpeed, scrollPause, scrollEffect, scrollEffect); // print opening message
//P.setFont(SmallDigits);
pinMode(startbuttonPin, INPUT); // not really necessary, pins default to INPUT anyway
pinMode(stopbuttonPin, INPUT); // not really necessary, pins default to INPUT anyway
digitalWrite(startbuttonPin, HIGH); // turn on pullup resistors. Wire button so that press shorts pin to ground.
digitalWrite(stopbuttonPin, HIGH); // turn on pullup resistors. Wire button so that press shorts pin to ground.
}
void loop(){
/*do {
CallScrolling();
digitalRead(startbuttonPin);
startbuttonState = digitalRead(startbuttonPin);
//digitalRead(stopbuttonPin);
}
while (startbuttonState == HIGH);
*/
while(digitalRead(startbuttonPin) == HIGH)
{
CallScrolling();
startbuttonState = digitalRead(startbuttonPin); // Check for button press, read the button state and store
stopbuttonState = digitalRead(stopbuttonPin); // 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 (startbuttonState == LOW && laststartButtonState == HIGH && blinking == false){
startTime = millis(); // store the start time
blinking = true; // turn on blinking while timing
delay(10); // short delay to debounce switch
laststartButtonState = startbuttonState; // 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 (stopbuttonState == LOW && laststopButtonState == HIGH && blinking == true){
blinking = false; // turn off blinking, all done timing
laststopButtonState = stopbuttonState; // store buttonState in lastButtonState, to compare next time
// Routine to report elapsed time
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 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.setFont(SmallDigits);
sprintf(buff, "%2d:%02d.%02d", fractionalMins, fractionalSecs, fractional);
P.print(buff);
delay(10);
}
else{
laststartButtonState = startbuttonState; // store buttonState in lastButtonState, to compare next time
laststopButtonState = stopbuttonState; // 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
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.setFont(SmallDigits);
sprintf(buff, "%2d:%02d.%02d", fractionalMins, fractionalSecs, fractional);
P.print(buff);
delay(10);
}
}
}
}
void CallScrolling(){
if (P.displayAnimate())
{
if (newMessageAvailable)
{
strcpy(curMessage, newMessage);
newMessageAvailable = false;
}
P.displayReset();
}
}
Thank you for your reply, both work to the same extent, the problem is that when the stop button is pressed the display goes blank rather than displaying the stop time!
I was under the impression that I was giving pin 2 the label startbuttonPin and that while (startbuttonPin == HIGH) was was talking about the state of the pin, not the number!
So when the button is pressed it will read as LOW.
This allows the timer to start and this displays on the LED matrix as it should. When the stop button is pressed, it should stop the timer and display the finish time but the display goes blank. I works fine without the scrolling message element in the code. It looks like the stop button does stop the timer, it just does not display the time!
Prior to adding the scrolling message part, when the stop button was pressed, the time would be displayed until the start button was pressed again or the program was reset. Now having looked at the results on the serial monitor, I can see that the stop time is there but only displays for 10ms hence the blank display. By increasing the delay I can see the time on the LED Matrix, so the while loop is causing this issue, just need to figure out a way around this.