Hi,
I'm new here and to arduino, so forgive any mistakes.
I'm making a stopwatch. It counts milliseconds, seconds and minutes and is supposed to have to buttons. One reset button and one start/stop button. Everything here works with the exception of the start/stop button. I have managed to make it a start button, but not a stop button. To be clear, pressing the button is supposed to start the clock, and pressing it again is supposed to stop it, without resetting the time. Even better if the time is showing even when it's stopped, so that it doesn't disappear until started.
Here is the code. Sorry if it's messy or amateur-ish. I'm doing my best. I believe the problem lies in the void loop().
#include <LiquidCrystal.h>
LiquidCrystal LCD(12, 11, 5, 4, 3, 2);
long int msec=0;
int sec=0;
int minutes=0;
int period = 99;
unsigned long time_now = 0;
unsigned long time_pre= 0;
int button = 8;
int resetbutton = 9;
boolean oldButtonState = LOW;
boolean newButtonState = LOW;
void setup(){
LCD.begin(16, 2);
pinMode(button, INPUT);
pinMode(resetbutton, INPUT);
}
void loop(){
newButtonState = digitalRead(button);
LCD.setCursor(0,1);
LCD.print("00:00:00"); //startscreen
while (newButtonState != oldButtonState)){
timer();
timershow();
reset();
}}
void reset(){ //set the clock to 0
if (digitalRead(resetbutton)){ //reset-knapp
msec=0;
sec=0;
minutes=0;
newButtonState = oldButtonState;
}}
void timer(){ //counting millisecounds, secounds and minutes
time_now = millis();
if (time_now-time_pre > period){
time_pre=time_now;
msec ++;
if (msec>9){
msec=0; //når det er flere enn 10 millisekunder går den tilbake til 0
sec++; //deretter øker sekunder med 1
}
if (sec>59) //flere enn 59 sekunder, gir 1 min og 0sekunder
{minutes++;
sec=0;
}}
}
void timershow(){ //printing time to LCD
LCD.setCursor(0,1);
{
if(minutes<10){
LCD.print("0");
LCD.print(minutes);
}
else{
LCD.print(minutes);
}}
LCD.print(":");
{
if(sec<10){
LCD.print("0");
LCD.print(sec);
LCD.print(":");
}
else{
LCD.print(sec);
LCD.print(":");
}}
{
if(msec<10){
LCD.print("0");
LCD.print(msec);
}
else{
LCD.print(msec);
}}}
Thank you for taking the time to read and/or help me.<3
I take it when button is a 1 the timer is supposed to run and there is code for when the button is a 1 but where is the code if button is a 0?
void()
{
if( digitalRead(button) )
{
DoTheOneThing;
} else {
DoTheOtherThing;
}
}
And this is redundant
void loop()
{
while (newButtonState != oldButtonState)){
}
}
loop() is one loop and the while is a nested loop.
Idahowalker:
I take it when button is a 1 the timer is supposed to run and there is code for when the button is a 1 but where is the code if button is a 0?
I used a while loop, so I hoped it would run while the button states where different, and stop running when they weren't. Then maybe put the reset-function outside the while loop so that you can reset it when the clock isn't ticking. My logic might be totally off, though.
A guy said I should use an if loop in stead, but when I do that the clock only works when I hold the button down and it goes on and off super fast.
akinear:
To be clear, pressing the button is supposed to start the clock, and pressing it again is supposed to stop it, without resetting the time. Even better if the time is showing even when it's stopped, so that it doesn't disappear until started.
Are your buttons active HIGH or LOW? Since you are configuring them without the built-in pullup do you have a pull-up or pull-down in your circuit?
I assume you want to press/release the button to start the timer and press/release to stop the timer. If so then you need to check for a button OFF to ON transition and use a flag to track the running/stopped state. Keep in mind you will also need to "debounce" the buttons otherwise multiple transitions on the bounce will mess up your logic. I would suggest something like this:
#include <LiquidCrystal.h>
LiquidCrystal LCD(12, 11, 5, 4, 3, 2);
long int msec = 0;
int sec = 0;
int minutes = 0;
int period = 99;
unsigned long time_now = 0;
unsigned long time_pre = 0;
const int button = 8;
const int resetbutton = 9;
byte oldButtonState = LOW;
byte oldResetButtonState = LOW;
boolean running = false;
void setup() {
LCD.begin(16, 2);
pinMode(button, INPUT);
pinMode(resetbutton, INPUT);
LCD.setCursor(0, 1);
LCD.print("00:00:00"); //startscreen
}
void loop() {
byte newButtonState;
byte newResetButtonState;
//
// Process reset button
//
newResetButtonState = digitalRead(resetbutton);
// LOW to HIGH transition means button is pressed assuming active HIGH button
if (newResetButtonState == HIGH && oldResetButtonState == LOW)
{
delay(50); // quick and dirty debounce: wait for bouncing to stop
// TBD: reset clock logic
}
oldResetButtonState = newResetButtonState;
//
// Process start/stop button
//
newButtonState = digitalRead(button);
// LOW to HIGH transition means button is pressed assuming active HIGH button
if (newButtonState == HIGH && oldButtonState == LOW)
{
delay(50); // quick and dirty debounce: wait for bouncing to stop
if (running)
{
// TBD: stop clock logic
running = false;
}
else
{
// TBD: start clock logic
running = true;
}
}
oldButtonState = newButtonState;
}
Yes, active is HIGH (I think). At least something is happening when I tried out your suggestion. Not what I wanted, though. I'm trying to put it together..
Here's the loop now. When I press the start/stop button now it just goes up one ms with every button push. The reset button sorta works, though. It resets, but you only see that when you press the start button and you're back at counting from 0 to 1ms. I must have misunderstood something.
void loop() {
byte newButtonState;
byte newResetButtonState;
newResetButtonState = digitalRead(resetbutton);
if (newResetButtonState == HIGH && oldResetButtonState == LOW){
delay(50); //debounce
reset();
}
oldResetButtonState = newResetButtonState;
newButtonState = digitalRead(button);
if (newButtonState == HIGH && oldButtonState == LOW){
delay(50); //debounce
if (running)
{
timer();
timershow();
running = false;
}
else
{
timer();
timershow();
running = true;
}
}
oldButtonState = newButtonState;
}
akinear:
Here's the loop now. When I press the start/stop button now it just goes up one ms with every button push. The reset button sorta works, though. It resets, but you only see that when you press the start button and you're back at counting from 0 to 1ms. I must have misunderstood something.
It's hard to say without seeing your entire updated sketch and knowing how your buttons are wired.
Post your entire sketch and how your buttons are wired and I'll see if I can figure out what is happening.
Ok here's the entire code and image of how it's wired attached. Thanks for helping.
#include <LiquidCrystal.h>
LiquidCrystal LCD(12, 11, 5, 4, 3, 2);
long int msec = 0;
int sec = 0;
int minutes = 0;
int period = 99;
unsigned long time_now = 0;
unsigned long time_pre = 0;
const int button = 8;
const int resetbutton = 9;
byte newButtonState = LOW;
byte oldButtonState = LOW;
byte oldResetButtonState = LOW;
boolean running = false;
void setup() {
LCD.begin(16, 2);
pinMode(button, INPUT);
pinMode(resetbutton, INPUT);
LCD.setCursor(0, 1);
LCD.print("00:00:00"); //startscreen
}
void loop() {
byte newButtonState;
byte newResetButtonState;
newResetButtonState = digitalRead(resetbutton);
if (newResetButtonState == HIGH && oldResetButtonState == LOW){
delay(50); //debounce
reset();
}
oldResetButtonState = newResetButtonState;
newButtonState = digitalRead(button);
if (newButtonState == HIGH && oldButtonState == LOW){
delay(50); //debounce
if (running)
{
timer();
timershow();
running = false;
}
else
{
timer();
timershow();
running = true;
}
}
oldButtonState = newButtonState;
}
void reset(){ //set the clock to 0
if (digitalRead(resetbutton)){ //reset-knapp
msec=0;
sec=0;
minutes=0;
newButtonState = oldButtonState;
}}
void timer(){ //counting millisecounds, secounds and minutes
time_now = millis();
if (time_now-time_pre > period){
time_pre=time_now;
msec ++;
if (msec>9){
msec=0; //når det er flere enn 10 millisekunder går den tilbake til 0
sec++; //deretter øker sekunder med 1
}
if (sec>59) //flere enn 59 sekunder, gir 1 min og 0sekunder
{minutes++;
sec=0;
}}
}
void timershow(){ //printing time to LCD
LCD.setCursor(0,1);
{
if(minutes<10){
LCD.print("0");
LCD.print(minutes);
}
else{
LCD.print(minutes);
}}
LCD.print(":");
{
if(sec<10){
LCD.print("0");
LCD.print(sec);
LCD.print(":");
}
else{
LCD.print(sec);
LCD.print(":");
}}
{
if(msec<10){
LCD.print("0");
LCD.print(msec);
}
else{
LCD.print(msec);
}}}
Your wiring diagram did look OK. You have pull down resistors and your switches are active HIGH. FYI, you could eliminate the resistors if you used the internal pullup resistors and wired your switches to GND making them active LOW. However, what you have is fine.
You were only calling timer() and timershow() when the button was pressed and were not doing anything with the running flag. timer() needs to be called every time through loop() if it is running. Technically you only need to call timershow() when the time is updated so I changed the code to call timershow() from timer() whenever the time is updated.
You also had redundant code in reset() that I removed and useless code blocks in timershow() that I removed.
Here it is as I have coded it. It compiles but I couldn't test it; however, it should work or be really close to it.
#include <LiquidCrystal.h>
LiquidCrystal LCD(12, 11, 5, 4, 3, 2);
long int msec = 0;
int sec = 0;
int minutes = 0;
int period = 99;
unsigned long time_now = 0;
unsigned long time_pre = 0;
const int button = 8;
const int resetbutton = 9;
byte newButtonState = LOW;
byte oldButtonState = LOW;
byte oldResetButtonState = LOW;
boolean running = false;
void setup() {
LCD.begin(16, 2);
pinMode(button, INPUT);
pinMode(resetbutton, INPUT);
timershow();
}
void loop() {
byte newButtonState;
byte newResetButtonState;
newResetButtonState = digitalRead(resetbutton);
if (newResetButtonState == HIGH && oldResetButtonState == LOW) {
delay(50); //debounce
reset();
timershow();
}
oldResetButtonState = newResetButtonState;
newButtonState = digitalRead(button);
if (newButtonState == HIGH && oldButtonState == LOW) {
delay(50); //debounce
running = !running;
}
oldButtonState = newButtonState;
if (running) {
timer();
}
}
void reset() { //set the clock to 0
msec = 0;
sec = 0;
minutes = 0;
}
void timer() { //counting millisecounds, secounds and minutes
time_now = millis();
if (time_now - time_pre > period) {
time_pre = time_now;
msec ++;
if (msec > 9) {
msec = 0; //når det er flere enn 10 millisekunder går den tilbake til 0
sec++; //deretter øker sekunder med 1
}
if (sec > 59) //flere enn 59 sekunder, gir 1 min og 0sekunder
{ minutes++;
sec = 0;
}
timershow();
}
}
void timershow() { //printing time to LCD
LCD.setCursor(0, 1);
if (minutes < 10) {
LCD.print("0");
LCD.print(minutes);
}
else {
LCD.print(minutes);
}
LCD.print(":");
if (sec < 10) {
LCD.print("0");
LCD.print(sec);
LCD.print(":");
}
else {
LCD.print(sec);
LCD.print(":");
}
if (msec < 10) {
LCD.print("0");
LCD.print(msec);
}
else {
LCD.print(msec);
}
}
Wow! It works perfectly now. Thank you for helping me.
<3.
akinear:
Wow! It works perfectly now. Thank you for helping me.
<3.
No problem. I hope you learned something!