1

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++;
}
4
  • You should make impulse volatile, otherwise its value could be cached. Commented May 9, 2017 at 8:36
  • IF it is that line then I can see why it might be an issue. Can you refactor the formula so there is only one multiplication operation instead of all those constants? An alternative system design might be to use an independent counter IC that you query periodically, that way the calculation and presentation is separated from the counting. Commented May 9, 2017 at 8:42
  • Your deltaT has 3 elements, but you are writing to 4 and only reading from 3.
    – gre_gor
    Commented May 9, 2017 at 14:31
  • And when appoggio is 3, appoggio gets set to 0 and the if block for appoggio == 0 gets also executed in the same loop.
    – gre_gor
    Commented May 9, 2017 at 14:35

1 Answer 1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.