I have trouble wrapping my head around milling. Usually I can get timers working without too much frustration. But I am trying to use it differently now it it just isn't working. Any advise would be appreciated!
Basically. As soon and I press and hold a button. I want it to start counting from 0 on up until I release the button. I'd like to serial print it in tenths of a second.
I can sort of get it to work. But it always start at say 5 seconds because previousmillis was 0 at the time. So naturally 5-0 = 5 . I'm having trouble understanding how to get the clock to start at zero.
This seems so simple yet it's driving me up a wall.
If someone could be so kind to demonstrate a simple example, I would be forever grateful!
When the switch state changes to pushed, make previousMilliis = millis().
When the switch state changes to not pushed, print millis() - previousMillis.
Sloppsta:
But it always start at say 5 seconds because previousmillis was 0 at the time.
I think (but you didn't show your code yet) that's because you need to capture the time at which the button became pressed. See code below, where I used a state machine approach. Works for me.
(Note the button is to ground with internal pullup enabled; the button is thus "active low". In the IDLE state, where it goes right at the start, it only looks for the button's state to go low (the if (!buttonState)), at which point it goes to the COUNTING state.)
byte buttonPin = 2;
bool buttonState;
bool timing = false;
unsigned long previousMillis;
unsigned long currentMillis;
unsigned long timingStartedAt;
int timingInterval = 100;
enum {IDLE, COUNTING} currentState = IDLE;
void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
Serial.println("Setup done");
Serial.println("Entering Idle state");
Serial.println("Press button to count");
Serial.println("---------------------");
Serial.println("");
}//setup
void loop()
{
currentMillis = millis();
buttonState = digitalRead(buttonPin);
switch (currentState)
{
case IDLE:
//Serial.println("Idle");
if (!buttonState) //pressed
{
currentState = COUNTING;
}
break;
case COUNTING:
if (!timing) //first time here, so initialise
{
timing = true;
timingStartedAt = currentMillis;
previousMillis = currentMillis;
}
if (timing)
{
if (currentMillis - previousMillis >= timingInterval)
{
Serial.println(currentMillis - timingStartedAt);
previousMillis = currentMillis;
}
}
if (buttonState) //button has been released
{
currentState = IDLE;
Serial.println("Returning to Idle state");
Serial.println(" Press button to count");
Serial.println("-----------------------");
timing = false;
}
break;
}//switch
}//loop
The "enum" by the way, is just a simple way of assigning a number to word, starting with 0 at the left of the list. So there, IDLE has the value 0, and COUNTING is 1; both of those are used in the switch... case as the normal 0 and 1, but more meaningful and human friendly.
Was open now open (state 0) : Switch is released (OPEN)
Was open now closed (state 1) : Switch was just pressed (RISING)
Was closed now closed (state 2) : Switch is pressed (CLOSED)
Was closed now open (state 3) : Switch was just released (FALLING)
Basically. As soon and I press and hold a button. I want it to start counting from 0 on up until I release the button. I'd like to serial print it in tenths of a second.
You want to start the chronometer on the RISING edge and print it on the FALLING edge.
Start in state 0
if the state is 0: read the switch. if it is closed change state to 1
if the state is 1: set the chronometer @ millis(); change state to 2
if the state is 2: read the switch. if it is open: change state to 3
if the state is 3: print ((millis() - chronometer) / 100); change state to = 0
Thank you guys. after reading over your suggestions and learning about state machines, I was able to cobble something together that is working rather well.
Sloppsta:
Thank you guys. after reading over your suggestions and learning about state machines, I was able to cobble something together that is working rather well.
Feel free to share it. Folks here may see a way to make it better. Thus helping you and anyone else doing something similar to learn even more.
My code in #4 did exactly what you asked. Press a button; while it's held, display a counter or timer or whatever you want to call it from 0 in 1/100 of a second; stop doing that when button released; start at 0 again next time round.
Unless you mean you needed to incorporate that functionality into a bigger scheme of things.
Welease_Woggah:
My code in #4 did exactly what you asked. Press a button; while it's held, display a counter or timer or whatever you want to call it from 0 in 1/100 of a second; stop doing that when button released; start at 0 again next time round.
Unless you mean you needed to incorporate that functionality into a bigger scheme of things.
Yes. Your code was flawless! Thank you for sharing it. By cobbling I meant my own incompetent skills trying to implement it into a larger project. Slowly but surely I'll get there! Thanks again
Yeah it's the bigger picture where it gets tricky. But if we modularise things and design those building blocks correctly (eg use millis() not delay()) then it should be easy to plug the blocks together.
BTW just in case you or anyone is wondering: it's often a requirement to look for a button to become pressed, rather than be pressed, and that's explained well in the StateChangeDetection example. It was unnecessary to use that technique in my code, since as soon as the IDLE state saw the button was pressed (low), it left that state. Implicit in that, was the fact that as soon as it saw the button was low, that meant a new press, since if it was an old (ie continuing) press, it wouldn't have been in the IDLE state to look for it anyway.