crankshaft position sensor reading

I need to calculate RPM from this motorcycle via the Crankshaft position sensor.

the sensor is a two wire and not sure how to hook it up to Arduino ( Leonardo )
as it has to have a floating ground ?

here is a video of it running with an oscilloscope tapped into the leads

I guess I need to convert this to a square wave, so I can count pulses on a digital pin ?

any help would be appreciated, I and pretty much a beginner with the hardware side of this

You don't need to convert it to a square wave, but it looks like the signal is an inductive pickup. You are going to have to limit the voltage to the Arduino's range 0..5V.

I could not see the voltage range from the Oscilloscope. Was the voltage symmetric about the 0V level?

You could use some resistors and diodes to clamp the voltage between 0..5V.

Here is a simple circuit. It is just a guess it should not damage the tach. Wire it up and see what the waveform between GND and INTERRUPT.

The waveform should be a chopped copy of your sine wave. limited from 0 to about 4.5v

Chuck.

@chucktodd:

when you say:
"was the voltage symmetric about the 0V level"
do you mean the waveform goes above and below the 0V level ?

Ill have to get another better screenshot of the waveform.

does the circuit you outline isolate the ground in this sensor circuit ?
because when I connect my tap on the black sensor wire to arduino ( and motorcycle common ) ground
the sensor does not work properly, and engine stops running.

375k red sensor wire resistance to GND
365k black sensor wire resistance to GND
0.98K across red/black terminals of sensor

and in the attached drawing, am I clarifying the connections correctly ?

so this is how I have it hooked up ( see attachment )

and this is what I see on the scope:

but I cannot read the pulses with arduino

here is my code:

#include <SoftwareSerial.h>
// serial coms for LCD
const byte tachPin = 3;       // tach signal on digital pin 3 (interrupt 1)
const byte tachInterrupt = 1; // tach signal on interrupt 1 (digital pin 3)
byte engineCylinders = 2;     // for tach calculation (pulses per revolution = 2 * cylinders / cycles)
byte engineCycles = 4;        // for tach calculation
int refreshInterval = 750;    // milliseconds between sensor updates
unsigned long previousMillis = 0;
volatile int RPMpulses = 0;
int rpm = 0;

// Attach the serial display's RX line to digital pin 2
SoftwareSerial mySerial(6,5); // pin 5 = TX to display, pin 3 = RX (unused)

void setup()
{
  pinMode(tachPin, INPUT_PULLUP); // enable internal pullup for tach pin
  attachInterrupt(tachInterrupt, countRPM, FALLING);
  Serial.begin(9600); // Console serial output
  //SoftwareSerial mySerial(6,5); // pin 5 = TX to display, pin 3 = RX (unused)
  mySerial.begin(9600); // set up LCD serial port for 9600 baud
  delay(500); // wait for display to boot up
  mySerial.write("                "); // clear display
  mySerial.write("                ");
  mySerial.write("                ");
  mySerial.write("                ");
  mySerial.write(254);
  mySerial.write(128); // move cursor to 1st position first line
  mySerial.write("Current RPM:");
  mySerial.write(254); // move cursor to beginning of first line
  mySerial.write(192);
  mySerial.write("Neutral?    YES");
}

void loop()
{
  if(millis() - previousMillis > refreshInterval)
  {
    previousMillis = millis();
    Serial.println(getRPM());
    String rpmstring =  String(getRPM());
    //char rpmstring[15];
    //rpmstring =  String(getRPM());
    //Serial.println(rpmstring);
    mySerial.write(254);
    mySerial.write(141); // move cursor to 14th position first line
    mySerial.println(rpmstring);
  }
}

// counts tach pulses
void countRPM()
{
  RPMpulses++;
}

// checks accumulated tach signal pulses and calculates engine speed
// returns engine speed in RPM
// Resolution: 30000 * engineCycles / refreshInterval / engineCylinders RPM (for default values = 20 RPM)
int getRPM()
{
  int RPM = int(RPMpulses * (60000.0 / float(refreshInterval)) * engineCycles / engineCylinders / 2.0 ); // calculate RPM
  RPMpulses = 0; // reset pulse count to 0
  RPM = min(99999, RPM); // don't return value larger than 9999
  return RPM;
}

What type sensor is on the engine? It appears it is a missing tooth sensor. Can you verify that. A pic of the sensor mechanism might help.

edit: The reason I say that is if you watch the o-scope display closely, every now and then you will see a gap between pulses that is missing a positive pulse.

here is the sensor:

Here is a pic of your o-scope with the missing pulse.

vlcsnap-2016-04-14-12h03m36s972.png

looks like this sensor:
HD part number 32707 01C
is a Variable Reluctance (VR) type sensor

do I need to do anything special in my code to detect this pulse ?

more info here on the sensors:

http://www.daytona-twintec.com/tech_sensors.html

This should be somewhat like your crankshaft. Note the missing teeth.

You will need to determine the normal time between pulses, then wait for the missing pulses. The time between pulses in that gap will be much longer (4 times?) than the normal duration.

edit: I would use interrupts and save the microsecond reading for this pulse, and compare it to the last pulse microsecond reading, then check the average time. If that gear has 36 teeth with some missing (10 degrees between non-missing teeth), the time between non-missing teeth should be 1388 microseconds at 1200RPM. If the time between those is more than twice (greater than 2700us), you just went by the gap (missing teeth).

I recommend checking my math. I think that is correct.

oelbrenner:
so this is how I have it hooked up ( see attachment )

but I cannot read the pulses with arduino

here is my code:

The sensor is giving multiple pulses per revolution. I agree with others, that you need to write a 'missing pulse' interrupt routine something like this.

Try changing your countRPM()

// counts tach pulses
static volatile unsigned long shortPulse=0;
static volatile unsigned long lastPulse=0;


void countRPM()
{
unsigned long now = micros(); // current microsecond counter
unsigned long nowPulse = now - lastPulse; // microseconds since last pulse
lastPulse = now; // new starting point

if((nowPulse >> 1)>shortPulse){ 
/* if nowPulse was over twice as long a short pulse then must be Top Dead Center
  count as one revolution
*/
  RPMpulses++;
  shortPulse = nowPulse; 
/* since shortPulse starts at 0, any value greater than 1 is more than twice a large as zero.
so if I assume the current pulse is the 'long' pulse and set the short pulse that long, 
the next pulse should be the shorter pulse.  If it is not, the else case will correct it. 
*/

  }
else { // just another short pulse, engine may be changing speed so update current shortPulse
  shortPulse = nowPulse;
  }
}

Can you describe your scope settings?

What is the Purple ringing Wave?

What is the blue trapezoid wave?

What are the time periods, what are the voltages (milliseconds per division, volts per division, where is the 0v reference line?)

Chuck.

Ill try the missing pulse code tomorrow, but I am getting nothing at all
zero pulses.

even with the gap in pulses I should get some count right ?

getRPM is always returning zero.

the purple wave on the scope are because I have no idea how to use that scope beyond how its working.
I was able to turn off the display of that purple wave at some point, but neglected to on this run.

I have it on a 5V range, with 1ms refresh
with a 1.0V falling trigger ?

maybe someone with experience with this scope ?
http://www.seeedstudio.com/depot/DSO-Nano-v3-p-1358.html

The reference for the attachInterrupt function uses a different format than in your code.

// change this
  attachInterrupt(tachInterrupt, countRPM, FALLING);
// to this
  attachInterrupt(digitalPinToInterrupt(tachPin), countRPM, FALLING);

See if that makes a difference.

edit: I changed the variable to tachPin.

On the o-scope, did you change the Y offset setting? It is displaying the pulse voltage as below zero (between -1 and -3 volts).

SurferTim:
The reference for the attachInterrupt function uses a different format than in your code.

// change this

attachInterrupt(tachInterrupt, countRPM, FALLING);
// to this
 attachInterrupt(digitalPinToInterrupt(tachPin), countRPM, FALLING);



See if that makes a difference.

good Catch, I did not see that. It should work better if we actually tell the software which pin to use for the interrupt! :confused:

Chuck.

works!

my RPM calculation is a bit off tho, showing idle RPM around 1120 to 1150
when its supposed to be closer to 900, but I need to verify with a real calibrated tachometer.

here is video of latest test:

How are you calculating the RPM? What is the raw microsecond reading between missing pulses at an idle?

actually the RPM calculation is correct.

turn out they idle a bit fast when cold, then drops back to about 1040 RPM which is within the HD idle specification.

Thanks to everyone for helping out !

Hello everyone I need car cmp sansor and ckp sansor simulation Arduino code

I am trying this to my motorcycle...can u give me the circuit??