You are on page 1of 28

Crankshaft sensor code

on: February 09, 2013, 01:47:25 pm Bigger Smaller Reset



Folks,
I'm currently involved in an ev conversion project and wrote some code (well mostly copied!) to simulate a 60-2 crankshaft position
sensor. Basically the sketch should output 58 pulses , skip two , another 58 and so on. A pot on A0 provides a reference for pulse
width and hence rpm. Could someone please have a look at the sketch and let me know if I have the pulse counts correct as i don't
have a dso to verify the output?

/**
crank signal simulator
*/

#define PULSE_PIN 10


void setup() {
pinMode(PULSE_PIN, OUTPUT);
}

/**
Simulate the high of a tooth on a
reluctor wheel
*/
void triggerHigh(int duration) {
digitalWrite(PULSE_PIN, HIGH);
delayMicroseconds(duration);
digitalWrite(PULSE_PIN, LOW);
}

/**
Simulate the reference marker on a
reluctor wheel
*/
void triggerReference(int duration) {
// pin should be low already
delayMicroseconds(duration);
delayMicroseconds(duration); // two delays for two missing pulses.
}


/**
Simulates a 58 tooth reluctor wheel
with a 2 tooth reference
*/
void loop(){
int val = analogRead(0);
val = map(val, 0, 1023, 100, 3500);

for(int i = 0; i <= 58; i++) {
triggerHigh(val);
delayMicroseconds(val);
}
triggerReference(val);
delayMicroseconds(val);
}

many thanks. For anyone interested in the project please see http://www.e39ev.com/
Counting 0 through 58, inclusive, gives you 59 counts:
Code:
for(int i = 0; i <= 58; i++) {

Typically you would count to 58 by counting 0 through 57, inclusive:
Code:
for(int i = 0; i < 58; i++) {


If the two missing pulses are supposed to be the same length as the 58 other pulses you need to do FOUR delays instead of THREE
(two in the triggerReference() function and one after).

I would put all the delays in the functions:
/**
crank signal simulator
*/

#define PULSE_PIN 10

void setup() {
pinMode(PULSE_PIN, OUTPUT);
}

/**
Simulate the high of a tooth on a
reluctor wheel
*/
void triggerHigh(int duration) {
digitalWrite(PULSE_PIN, HIGH);
delayMicroseconds(duration);
digitalWrite(PULSE_PIN, LOW);
delayMicroseconds(val);
}

/**
Simulate the reference marker on a
reluctor wheel
*/
void triggerReference(int duration) {
// pin should be low already
delayMicroseconds(duration);
delayMicroseconds(duration); // two delays for two missing pulses.
delayMicroseconds(duration);
delayMicroseconds(duration); // two delays for two missing pulses.
}


/**
Simulates a 58 tooth reluctor wheel
with a 2 tooth reference
*/
void loop(){
int val = analogRead(0);
val = map(val, 0, 1023, 100, 3500);

for(int i = 0; i <= 58; i++) {
triggerHigh(val);
}

triggerReference(val);
}
hello Jack Bauer. (and helpers)
I'm doing the same thing, now, but 36:1 for ford 1996 .
I presume you are trying to get ECU happy, so your EV, will shift an automatic tranny?, if yes, I can help you too. or a new ECU?
for bench testing, like me...
I have an OBD2 test bed that i made and the CPK sensor in the FORD ECU is very fussy.. it must have to 1 pulse drop or the ECU
will not gen spark.
I found this out by sending all types of wave forms and only white noise would trigger it ( the drop out must be there or ECU is a
brick.) Im sure it has zero crossing detector in the ECU.;

I also found out this ECU even sparks with a dead, cam sensor... (at least cranking)
but i digress.
If you got your code running now, can you , loan it to me?

all i get compiling is . main.cpp:11: undefined reference to `setup'
and
main.cpp:14: undefined reference to `loop'

using code above.
im an rank rank amateur of UNO but not asm or "C"

i like your POT code for RPM, nice feature.
Good day and thanks for posting this code, it will make generating, CKP signals very easy. once i learn to make this complier happy.
running, sketch jun28a 105
my hardware is all in the mail. so was playing with the CPP.
all i get compiling is . main.cpp:11: undefined reference to `setup'
and
main.cpp:14: undefined reference to `loop'

using code above.

That would happen if you compiled an empty sketch, or one that didn't define void setup() and void loop() functions. Did you paste
the code above into a sketch (.ino) file and then build it within the Arduino IDE?
thanks!
yes, I cut and pasted it into notepad2 (64bit) the with the arduino.exe , i opened that file and built it.
i have the examples running, ok. so its me. my errors.
I then read the many posts on why java blows up. and it was me.
I had some odd illegal. comments. in the first 3 lines. switching /* xxxxx */ solved it.
// this
// that
// something.
#include "Arduino.h"
#define PULSE_PIN 10
etc..

it now compiles , no error, wish my hardware was here.
what a great product and even better docs, and support. wow.

in the old days the C compiler would error as,,, "found { with out an } end" for just about all dumb formatting. Ok I got it.
cant wait to scope this with my old tek scope.

thanks ! for helping !!


Hi,Even i am working on similar project in pic.I have to generate two pulse types on cam and crank(60-2,6+1 or 24+1) and
synchronize them to get same rpm.The programming part is in C language.I have written a code for generating 60-2 pulse on pic
and along with it trying to generate 6+1 simultaneously.I am able to generate 60-2 pulse but i am having trouble generating the
extra pulse in 6+1 type.Can someone have a look and guide me with the modifications that i need to do to make it work.
P.S. I am using pic 18F4525.

#include<p18f4525.h>
#define mybit1 PORTCbits.RC3
#define mybit2 PORTCbits.RC2
void isr(void);
void T0_ISR(void);
void T1_ISR(void);



#pragma code int_vector=0x0008
void high_interrupt(void)
{
_asm
GOTO isr
_endasm
}
#pragma code

#pragma interrupt isr
void isr(void)
{

if(PIR1bits.TMR1IF==1)
T1_ISR();
// if(INTCONbits.TMR0IF==1)
//T0_ISR();
}
unsigned char counter1;
unsigned char counter2;
unsigned char counter3;
unsigned int i;
//unsigned int ii;
//unsigned int jj;

//unsigned int x,y;
unsigned int timer_10msec_flag;
unsigned int timer_flag;

void main()
{



OSCCON=0x77;
TRISAbits.TRISA0=1; //INPUT
TRISCbits.TRISC3=0; //OUTPUT
TRISCbits.TRISC2=0; //OUTPUT
//TRISD=0;
// TRISB=0;


ADCON0=0x03;
ADCON1=0x00;
ADCON2bits.ADFM=0;


// INTCONbits.TMR0IF=0; //CLEAR IF FLAG
PIR1bits.TMR1IF=0;

// INTCONbits.TMR0IE=1; //ENABLE INTERRUPTS
PIE1bits.TMR1IE=1;

// T0CONbits.TMR0ON=1; //START TIMERS
T1CONbits.TMR1ON=1;
INTCONbits.PEIE=1;

INTCONbits.GIE=1;

//timer_100msec_flag=0;
timer_10msec_flag=0;

counter1=0;
counter2=0;
counter3=0;
i=0;

mybit2=1;
mybit1=1;

while(1)
{
T1_ISR();

if(timer_10msec_flag==1)
{

timer_10msec_flag=0;




if(counter1<116)
{
counter1++;
counter2++;
mybit2=~mybit2;
}

else
{
mybit2=0;
if(counter1<119)
{
counter1++;
counter2++;
}

else
{
counter1=0;
//counter2=0;
}
}



if(counter2==10)
{

counter2=0;
counter3++;

mybit1=~mybit1;
//counter2=0;

}

if(counter3==12)
{
//counter3=0;

if(counter2==3)
{
mybit1=~mybit1;
counter3=0;
}

if(counter2==6)
{

mybit1=~mybit1;
counter3=0;

}




}


}

}

}


/*if(timer_10msec_flag!=0)
{
i++;
if(i==1)
{
timer_10msec_flag=1;
mybit2=~mybit2;
i=0;
timer_100msec_flag=0;
ADCON0bits.GO=1;

}

timer_10msec_flag=0;
}
}*/







//PIR1bits.TMR1IF=1;
void T1_ISR(void)
{

T1CON=0x80;

TMR1H=0xFC;
TMR1L=0x17;

T1CONbits.TMR1ON=1;
while(PIR1bits.TMR1IF==0);
T1CONbits.TMR1ON=0;
PIR1bits.TMR1IF=0;

timer_10msec_flag=1;


}


/*void T0_ISR(void)
{
T0CON=0x80;

TMR0H=0xFF;
TMR0L=0xFF;


T0CONbits.TMR0ON=1;
while(INTCONbits.PEIE==0);
T0CONbits.TMR0ON=0;


INTCONbits.TMR0IF=0;

}*/


/**
crank signal simulator
*/

#define PULSE_PIN 10

void setup() {
pinMode(PULSE_PIN, OUTPUT);
}

/**
Simulate the high of a tooth on a
reluctor wheel
*/
void triggerHigh(int duration) {
digitalWrite(PULSE_PIN, HIGH);
delay(duration);
digitalWrite(PULSE_PIN, LOW);
}

/**
Simulate the reference marker on a
reluctor wheel
*/
void triggerReference(int duration) {
// pin should be low already
delay(duration);
}


/**
Simulates a 35 tooth reluctor wheel
with a reference tooth
*/
void loop() {
for(int i = 0; i <= 35; i++) {
triggerHigh(5);
delay(5);
}
triggerReference(5);
delay(5);
}
Crank pulse simulator..similar to Frequency generator..need Bigger Smaller
help
on: January 21, 2012, 10:56:38 pm
Reset

If you can imagine a encoder wheel with 24 evenly space squares\valleys and 2 blank
square\valley areas, this is what I am trying to simulate as an output from my Arduino.

I am trying to create a square wave currently from pin13 that will cycle High to Low 24 times
then cycle Low, Low 2 times. During the first Low, Low cycle, I want to cycle pin 12 High to low
1 time. After this is complete I want to repeat the steps.

This issue that I am need help with is that my "for" loop is going to be "blocking" and also I
need to vary the frequency of the loop. This would represent the possible speed of an engine
from 800 rpm to 17,000 rpm.
I would like to use a pot for the speed adjust and be able to read from the pins if possible. I am
willing to use additional boards if I must.

Here is my code thus far:
/*
//
800rpm = 13.33Hz = 75ms per RPM/26 = 2.88ms per pulse set... time
between pulse state change is 1.44 ms
17,000rpm =283.33Hz = 3.529ms per RPM/26 = .1357ms per pulse set...
time between pulse state change is .06787ms


*/
int timer = 100; // The higher the number, the slower the
timing.

void setup() {

pinMode(13, OUTPUT);
pinMode(12, OUTPUT);

}

void loop() {
// loop for 24 cycles
for (int x = 0; x < 24; x++) {
// turn the pin on:
digitalWrite(13, HIGH);
delay(timer);
// turn the pin off:
digitalWrite(13, LOW);
delay(timer);
}

////////////////////////////// keep pin 13 low for 2 cycles
digitalWrite(13, LOW);
// pulse pin 12 one time for one cycle:
digitalWrite(12, HIGH);
delay(timer);
digitalWrite(12, LOW);
delay(timer);
digitalWrite(13, LOW);
delay(timer);
digitalWrite(13, LOW);
delay(timer);

}
I have this part set this way to keep my mind clear on my task. I do want to improve the
sketch where possible.
Code:
digitalWrite(13, LOW);
// pulse pin 12 one time for one cycle:
digitalWrite(12, HIGH);
delay(timer);
digitalWrite(12, LOW);
delay(timer);
digitalWrite(13, LOW);
delay(timer);
digitalWrite(13, LOW);
delay(timer);

I changed my strategy I just needed to think in a new direction. Here is my code so far, I need
to make the interval adjustable and use micros instead of millis.
It uses a modified version of blink with out delay. I also put in prints in to show progress threw
the "if" statements.
/*

800rpm = 13.33Hz = 75ms per RPM/26 = 2.88ms per pulse set... time
between pulse state change is 1.44 ms
17,000rpm =283.33Hz = 3.529ms per RPM/26 = .1357ms per pulse set...
time between pulse state change is .06787ms

future use
int sensorPin = A0; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the
sensor
int val = 0;
sensorValue = analogRead(sensorPin);
val = map(sensorValue, 0, 1023, 0, 255);

*/
const int crankpin = 13; // the number of the LED pin //crank
pulse
const int campin = 12; // the number of the LED pin // cam
pulse
int ledState = LOW; // ledState used to set the LED
int ledState2 = LOW; // ledState used to set the LED
long previousMillis = 0; // will store last time LED was
updated
long interval = 500; // interval at which to blink
(milliseconds
int i = 1;


void setup() {
Serial.begin(9600);
// set the digital pin as output:
pinMode(crankpin, OUTPUT);
pinMode(campin, OUTPUT);
}

void loop()
{
unsigned long currentMillis = millis();

if(currentMillis - previousMillis > interval) {
if( i < 24){
Serial.println(i);
i = i++;
previousMillis = currentMillis;

if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(crankpin, ledState);
}
}

if(currentMillis - previousMillis > interval) {
if(i == 24 || i == 25){
Serial.println(i);
i = i++;
previousMillis = currentMillis;
if (ledState2 == LOW)
ledState2 = HIGH;
else
ledState2 = LOW;

digitalWrite(campin, ledState2);
}
}

if(currentMillis - previousMillis > interval) {
if (i ==26) {
Serial.println(i);
previousMillis = currentMillis;
///need some delay to keep cycles even
i = 1;
}
}

}



OK latest update. I have a pot that adjusts the interval that determines when cycles
occur. I am using a analogread and a map function to make it work with micros() to
adjust the interval. I have also added a Serial.print called Hz. to show the frequency of
the 26 pulse run. It does not work yet it keeps showing 0.00, I am still trying to figure it
out.

none working time code:
Code:
if (i == 2){
time = (currentMillis - previoustime);
Hz = (1 / time);
Serial.print("Time "); //print current interval
Serial.println(Hz);
previoustime = currentMillis;
}
/*

800rpm = 13.33Hz = 75ms per RPM/26 = 2.88ms per pulse set... time
between pulse state change is 1.44 ms
17,000rpm =283.33Hz = 3.529ms per RPM/26 = .1357ms per pulse set...
time between pulse state change is .06787ms


*/
int sensorPin = A0; // select the input pin for the
potentiometer
int sensorValue = 0; // variable to store the value coming
from the sensor
unsigned long val = 0; //value to be used with map
const int crankpin = 13; // the number of the LED pin //crank
pulse
const int campin = 12; // the number of the LED pin // cam
pulse
int ledState = LOW; // ledState used to set the LED
int ledState2 = LOW; // ledState used to set the LED
unsigned long previousMillis = 0; // will store last time LED was
updated
unsigned long interval = 500; // interval at which to blink
(milliseconds
unsigned long time = 0;
unsigned long previoustime = 0; // will store last time Time was
updated
float Hz = 0;
int i = 1;


void setup() {
Serial.begin(115200);
// set the digital pin as output:
pinMode(crankpin, OUTPUT);
pinMode(campin, OUTPUT);
}

void loop()
{
sensorValue = analogRead(sensorPin);
val = map(sensorValue, 0, 1023, 65, 1440); // interval adjuster
from .065ms to 1.44ms
interval = val;
unsigned long currentMillis = micros();

if (i == 2){
time = (currentMillis - previoustime);
Hz = (1 / time);
Serial.print("Time "); //print current interval
Serial.println(Hz);
previoustime = currentMillis;
}

if(currentMillis - previousMillis > interval) { // 24 cycles of HIGH
to LOW on pin 13 crankpin
if( i < 24){
Serial.println(i);
i = i++;
previousMillis = currentMillis;

if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(crankpin, ledState);
}
}

if(currentMillis - previousMillis > interval) { // 1st cycle of
LOW, LOW on pin 13 crankpin
if(i == 24 || i == 25){ // cycle High, Low
pin 12 cam pin
Serial.println(i);
i = i++;
previousMillis = currentMillis;
if (ledState2 == LOW)
ledState2 = HIGH;
else
ledState2 = LOW;

digitalWrite(campin, ledState2);
}
}

if(currentMillis - previousMillis > interval) { // 2nd cycle of LOW,
LOW on pin 13 crankpin
if (i == 26) {
Serial.println(i);
previousMillis = currentMillis;
///need some delay to keep cycles even
i = 1;
}
}

}



Here is the latest code. I have the Hz serial print working in what looks to be a correct way. My
Fluke meter says that I have frequency capability of 24Hz to 177Hz. My serial monitor shows
24 to 200. I can not run the loop faster than 200 at this point however. I need it to run up to
288Hz. I may have to use the new Fast write library that is on this forum.
/*

800rpm = 13.33Hz = 75ms per RPM/26 = 2.88ms per pulse set... time
between pulse state change is 1.44 ms
17,000rpm =283.33Hz = 3.529ms per RPM/26 = .1357ms per pulse set...
time between pulse state change is .06787ms


*/
int sensorPin = A0; // select the input pin for the
potentiometer
int sensorValue = 0; // variable to store the value coming
from the sensor
unsigned long val = 0; //value to be used with map
const int crankpin = 13; // the number of the LED pin //crank
pulse
const int campin = 12; // the number of the LED pin // cam
pulse
int ledState = LOW; // ledState used to set the LED
int ledState2 = LOW; // ledState used to set the LED
unsigned long previousMillis = 0; // will store last time LED
was updated
unsigned long interval = 500; // interval at which to blink
(milliseconds
unsigned long time = 0;
unsigned long previoustime = 0; // will store last time Time was
updated
float Hz = 0;
int i = 1;


void setup() {
Serial.begin(115200);
// set the digital pin as output:
pinMode(crankpin, OUTPUT);
pinMode(campin, OUTPUT);
}

void loop()
{
sensorValue = analogRead(sensorPin);
val = map(sensorValue, 0, 1023, 50, 1440); // interval adjuster
from .065ms to 1.44ms
interval = val;
unsigned long currentMillis = micros();



if(currentMillis - previousMillis > interval) { // 24 cycles of
HIGH to LOW on pin 13 crankpin
if( i < 24){
i = i++;
if (i == 2){
time = (currentMillis - previoustime);
Hz = (1000 / (time/1000));
Serial.println(Hz); //print current interval

previoustime = currentMillis;

}
previousMillis = currentMillis;

if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(crankpin, ledState);
}
}

if(currentMillis - previousMillis > interval) { // 1st cycle of
LOW, LOW on pin 13 crankpin
if(i == 24 || i == 25){ // cycle High, Low
pin 12 cam pin
i = i++;
previousMillis = currentMillis;
if (ledState2 == LOW)
ledState2 = HIGH;
else
ledState2 = LOW;

digitalWrite(campin, ledState2);
}
}

if(currentMillis - previousMillis > interval) { // 2nd cycle of
LOW, LOW on pin 13 crankpin
if (i == 26) {
previousMillis = currentMillis;
///need some delay to keep cycles even
i = 1;
}
}

}


My first comment is that all your times are held as micros so the variable names are
misleading.

Secondly, I would expect the logic to detect when one interval has elapsed to occur once, and
then use some sort of 'tooth count' to work out whether your output should be high or low.

Thirdly, I'm unclear from your description whether you are trying to emulate a 'missing tooth'
signal. For example a '25 -1' missing tooth signal would have three consecutive 'lows' at the
missing tooth, not two.

Fourthly, I suggest that whenever you have any conditional code (if, else, for, while, do etc)
you always put a compound statement i.e. { and } pair, even when you only have a single
statement in the conditional block. It is so easy to inadvertently tack an extra statement on, or
use a macro that silently expands to more than one statement, and suddenly the logic you see
doesn't match what actually happens.
val = map(sensorValue, 0, 1023, 50, 1440); // interval adjuster from .065ms to 1.44ms

As input and output range are almost equal in size you will get no nice transformation
by the map function. The potmeter/ADC will fluctuate in its readings so that might give
some unwanted effects. YOu can see this if you try to print interval every cycle....

refactored your code a bit
/*
* FILE:
* AUTHOR:
* DATE:
* PURPOSE:
* VERSION:
* HISTORY:
*
* NOTES
*
* 800rpm = 13.33Hz = 75ms per RPM/26 = 2.88ms per pulse set... time
between pulse state change is 1.44 ms
* 17,000rpm =283.33Hz = 3.529ms per RPM/26 = .1357ms per pulse set...
time between pulse state change is .06787ms
*
*/

int sensorPin = A0; // select the input pin for the
potentiometer
int sensorValue = 0; // variable to store the value coming
from the sensor

unsigned long val = 0; //value to be used with map
const int crankpin = 13; // the number of the LED pin //crank
pulse
const int campin = 12; // the number of the LED pin // cam
pulse

int ledState = LOW; // ledState used to set the LED
int ledState2 = LOW; // ledState used to set the LED

unsigned long previousMicros = 0; // will store last time LED was
updated
unsigned long interval = 500; // interval at which to blink
(milliseconds
unsigned long time = 0;
unsigned long previousTime = 0; // will store last time Time was
updated
float Hz = 0;
int i = 1;


void setup()
{
Serial.begin(115200);
// Serial.println("Start...");
// set the digital pin as output:
pinMode(crankpin, OUTPUT);
pinMode(campin, OUTPUT);
}

void loop()
{
sensorValue = analogRead(sensorPin);
interval = map(sensorValue, 0, 1023, 65, 1440); // interval
adjuster from .065ms to 1.44ms

unsigned long currentMicros = micros();

time = currentMicros - previousMicros;
if (time > interval) // 24 cycles of
HIGH to LOW on pin 13 crankpin
{
previousMicros = currentMicros;
i++;

if (i == 2)
{
time = currentMicros - previousTime;
previousTime = currentMicros;
Hz = 1000000.0 / time;
Serial.println(Hz, 2); // 2 digits
}

if (i < 24)
{
ledState = !ledState; // 1 -> 0 -> 1 -> 0
etc
digitalWrite(crankpin, ledState);
}

if (i == 24 || i == 25)
{
ledState2 == !ledState2;
digitalWrite(campin, ledState2);
}

if (i == 26)
{
/// need some delay to keep cycles even
i = 1;
}
}
}

1) My first comment is that all your times are held as micros so the variable names are
misleading.

2) Secondly, I would expect the logic to detect when one interval has elapsed to occur
once, and then use some sort of 'tooth count' to work out whether your output should
be high or low.

3) Thirdly, I'm unclear from your description whether you are trying to emulate a
'missing tooth' signal. For example a '25 -1' missing tooth signal would have three
consecutive 'lows' at the missing tooth, not two.

4) Fourthly, I suggest that whenever you have any conditional code (if, else, for,
while, do etc) you always put a compound statement i.e. { and } pair, even when you
only have a single statement in the conditional block. It is so easy to inadvertently tack
an extra statement on, or use a macro that silently expands to more than one statement,
and suddenly the logic you see doesn't match what actually happens.

Thank you for your interest and tips. PeterH.

1) Yes, I should have corrected my variable names. I started writing the program using
millis() until I realized that I had to have micros(). I did not correct it after that.

2) You may be correct.

3) Yes, I am trying to emulate a 'missing tooth' signal. I thought it was '26 -2' but, I
got some new information that it is '24 -2'. Based on your advice about a '25-1' wheel
I think I need 5 consecutive 'lows' for my wheel at the missing tooth. Thanks for that
tip.

4) I will have to look my code over more to see where the { } error is but, I will try to
fix it.

Quote
val = map(sensorValue, 0, 1023, 50, 1440); // interval adjuster from .065ms to 1.44ms

As input and output range are almost equal in size you will get no nice transformation
by the map function. The potmeter/ADC will fluctuate in its readings so that might give
some unwanted effects. YOu can see this if you try to print interval every cycle....

You are correct about the results of the map function that I wrote. It was not very linear
and I did not like the way it was working.

Also, thank you for reworking my sketch! I was struggling to solve my Hz display. I
am going to try you method right away.

As I said in the above post, I will have to correct the sketch from 26 cycles to 24. But
that is easy enough.

Thank you for you help, I will keep working at it.
Here is my latest code with many improvements implemented from the suggestions given. I
had to double the numbers in the "if" statements to get my '24-2' wheel result because using
the shorter code that Robtillart gave me cut everything in half. I am using a Parallax USB
Oscilloscope to check the pulses and the crankpin and campin timing look very good.

My Hz display now works flawlessly but, the fastest my Uno can run is 106 cycles per second I
am calling that Hz. I need to run at 288. My next version will have the new fastwrite library in
it.
/*
* FILE:Crank Pulse Simulator
* AUTHOR:Mark M. with help from Robtillart
* DATE:1/22/12
* PURPOSE: Simulate the output of a '24-2' crank encoder wheel and
camshaft timing pin
* VERSION:1
* HISTORY:
*
* NOTES
*
* 800rpm = 13.33Hz = 75ms per RPM/26 = 2.88ms per pulse set... time
between pulse state change is 1.44 ms
* 17,000rpm =283.33Hz = 3.529ms per RPM/26 = .1357ms per pulse set...
time between pulse state change is .06787ms
*
*/

int sensorPin = A0; // select the input pin for the
potentiometer
int sensorValue = 0; // variable to store the value coming
from the sensor

unsigned long val = 0; //value to be used with map
const int crankpin = 13; // the number of the LED pin //crank
pulse
const int campin = 12; // the number of the LED pin // cam
pulse

int ledState = LOW; // ledState used to set the LED
int ledState2 = LOW; // ledState used to set the LED

unsigned long previousMicros = 0; // will store last time LED was
updated
unsigned long interval = 500; // interval at which to blink
(milliseconds
unsigned long time = 0;
unsigned long previousTime = 0; // will store last time Time was
updated
float Hz = 0;
int i = 0;


void setup()
{
Serial.begin(115200);
Serial.println("Start...");
// set the digital pin as output:
pinMode(crankpin, OUTPUT);
pinMode(campin, OUTPUT);
delay(1000);
}

void loop()
{
sensorValue = analogRead(sensorPin);
interval = map(sensorValue, 0, 1023, 65, 1595); // interval
adjuster from .065ms to 1.44ms

unsigned long currentMicros = micros();

time = currentMicros - previousMicros;
if (time > interval) // 22 cycles of
HIGH to LOW on pin 13 crankpin
{
previousMicros = currentMicros;
i++;
if (i <= 44)
{
ledState = !ledState; // 1 -> 0 -> 1 -> 0
etc
digitalWrite(crankpin, ledState);
}

if (i == 45 || i == 46)
{ //first of two cycles of
LOW, LOW on crankpin
ledState2 = !ledState2;
digitalWrite(campin, ledState2);

}

if (i == 47)
{ //second of two cycles of
LOW, LOW on crankpin
time = currentMicros - previousTime;
previousTime = currentMicros;
Hz = 1000000.0 / time;
Serial.println(Hz, 2); // 2 digits

/// need some delay to keep cycles even

}

if (i == 47 || i == 48)
{
/// need some delay to keep cycles even
i = 0;
}

}
}

Here is my next revision of my code. I increased my loop cycles per second from 106 to 120 by
using the new DigitalPin.h library and commenting out the Serial.Print. DigitalPin.h library gave
me a 13% speed increase which is impressive but, sadly I need 288 loop cycles per second so, I
may be at the limit of the 16MHz Arduino.

If anyone has a suggestions to increase my speed I am ready to hear it. I have enjoyed writing
this code even though I have not reached my goal.
/*
* FILE:Crank Pulse3
* AUTHOR:Mark M. with help from Robtillart
* DATE:1/22/12
* PURPOSE: Simulate the output of a '24-2' crank encoder wheel and
camshaft timing pin
* VERSION:2
* HISTORY:
*Old version would run up to 106 cycles per second
*This version runs up to 120 cycles per second because faster
Digital.Write and not using serail.
*
* NOTES
* changing from standard digital.Write to DigitalPin.h methods
*commented out Serial.print to maximize speed of loop
*
* 800rpm = 13.33Hz = 75ms per RPM/26 = 2.88ms per pulse set... time
between pulse state change is 1.44 ms
* 17,000rpm =283.33Hz = 3.529ms per RPM/26 = .1357ms per pulse
set... time between pulse state change is .06787ms
*
*/
#include <DigitalPin.h>

int sensorPin = A0; // select the input pin for the
potentiometer
int sensorValue = 0; // variable to store the value coming
from the sensor

DigitalPin<13> pin13; // the number of the LED pin //crank pulse
DigitalPin<12> pin12; // the number of the LED pin // cam pulse
//const int crankpin = 13; // the number of the LED pin //crank
pulse
//const int campin = 12; // the number of the LED pin // cam
pulse

int ledState = LOW; // ledState used to set the LED
int ledState2 = LOW; // ledState used to set the LED

unsigned long previousMicros = 0; // will store last time LED
was updated
unsigned long interval = 500; // interval at which to blink
(milliseconds
unsigned long time = 0;
unsigned long previousTime = 0; // will store last time Time was
updated
float Hz = 0;
int i = 0;


void setup()
{
Serial.begin(115200);
Serial.println("Start...");
// set the digital pin as output:
//pinMode(crankpin, OUTPUT);
//pinMode(campin, OUTPUT);
pin13.outputMode();
pin12.outputMode();
delay(1000);
}

void loop()
{
sensorValue = analogRead(sensorPin);
interval = map(sensorValue, 0, 1023, 65, 1595); // interval
adjuster from .065ms to 1.44ms

unsigned long currentMicros = micros();

time = currentMicros - previousMicros;
if (time > interval) // 22 cycles of
HIGH to LOW on pin 13 crankpin
{
previousMicros = currentMicros;
i++;
if (i <= 44)
{
ledState = !ledState; // 1 -> 0 -> 1 -> 0
etc
if (ledState == LOW) {
pin13.low();
}
else {
pin13.high();
}

}


if (i == 45 || i == 46)
{ //first of two cycles of
LOW, LOW on crankpin
ledState2 = !ledState2;
if (ledState2 == LOW) {
pin12.low();
}
else {
pin12.high();
}

}


if (i == 47)
{ //second of two cycles of
LOW, LOW on crankpin
time = currentMicros - previousTime;
previousTime = currentMicros;
Hz = 1000000.0 / time;
//Serial.println(Hz, 2); // 2 digits

/// need some delay to keep cycles even

}

if (i == 47 || i == 48)
{
/// need some delay to keep cycles even
i = 0;
}

}
}

Here is a sketch I made using DigitalPin.h library and delayMicroseconds() to get my pulse
interval correct. It works well except the Analog.read takes too long it seems to be 130us
seconds and makes an uneven gap during the read. The map function takes about 70us.
Maybe I can somehow relocate there spot in the loop and still use them. I will have to think
about it.
// scope test for write timing
#include <DigitalPin.h>

// class with compile time pin number
DigitalPin<13> pin13;
DigitalPin<12> pin12;
int time = 0;
int sensorPin = A0; // select the input pin for the
potentiometer
int sensorValue = 0; // variable to store the value coming
from the sensor

void setup() {
// set mode to OUTPUT
pin13.outputMode();
pin12.outputMode();
}
void loop() {
sensorValue = analogRead(sensorPin);
time = map(sensorValue, 0, 1023, 65, 1595); // interval
adjuster from .065ms to 1.44ms
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
pin12.high();
delayMicroseconds(time);
pin13.low();
pin12.low();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);


}
This sketch provides even spacing but, only with 65us delays. If the delay is reduced spacing
will not be equal.
// scope test for write timing
#include <DigitalPin.h>

// class with compile time pin number
DigitalPin<13> pin13;
DigitalPin<12> pin12;
int time = 0;
int sensorPin = A0; // select the input pin for the
potentiometer
int sensorValue = 0; // variable to store the value coming
from the sensor

void setup() {
// set mode to OUTPUT
pin13.outputMode();
pin12.outputMode();
}
void loop() {

pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
delayMicroseconds(time);
pin13.low();
delayMicroseconds(time);
pin13.high();
pin12.high();
delayMicroseconds(time);
pin13.low();
pin12.low();
delayMicroseconds(time);
pin13.low();
sensorValue = analogRead(sensorPin);
//delayMicroseconds(time - 65);
pin13.low();
//delayMicroseconds(time - 65);
pin13.low();
time = map(sensorValue, 0, 1023, 65, 1595); // interval
adjuster from .065ms to 1.44ms
//delayMicroseconds(time - 65);
pin13.low();
delayMicroseconds(time);

}


/*
60-2 tooth CAS signal generator for bench testing Bosch Motronic
ECUs.
Connect a linear 10k potentiometer's pin 1 to VCC, pin 2 to A0, pin
3 to GND.
TTL CAS signal output is on pin 12.
*/

int PotPin = A0; // the input pin for the
potentiometer
int PotValue = 0; // variable to store the value
coming from the sensor
int CASpin = 12; // CAS out pin
int LEDpin = 13; // on-board LED

void setup() {
pinMode(CASpin, OUTPUT);
pinMode(LEDpin, OUTPUT);
}

void loop() {
PotValue = analogRead(PotPin); // read the value from the
potentiometer
digitalWrite(LEDpin,LOW);
int PulseDelay = 50000 / PotValue; // 50000 gives >7000 rpm which
is enough
if (PotValue > 5) // Stop signal output
at minimum pot value
{
digitalWrite(LEDpin,HIGH); // LED indicates CAS signal
status
for (int j = 0; j < 5; j++) // Update the RPM only
every few revolutions
{
for (int i = 0; i < 58; i++) // 58 of the 60 teeth
high/pause/low/pause cycle
{
digitalWrite(CASpin, HIGH);
delayMicroseconds(PulseDelay);
digitalWrite(CASpin, LOW);
delayMicroseconds(PulseDelay);
}
for (int i = 0; i < 4; i++) // 2 missing teeth are
low for both halves of cycle
{
delayMicroseconds(PulseDelay);
}
}
}
}




EDIT: slo soy capaz de llegar a 120 Hz o 7.200 rpm con un boceto que es un poco mejor que ste. Necesito un chip
ms rpido.

En mi post anterior me pareci que la rueda del cigeal tena 24 dientes y 2 zonas sin cubrir, pero ahora me doy
cuenta de que es de 22 dientes con 2 reas descubiertas = 24 as decirlo.
Tengo un cdigo para generar los pulsos y reporte el Hz de rpms. La Hz es ajustable con un bote. Estoy mostrando un
extremo inferior de 1280rpm hasta ahora. En el momento que estoy limitado a alrededor de 120 Hz o 7.200 rpm. Mi Hz
impresin no funciona correctamente al 100% todava. Yo lo la impresin tiene un problema de redondeo en los
clculos.
Aqu est el cdigo si alguien puede leerlo.

[code]/*
///this math needs work
800rpm = 13.33Hz = .075ms per RPM/24 = 3.1ms per pulse set... time between pulse state change is 1.56 ms
17,000rpm =283.33Hz = 3.529ms per RPM/24 = .147ms per pulse set... time between pulse state change is .0735ms


*/
int sensorPin = A0; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
unsigned long val = 0; //value to be used with map
const int crankpin = 13; // the number of the LED pin //crank pulse
const int campin = 12; // the number of the LED pin // cam pulse
int ledState = LOW; // ledState used to set the LED
int ledState2 = LOW; // ledState used to set the LED
unsigned long previousMillis = 0; // will store last time LED was updated
unsigned long interval = 500; // interval at which to blink (milliseconds
unsigned long time = 0;
unsigned long previoustime = 0; // will store last time Time was updated
float rpm = 0;
int i = 1;


void setup() {
Serial.begin(115200);
// set the digital pin as output:
pinMode(crankpin, OUTPUT);
pinMode(campin, OUTPUT);
}

void loop()
{
sensorValue = analogRead(sensorPin);
val = map(sensorValue, 0, 1023, 50, 1440); // interval adjuster from .065ms to 1.44ms
interval = val;
unsigned long currentMillis = micros();



if(currentMillis - previousMillis > interval) { // 24 cycles of HIGH to LOW on pin 13 crankpin
if( i < 22){
i = i++;
if (i == 2){
time = (currentMillis - previoustime);
rpm = (1000 / (time/1000));
Serial.println(rpm * 60); //print current interval

previoustime = currentMillis;

}
previousMillis = currentMillis;

if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(crankpin, ledState);
}
}

if(currentMillis - previousMillis > interval) { // 1st cycle of LOW, LOW on pin 13 crankpin
if(i == 22 || i == 23){ // cycle High, Low pin 12 cam pin
i = i++;
previousMillis = currentMillis;
if (ledState2 == LOW)
ledState2 = HIGH;
else
ledState2 = LOW;

digitalWrite(campin, ledState2);
}
}

if(currentMillis - previousMillis > interval) { // 2nd cycle of LOW, LOW on pin 13 crankpin
if (i == 24) {
previousMillis = currentMillis;
///need some delay to keep cycles even
i = 1;
}
}

}

/**
crank signal simulator
*/

#define PULSE_PIN 10


void setup() {
pinMode(PULSE_PIN, OUTPUT);
}

/**
Simulate the high of a tooth on a
reluctor wheel
*/
void triggerHigh(int duration) {
digitalWrite(PULSE_PIN, HIGH);
delayMicroseconds(duration);
digitalWrite(PULSE_PIN, LOW);
}

/**
Simulate the reference marker on a
reluctor wheel
*/
void triggerReference(int duration) {
// pin should be low already
delayMicroseconds(duration);
delayMicroseconds(duration); // two delays for two missing pulses.
}


/**
Simulates a 58 tooth reluctor wheel
with a 2 tooth reference
*/
void loop(){
int val = analogRead(0);
val = map(val, 0, 1023, 100, 3500);

for(int i = 0; i <= 58; i++) {
triggerHigh(val);
delayMicroseconds(val);
}
triggerReference(val);
delayMicroseconds(val);
}






**
crank signal simulator
*/

#define PULSE_PIN 10

void setup() {
pinMode(PULSE_PIN, OUTPUT);
}

/**
Simulate the high of a tooth on a
reluctor wheel
*/
void triggerHigh(int duration) {
digitalWrite(PULSE_PIN, HIGH);
delay(duration);
digitalWrite(PULSE_PIN, LOW);
}

/**
Simulate the reference marker on a
reluctor wheel
*/
void triggerReference(int duration) {
// pin should be low already
delay(duration);
}


/**
Simulates a 35 tooth reluctor wheel
with a reference tooth
*/
void loop() {
for(int i = 0; i <= 35; i++) {
triggerHigh(5);
delay(5);
}
triggerReference(5);
delay(5);
}

You might also like