Without using "delay," how can one record the time between say one button push or interrupt and another?
I've tried using an interrupt and the Millis() function a few different ways but I'm stumped. Either I get 0 or Millis() just keeps rolling. I guess what I need to know is can I capture time at point a, then point b, and measure the elapsed time between the two? Because Millis() doesn't start and stop real easy, I'm finding this vexing.
You don't need millis to stop. You just need to know what value it had at any one point. You call it and store the result in a variable at the beginning. You call it and store the result in a different variable at the end. The variables both need to be unsigned long type. Then you just subtract to find out how far in between.
If that hasn't been working for you, then post up your code and maybe someone can see where you went wrong.
Okay, this is one testing sketch that doesn't work. It's a bit cobbled together. If you run it, each button push just spits out what's in millis as it roles along like a runaway train. I just can't seem to get solid time A and time B stamps. Eventually, I want to trigger an interrupt with a Hall sensor and figure time between triggers. I'm trying to use a button just for a mock-up.
volatile int start =0;
volatile int revs = 0;
void setup()
{
pinMode (2,INPUT);
digitalWrite(2,HIGH);
Serial.begin(9600);
attachInterrupt(0,react,FALLING);
digitalWrite(2, HIGH);
//get the start time
start = millis();
}
void loop()
{
}
void react()
{
long fin = millis();
revs =(fin - start);
Serial.println(revs);
}
There are problems using Serial.print() in an ISR because it uses interrupts and they are disabled whilst an interrupt is being serviced. Instead, set a flag when the interrupt occurs and do the printing in loop() based on the value of the flag.
void react()
{
long fin = millis();
revs =(fin - start);
Serial.println(revs);
}
So each time through you subtract start from fin. start that you saved way back in setup and never change anywhere else in the program. So what you are printing is the time between the current pulse and the end of the setup function. If you want to see the time between this pulse and the last pulse then you need to update the start time appropriately.
My understanding is global variables used in the ISR must be "volatile."
The Serial.print in the function isn't the issue.
I understand the logic of taking the difference of two time stamps. Truble is, I can't seem to make that happen. My understanding is that millis () keeps going once started. It does however stop in the ISR. I don't know how to write code that can flag millis() or plug its value into a variable at a given time. I've been trying and failing. I can make it work by calculating start to a given point, but I cannot record time elapsed between ongoing button presses. Anyone care to try?
{
long fin = millis();
revs =(fin - start);
Serial.println(revs);
}
So each time through you subtract start from fin. start that you saved way back in setup and never change anywhere else in the program. So what you are printing is the time between the current pulse and the end of the setup function. If you want to see the time between this pulse and the last pulse then you need to update the start time appropriately.
Ok, so the ISR stops millis(). What if I use two interrupt commands in a row with two functions and two variables? Think funcA(), which makes time1 = millis() then funcB() which makes time2= millis(). The elapsed = time2 - time1. Then I just loop it so I keep getting a new "elapsed."
This is the only way I can think of two get two time stamps. Now I just have to figure out how to code that out to see if it works. Anyone think it is feasible?
What do you mean can't make it happen? It's just a variable assignment. Do you want the time between interrupts? So the fin time for this one should be the start time for the next one?
void react()
{
long fin = millis();
revs =(fin - start);
start = fin; // sets up start for the next interrupt
Serial.println(revs);
}
You don't have to worry about the ISR stopping millis if it is really fast. As long as the ISR doesn't take more than a few milliseconds then the next Timer0 overflow will catch millis up as soon as your ISR exits. That's not a problem for you.
Delta_G:
What do you mean can't make it happen? It's just a variable assignment. Do you want the time between interrupts? So the fin time for this one should be the start time for the next one?
That did it! I can't believe it was that simple. Thank you!
All I had to do was add start = fin to the end. Elapsed is for future use.
Seems to work great.
long int start =0;
long int revs = 0;
volatile int elapsed =0;
void setup()
{
pinMode (2,INPUT);
digitalWrite(2,HIGH);
Serial.begin(9600);
attachInterrupt(0,react,FALLING);
digitalWrite(2, HIGH);
//get the start time
start = millis();
}
void loop()
{
}
void react()
{
//start = millis();
long fin = millis();
revs =(fin - start);
Serial.println(revs);
start = fin;
elapsed = revs;
}
DON'T ATTEMPT TO PRINT INSIDE AN ISR! How many times do we have to say it?
It's like "Don't run with scissors." Yes, you can run a lot with scissors but when it goes wrong it is a really serious injury.
Have your ISR set a global variable like boolean isReady; When the main loop detects that isReady is true, then it can grab a 'safe copy' of the volatile variables and print that. Inside the 'safe copy' area, it can set isReady back to false, so the next time the ISR hits it, the main loop will know that it has a new thing ready to print.