For anything not related to Speeduino, but still about car/bike/boat/engines etc
By whiskey
#62745
Hi all, I'm attempting to use a modified version of the speedy basic distributor code to read rpm of a motor.
But I get weird results when I approach zero and go back up from there. If i bring the speed up slowly the rpm oscillates between what it should read and half of what it should read. If i do it quickly the reading is perfect

No idea what I've done wrong, Im not very good at programming.
Any help is appreciated.
Code: Select all
unsigned long curTime;
unsigned long toothLastToothTime = 0;
unsigned int triggerActualTeeth = 8;

volatile unsigned long triggerFilterTime = 0;
volatile unsigned long curGap = 0;

volatile unsigned int rpm = 0; // Initial rpm value
volatile unsigned int cur_rpm = 0;
const byte rpm_in = 2;

bool hasSync = false;
volatile unsigned long toothCurrentCount;
volatile unsigned long toothOneMinusOneTime;
volatile unsigned long toothOneTime;
volatile unsigned long syncLossCounter;
volatile unsigned long startRevolutions;
volatile unsigned long toothLastMinusOneToothTime;
volatile unsigned long currentLoopTime;
unsigned long MAX_STALL_TIME = 500000;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  pinMode(rpm_in, INPUT); //Interrupt 0
  attachInterrupt(digitalPinToInterrupt(rpm_in), triggerPri_BasicDistributor, FALLING);
}


void loop() {
  // put your main code here, to run repeatedly:


  Serial.print("RPM =  ");
  Serial.println(rpm);
  //Serial.println(" ");




  currentLoopTime = micros();
  unsigned long timeToLastTooth = (currentLoopTime - toothLastToothTime);
  if ( (timeToLastTooth < MAX_STALL_TIME) || (toothLastToothTime > currentLoopTime) ) //Check how long ago the last tooth was seen compared to now. If it was more than half a second ago then the engine is probably stopped. toothLastToothTime can be greater than currentLoopTime if a pulse occurs between getting the latest time and doing the comparison
  {
  noInterrupts();
  if (hasSync == true)
  {
    rpm = 60000000UL / (curGap * triggerActualTeeth);
  }
  interrupts();
  }
  else
  {
    //We reach here if the time between teeth is too great. This VERY likely means the engine has stopped
    toothLastToothTime = 0;
    //toothLastMinusOneToothTime = 0;
    hasSync = false;
    startRevolutions = 0;
    rpm = 0;
  }


  } void triggerPri_BasicDistributor(void)
  {
    curTime = micros();
    curGap = curTime - toothLastToothTime;
    if ( (curGap >= triggerFilterTime) )
    {
      if (hasSync == true) {
        triggerFilterTime = (curGap * 3) >> 2;  //Recalc the new filter value
      }
      else {
        triggerFilterTime = 0;  //If we don't yet have sync, ensure that the filter won't prevent future valid pulses from being ignored.
      }

      if ( (toothCurrentCount == triggerActualTeeth) || (hasSync == false) ) //Check if we're back to the beginning of a revolution
      {
        toothCurrentCount = 1; //Reset the counter
        toothOneMinusOneTime = toothOneTime;
        toothOneTime = curTime;
        hasSync = true;
        startRevolutions++; //Counter
      }
      else
      {
        if ( (toothCurrentCount < triggerActualTeeth) ) {
          toothCurrentCount++;  //Increment the tooth counter
        }
        else
        {
          //This means toothCurrentCount is greater than triggerActualTeeth, which is bad.
          //If we have sync here then there's a problem. Throw a sync loss
          if ( hasSync == true )
          {
            syncLossCounter++;
            hasSync = false;
          }
        }

      }
      toothLastMinusOneToothTime = toothLastToothTime;
      toothLastToothTime = curTime;
    } //Trigger filter
  }
User avatar
By jonbill
#62746
What are the code modifications? Are you running a speeduino hardware and firmware, or have you just taken the decoder to use in a different context?

Also, what is "approach zero" in numbers? Less than 200rpm?
By whiskey
#62747
Only minimal code modifications, taking out parts that aren't relevant. It's in the post above. Using V0.4 hardware but just measuring rpm of an electric moter
User avatar
By jonbill
#62754
Tbh, if you're not confident coding, why not just run speeduino as is?
(Although below 200rpm I wouldn't be surprised if there are problems, since engines never really turn slower than that)
By JHolland
#62782
If you only want to read the RPM of an electric motor then read up on input capture, the way that Speeduino works is not the best way to read RPM.

With the help of an example at https://www.nursin[…]

Always going to be one, I have completed 3 convers[…]

Do i have to do something in arduino software ? i […]

STM32 development

Not yet, I have been too busy to look into it but […]

Still can't find what you're looking for?