I'm trying to make a speedometer, with utilization of interrupt for get number of pulse and some calculation for getting speed, but when compute speed the arduino freeze for some second and i lose alot of impulse and false all my successive capture of impulse. Why? thanks for reply
const int contaImpulsi = 2;
volatile int impulsi = 0;
int impulsiOld = 0;
static int appoggio = 0;
unsigned deltaT[3];
unsigned vel = 0;
void setup() {
Serial.begin(9600);
attachInterrupt(contaImpulsi, definisciTempi, RISING);
}
void loop() {
if (impulsiOld == impulsi || impulsi > impulsiOld)
{
if (appoggio == 3) {
deltaT[3] = millis();
appoggio = 0;
}
if (appoggio == 2) {
//Serial.println("ASSEGNO DELTA T 2");
deltaT[2] = millis();
//Serial.println(deltaT[2]);
appoggio = 3;
}
if (appoggio == 1) {
//Serial.println("ASSEGNO DELTA T 1");
deltaT[1] = millis();
appoggio = 2;
}
if (appoggio == 0) {
//Serial.println("ASSEGNO DELTA T 0");
deltaT[0] = millis();
appoggio = 1;
}
}
impulsiOld = impulsi;
if (appoggio == 3) {
int t1 = (deltaT[1] - deltaT[0]);
int t2 = (deltaT[2] - deltaT[1]);
int dividi = t1 + t2;
vel = (((690 * 2000 / dividi) * 3.6) / 10) * 0.85; // here i think is where the program freeze
Serial.println("------------------------------------------");
Serial.print("SPEED: ");
Serial.println(vel);
Serial.println("------------------------------------------");
}
}
void definisciTempi() {
impulsi++;
}
1 Answer 1
First off a comment on your variable types. It's not the cause of your problem, but just something to watch for in future:
int impulsi = 0;
This should be voltatile (Edit: I see you updated that, that's ok).
unsigned deltaT[3];
unsigned vel = 0;
These lack a type. As such the default to int
. Your deltaT array should be unsigned long
since it stores time. It will overflow very rapidly otherwise.
Now on to your problem.
The core of your problem is your methodology of calculating the speed. This bit:
if (impulsiOld == impulsi || impulsi > impulsiOld)
{
...
}
impulsiOld = impulsi;
is going to be running pretty much always. That's because impulsiOld
and impulsi
will either always be the same (since you set them to be the same) or impulsi
is going to be greater than impilsiOld
since you received a pulse in the brief interlude when it's not running that bit.
And that means that all your deltaT
entries are going to be the same most of the time. Which leads me on to the next bit:
int t1 = (deltaT[1] - deltaT[0]);
int t2 = (deltaT[2] - deltaT[1]);
int dividi = t1 + t2;
vel = (((690 * 2000 / dividi) * 3.6) / 10) * 0.85;
If delatT[1]
and deltaT[0]
are the same, then t1
will be 0
. The same goes for t2
. 0 + 0 = 0
, so dividi
will also be 0.
And that means:
690 * 2000 / 0
Which will be a divide by zero exception and will cause the MCU either to lock up or to reboot. If the latter you will see the bootloader run for a couple of seconds.
There are two normal methods of calculating the speed from pulses, and I am not sure what your method is trying to be.
The simplest one is to just count the number of pulses over a given period. Increment the count in your ISR, and after a second has elapsed (or longer, or shorter, depending on the frequencies you are working with) you reset the count to 0 (after storing it elsewhere) and calculate the speed from that stored count.
The other way is to just take the time between two successive pulses. You can average it, maybe with a rolling (AKA moving) average, or just take the raw value depending on what you are measuring. This method is a little harder since you need to do more work per pulse.
The two methods differ in critical ways when it comes to outputting the results. The first method will always give you a value every second (or whatever time period you use), but it can't cope with pulses that are further apart than the time period you use. The second method doesn't much care about the time between the pulses, but you can only get a meaningful reading if a pulse arrives, which if that is a while means you get no reading for a while. It's harder to determine "not moving" from that.
Also you should look at the use of critical sections when accessing your impulsi
variable outside the interrupt routine. It more than 8 bits, so all access to it will be non-atomic and could be interrupted by the ISR.
Explore related questions
See similar questions with these tags.
deltaT
has 3 elements, but you are writing to 4 and only reading from 3.appoggio
is 3,appoggio
gets set to 0 and the if block forappoggio == 0
gets also executed in the same loop.