I have this program that is meant to measure elapsed time and print it on the TFT lcd screen.
The UNO im using for this gets a 5v input pulse (straight cable) from a MEGA when its "time to start and to stop" measuring.
The input signal is defined as "buttonPin" in the sketch. Not logical at all. I know.
Anyways,
I need help understanding why this sketch only runs once and doesnt loop.
Im new to C++ so I problably missed out on something.
Tried your options guys. Thanks, but didnt work for me.
But I tried commenting out everything that interacts with the LCD.
Then the code runs fine and I can se the stopwatch update in serial monitor.
Is jumping between loops not good?
Is the way im calling for loops the wrong way to go?
The things you have named showtimeloop() and norgipsloop() are not loops - they are functions. And there is no repetitive code in them.
I suspect you need to stop using delay() for timing and use millis() instead as illustrated in several things at a time.
And I still think the advice I gave in Reply #6 needs careful consideration after you have dealt with the delay()s.
As you will see in several things, functions are a very good idea
dravinci:
The input signal is defined as "buttonPin" in the sketch. Not logical at all. I know.
For interactive programs that need quick reactions all blocking functions like "delay()" are absolutely forbidden functions in your sketch.
First rule: Never use "delay()" in any interactive program!
Or if you do, the sum of all delay() calls while running once through the loop() function may not exceed the maximum response time.
So if you want to code a stopwatch which reacts within 0.01 seconds (10ms) on a button press, the sum of all delay() calls may not exceed 10ms.
And if you want to code a stopwatch which reacts within 0.001 seconds (1ms) on a button press, the sum of all delay() calls may not exceed 1ms.
So you better use NOT ANY delay in your program!
For me, a good structure of any Arduino program is a loop function that looks like that:
void loop()
{
input();
processing();
output();
}
It consists of three functions that logically seperates three steps almost any program would need to handle:
input() ==> reads buttons, encoders, sensors and store values in variables
processing() ==> processes input variables to a logical output state / output variables
output() ==> sending the output state / output variables to somewhere in the world outside the Arduino
Do you need some demo code for a stopwatch?
Is it a stopwatch with two buttons (one button START/STOP and one button RESET)?
Or do you want all three functions START/STOP and RESET to be handled with just a single button?
jurs:
For interactive programs that need quick reactions all blocking functions like "delay()" are absolutely forbidden functions in your sketch.
First rule: Never use "delay()" in any interactive program!
Or if you do, the sum of all delay() calls while running once through the loop() function may not exceed the maximum response time.
So if you want to code a stopwatch which reacts within 0.01 seconds (10ms) on a button press, the sum of all delay() calls may not exceed 10ms.
And if you want to code a stopwatch which reacts within 0.001 seconds (1ms) on a button press, the sum of all delay() calls may not exceed 1ms.
So you better use NOT ANY delay in your program!
For me, a good structure of any Arduino program is a loop function that looks like that:
void loop()
{
input();
processing();
output();
}
It consists of three functions that logically seperates three steps almost any program would need to handle:
input() ==> reads buttons, encoders, sensors and store values in variables
processing() ==> processes input variables to a logical output state / output variables
output() ==> sending the output state / output variables to somewhere in the world outside the Arduino
Do you need some demo code for a stopwatch?
Is it a stopwatch with two buttons (one button START/STOP and one button RESET)?
Or do you want all three functions START/STOP and RESET to be handled with just a single button?
Thats some good tips! Thank you!
I dont want a button to reset. I want a function to reset a couple of seconds after it has shown the result on the LCD.
Robin2:
The things you have named showtimeloop() and norgipsloop() are not loops - they are functions. And there is no repetitive code in them.
I suspect you need to stop using delay() for timing and use millis() instead as illustrated in several things at a time.
And I still think the advice I gave in Reply #6 needs careful consideration after you have dealt with the delay()s.
As you will see in several things, functions are a very good idea
...R
Aha. Good to know
But these functions only run once right? When I tell them to?
And after that it starts over with the "void loop" right?
Try putting a Serial.print("Running loop"); as the very first command in the loop function. That will let you know it is at least turning over.
Now I feel kinda stupid.....
You are right about those 11 seconds.
The Mega starts the loop, for the second time, to early. Offcourse it has to wait for that "showtimeloop"-function to finish or the timer will be out of sync.
dravinci:
I dont want a button to reset. I want a function to reset a couple of seconds after it has shown the result on the LCD.
Hope that makes sence to you.
Here is a complete demo code for a stopwatch with just one button.
After stopping the time it will automatically reset to "WAITFORSTART" after 10 seconds.
All output is currently sent to Serial, but this can easily be changed as you only need to do some changes to the "output()" function.
Time formatting is like that:
while stopwatch is running ==> shows minutes and seconds, updated each second
when stopwatch is stopped ==> shows minutes, seconds and milliseconds of final time
Hope this helps.
#define INPUTMODE INPUT_PULLUP // INPUT or INPUT_PULLUP
#define BUTTONPIN 2
typedef enum {WAITFORSTART, RUNNING, STOPPED} watchMode_t;
watchMode_t watchMode=WAITFORSTART;
boolean buttonPressed;
unsigned long startMillis, stopMillis;
long watchTime;
void setup(){
Serial.begin(9600);
pinMode(BUTTONPIN, INPUTMODE);
showTime(watchTime,false);
}
void input()
{
static byte oldState;
buttonPressed=false;
byte state=digitalRead(BUTTONPIN);
if (INPUTMODE==INPUT_PULLUP) state=!state;
if (state!=oldState)
{
if (state==HIGH) buttonPressed=true;
oldState=state;
}
}
void showTime(long time, boolean withMillis)
{
char textbuf[21];
int milliseconds=time%1000;
time=time/1000;
int minutes=time/60;
int seconds=time%60;
if (withMillis)
snprintf(textbuf,sizeof(textbuf),"%3d:%02d,%03d",minutes,seconds,milliseconds);
else
snprintf(textbuf,sizeof(textbuf),"%3d:%02d ",minutes,seconds);
Serial.println(textbuf);
}
void processing()
{
if (buttonPressed && watchMode==WAITFORSTART)
{
watchMode=RUNNING;
startMillis=millis();
watchTime=0;
}
else if (buttonPressed && watchMode==RUNNING && watchTime>1000)
{
watchMode=STOPPED;
watchTime=millis()-startMillis;
stopMillis=millis();
}
else if (watchMode==STOPPED)
{
if (millis()-stopMillis>10000L)
{
watchMode=WAITFORSTART;
watchTime=0;
buttonPressed=false;
}
}
else if (watchMode==RUNNING)
{
watchTime=millis()-startMillis;
}
}
void output()
{
char textbuf[21];
static watchMode_t lastMode;
static int lastSeconds;
byte minutes, seconds;
if (lastMode!=watchMode) // mode changed?
{
lastMode=watchMode;
switch (watchMode)
{
case WAITFORSTART:
Serial.println("Waiting for start");
break;
case RUNNING:
Serial.println("Watch is running");
break;
case STOPPED:
Serial.println("Watch is stopped");
Serial.print("Final time: ");
showTime(watchTime,true);
break;
}
}
else if (watchMode==RUNNING)
{
if (watchTime/1000 != lastSeconds)
{
lastSeconds=watchTime/1000;
showTime(watchTime,false);
}
}
}
void loop()
{
input();
processing();
output();
}
To prevent wrong timing of milliseconds because of button debouncing, the debouncing is handled like that:
on first state change "button pressed" the clock will start
clock cannot be stopped during the first second ("long debouncing")
on next state change "button pressed" the clock will stop
So timing should be as accurate as the 16 MHz frequency of your Arduino board.