Car Tach on a single cylinder

Hows things guys

im working on a project involving a lawn mover engine( its a mini bike)

i want to put an rpm gauge on the motor but i have a few questions that i cant get answered.

so i have a sensor that is located on the cam shaft witch gives a 5v pulse to the micro controller.

the camshaft rotates at half the engine speed.

thing is i am using a car tach witch can be set for 4,6,8 cylinder engines and as far as i know on a 4 cylinder engine the tach will read every pulse from the engine ? or every pulse of 2 cylinders.

any way the result being that i am only reading half of the engine speed with this setup.

i wrote the program to just relay the pulse that it gets to an output pin, i am now looking to change the program so that it reads the pulses from the engine over a few milliseconds and then outputs double that pulses to a pin.

i have no idee how this would be done ?

is this even possible ?

here is my code

const int CamPin = 8;     // the number of the Proxy sensor pin
const int GuPin =  7;      // the number of the guage pin

// variables will change:
int CamPinState = 0;         // variable for reading the camsensor status

void setup() {
  // initialize the guage pin as an output:
  pinMode(GuPin, OUTPUT);
  // initialize the camsensor pin as an input:
  pinMode(CamPin, INPUT);
}

void loop() {
  // read the state of the Cam value:
  CamPinState = digitalRead(CamPin);

  // check the Cam in position. If it is, the CamPinState is HIGH:
  if (CamPinState == LOW) {
    // pulse on:
    digitalWrite(GuPin, LOW);
  } else {
    //  pulse off:
    digitalWrite(GuPin, HIGH);
  }
}

any input would be great !

You want to do two things:

  1. detect pulses on a pin and work out an average frequency over a few milliseconds.
  2. You want to double that frequency and output the pulses on another pin.

Is that right?

Is the duty cycle important ?
Does the spacing between the pulses matter or can the doubled pulses be sent with the same time lag irrespective of the engine speed ?

Sure possible.

  1. read the time between two pulses.
  2. produce two pulses, spaced at half that time - the first output pulse can be started as the second input pulse begins, and the second output pulse half a period later.
    This is very easy to do. As long as the input doesn't change much the output pulses will be pretty evenly spaced.
    How long time between pulses, typically?
    What's the required duration of the output pulse? Is that critical?

The pulse length is not that critical, although it has to be long enough so that the gauge can respond,so i would say it just needs to be the same as the input pulse length.

Can you help me get started on the program as i have no experience in counting pulses and so on?

Thanks guys!!

Lots of examples for pulse counters out there.
You'll probably need to use interrupts here as it seems pulses come in pretty fast.

Adriaankenny:
The pulse length is not that critical, although it has to be long enough so that the gauge can respond,so i would say it just needs to be the same as the input pulse length

That means you have to not only count the pulses, but also measure the duration. That's a non-trivial extra requirement.

I modified your sketch to test your tachometer to see if the "doubled" pulses can run together.
It goes from 200rpm to 10,000rpm (simulated). It sends a 1mS pulse then waits 3mS then sends another 1mS pulse then waits a time calculated to be the completion of the engine cycle.
If it is wildly out, the pulse width has to be changed and/or the pulse distribution has to be evened out.
On the serial console, you see the RPM and the calculated end of cycle delay.
Maybe it helps you to get started.

const int CamPin = 8;     // the number of the Proxy sensor pin
const int GuPin =  7;      // the number of the guage pin

// variables will change:
int CamPinState = 0;         // variable for reading the camsensor status

void setup() {
  Serial.begin( 115200) ;
  // initialize the guage pin as an output:
  pinMode(GuPin, OUTPUT);
  // initialize the camsensor pin as an input:
  pinMode(CamPin, INPUT);
}

void loop() {

  static uint16_t speedFactor = 0 ;
  static uint32_t lastIncrementAtMs = 0 ;
  static uint32_t rpm = 0 ;
  static uint32_t endDelayUs = 0 ;

  uint32_t ms = millis() ;

  // calculate every x seconds
  if ( ms - lastIncrementAtMs > 4000 ) {  // 4 seconds
     lastIncrementAtMs = ms ;
     speedFactor ++ ;
     if ( speedFactor > 50 ) speedFactor = 1 ;  // 1=200rpm limit to 10,000 rpm then repeat.
     rpm = speedFactor * 200 ;
     
     // endDelayUs pads out the period after the 2 pulses and gap to control the frequency
     // 5000 is combined pulse width ( 2 pulses of 1mS + 3mS gap)
     
     endDelayUs = ( 60UL * 1000UL * 1000UL / rpm ) - 5000 ;  
     
     Serial.print( rpm ) ;
     Serial.print( "  "  ) ;
     Serial.println( endDelayUs ) ; 
  }
  
  digitalWrite(GuPin, HIGH);
  delayMicroseconds( 1000 ) ;  // 1000 uS pulse width
  digitalWrite(GuPin, LOW);
  delayMicroseconds( 3000 ) ;  // 3000 uS delay for 2nd pulse

  digitalWrite(GuPin, HIGH);   // second pulse
  delayMicroseconds( 1000 ) ;  // 1000 uS pulse width
  digitalWrite(GuPin, LOW);


  if ( endDelayUs < 10000 )   delayMicroseconds ( endDelayUs ) ; 
  else delay( endDelayUs / 1000 ) ; 

}