Need some assistance with my Speedometer project

Hello everyone, I am currently debugging this speedometer setup on a friends vehicle. I did an engine swap on the rig and consequently the new transmission has an electronic output, the original was mechanical. My friend wanted to retain the factory gauge setup, so this project was born.

My basic plan was to take the Toyota VSS signal, convert that in an arduino nano, and output a signal that drives a small brushless motor mounted behind the gauge cluster. After much research and testing, I camp up with this code below. The brushless motor I am using is a Nidec 24H404H, it's a small bldc with built in drive circuitry and encoders. The motor requires a 15-25Khz PWM signal for speed control.

I used the PWM.h library for creating an 18Khz PWM signal for the motor, and the hardware counter Pin 5 for capturing the VSS signal. The setup seems to work quite well and is very accurate, with just a couple small issues.

The first problem is that the speedometer will quit working after about 15 minutes of highway driving at 65MPH. I believe this to be an issue with the "TCNT1" variable reaching its maximum value.

The Second Issue is that the speedometer only updates once a second, is there a better way to capture the VSS signal than the way I am doing it?

Thanks in advance

Code:

#include <SPI.h>
#include <Wire.h>
#include <PWM.h>

int led = 3; //Pin for PWM output
unsigned int range = 255;
int32_t frequency = 18000; //frequency (in Hz)

const int hardwareCounterPin = 5;

unsigned long count;
unsigned long pcount;
unsigned long ncount;

byte pwmval;
byte ulim = 125; //Adjust this variable to fine tune speedometer range





void setup(void) {
  Serial.begin(9600);
  Serial.println("Start");
  InitTimersSafe();
  SetPinFrequencySafe(led, frequency);
  pwmval = 255;
}


void loop() {

  
  bitSet(TCCR1B, CS12); // start counting pulses
  bitSet(TCCR1B, CS11); // Clock on rising edge
  count = TCNT1; //Store TCNT1 in variable
  delay(1000); //Delay to count pulses
  ncount = count - pcount; //Subtract previous count from current to get new count
  Serial.println(ncount); //For testing
  Serial.print("TCNT");
  Serial.println(TCNT1);
  
  if (ncount < 2){ //If new count or "MPH" is less than 2, set to 0
    ncount = 0;
  }
  
  pwmval = constrain(map(ncount, 85, 0, ulim, 255), ulim, 255); //Convert ncount to proper range for PWM which happens to be 255-125. The range on the speedometer is 0-85, 255 being zero, and 125 being 88. 
  Serial.println(pwmval);
  if (ncount != pcount){ //Only update PWM if the ncount variable changes
  pwmWrite(led, pwmval);
  }
  pcount = count; //Set pcount for next loop
  if(TCNT1 > 30000){ //If hardware counter exceeds 30000, then reset to 0
    TCNT1 = 0;
    bitSet(TCCR1B, CS12);
    bitSet(TCCR1B, CS11);
  }
  
}

I would reset TCNT1 t0 0 after every read. Then drop the pcount.

What do you know about the Vss signal. You could use a timer to count the period of each cycle.

Thanks John, that seemed to clear up the issue of it randomly cutting out. As far as the VSS, it outputs a 12v square wave signal which I step down to 5v through a transistor. It’s about 2.5 pulses per tire revolution (or 3 rising edges) measured with my scope.

As far as counting the period of the cycles, are you referring to using pulseIn() or some other way of counting the period? I tried pulseIn() early in this build, but it gave me very erratic readings at lower wheel speeds. It would be nice to have a way of updating more than once per second, although this current setup does work quite well as it is.

No, pulseln() will only count the pulse high time.

Create an interrupt at the rising time of the signal, note the time use millis().
on the next interrupt note the millis() from the previous interrupt.

Average a bunch of them. I like to sort maybe 8 to 16 readings, discard the highest and lowest. Maybe the 2 highest and 2 lowest. Average the rest.