Any engine control unit uses crankshaft and camshaft position to determine the timing of the various events needed to run an engine. The D16 series Honda engine has three variable reluctance (VR) wheels located in the distributor. The first wheel has one tooth on it which provides an index for the other two wheels. The second has 4 teeth on it and are positioned such that the pistons are at top dead center (TDC) when the tooth is positioned over the magnet. Finally the third wheel has 16 teeth on it to provide a crankshaft position signal (CPS). A photo of the interior of the distributor and a three dimensional drawing of the Honda VR wheels is shown.
I’ll cover a little on how a VR wheel works for those who might not be familiar with them. A permanent magnet is connected to a two transistor circuit which amplifies the signal produced when a ferrous object enters the magnetic field. When the ferrous object leaves the magnetic field the signal goes negative. The resulting AC signal can then be used for timing. You can look up magnetic reluctance for a more detailed explanation.
These signals must be converted to a useful digital waveform that can be subsequently used by the microprocessor. This can be done by using the MAXIM 9926 chip, the National Semi LM 1815 or I used the ON Semi NCV1124. The ON Semi chip was used because it needs a very minimal part count for functionality and I can hand solder the surface mount package to an adapter board. Here's the NCV1124 Data Sheet I initially used the LM 1815 chip but there were two problems using it. It has become obsolete, and at low rotational velocities it misses some of the VR output signals. This is the as built circuit that I used.
To develop and test the VR signal generator circuit I simulated the spinning crankshaft by attaching a two speed motor to the cam shaft with the valve arms removed from the head. This gave me a free spinning system with a variable rotational velocity. You can see it in the next photo.
/*This routine simulates the output from the distributor of a
1980's to 2000 Honda motor
*/
#include <digitalWriteFast.h>
int rpm;
String inputString = ""; // a String to hold incoming data
bool stringComplete = false; // whether the string is complete
// constants won't change. Used here to set the pins
const int outCYL = 2;// the number of the pin
const int outTDC = 3;// the number of the pin
const int outCPS = 4;// the number of the pin
int outStateCYL = LOW;
int outStateTDC = LOW;
int outStateCPS = LOW;
// Time variables
unsigned long newCYL;
unsigned long oldCYL;
unsigned long newTDC;
unsigned long oldTDC;
unsigned long newCPS;
unsigned long oldCPS;
unsigned long intervalCYL;
unsigned long intervalTDC;
unsigned long intervalCPS;
unsigned long cycle;
unsigned long delayTDC, durTDC, delayCPS, durCPS, durCYL;
void setup() {
// set the pins and the serial set-up for checking things:
pinModeFast(outCYL, OUTPUT);
pinModeFast(outTDC, OUTPUT);
pinModeFast(outCPS, OUTPUT);
Serial.begin(9600);
// reserve 200 bytes for the inputString:
inputString.reserve(200);
//initialize a cycle value
cycle = 50000;
Serial.println("Enter a RPM value");
}
void loop() {
if (stringComplete) {
rpm = inputString.toInt();
cycle = 1000000 / (rpm / 60);
Serial.print("Cycle Time = ");
Serial.print(cycle);
Serial.println(" us");
Serial.println("Enter a RPM value");
// clear the string:
inputString = "";
stringComplete = false;
}
newCYL = micros();
durCYL = cycle / 25;
delayTDC = cycle / 100;
durTDC = cycle / 25;
delayCPS = delayTDC - 100;
durCPS = cycle / 28;
if (newCYL - oldCYL >= cycle ) {
oldCYL = newCYL;
}
intervalCYL = newCYL - oldCYL;
//Serial.print(" ");
if (intervalCYL >= 0 && intervalCYL <= 3100) {
outStateCYL = LOW;
digitalWriteFast(outCYL, outStateCYL);
}
else {
outStateCYL = HIGH;
digitalWriteFast(outCYL, outStateCYL);
}
//TDC
if (intervalCYL >= delayTDC && intervalCYL < durTDC) {
outStateTDC = LOW;
digitalWriteFast(outTDC, outStateTDC);
}
if (intervalCYL >= durTDC && intervalCYL < delayTDC + cycle / 4) {
outStateTDC = HIGH;
digitalWriteFast(outTDC, outStateTDC);
}
if (intervalCYL >= delayTDC + cycle / 4 && intervalCYL < durTDC + cycle / 4) {
outStateTDC = LOW;
digitalWriteFast(outTDC, outStateTDC);
}
if (intervalCYL >= durTDC + cycle / 4 && intervalCYL < cycle / 2) {
outStateTDC = HIGH;
digitalWriteFast(outTDC, outStateTDC);
}
if (intervalCYL >= delayTDC + cycle / 2 && intervalCYL < durTDC + cycle / 2) {
outStateTDC = LOW;
digitalWriteFast(outTDC, outStateTDC);
}
if (intervalCYL >= durTDC + cycle / 2 && intervalCYL < 3 * cycle / 4) {
outStateTDC = HIGH;
digitalWriteFast(outTDC, outStateTDC);
}
if (intervalCYL >= delayTDC + 3 * cycle / 4 && intervalCYL < durTDC + 3 * cycle / 4) {
outStateTDC = LOW;
digitalWriteFast(outTDC, outStateTDC);
}
if (intervalCYL >= durTDC + 3 * cycle / 4 ) {
outStateTDC = HIGH;
digitalWriteFast(outTDC, outStateTDC);
}
//---------------------------------------//
//CPS
if (intervalCYL >= delayCPS && intervalCYL < durCPS) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS && intervalCYL < delayCPS + cycle / 16) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + cycle / 16 && intervalCYL < durCPS + cycle / 16) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + cycle / 16 && delayCPS + intervalCYL < cycle / 8) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + cycle / 8 && intervalCYL < durCPS + cycle / 8) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + cycle / 8 && intervalCYL < 3 * cycle / 16) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 3 * cycle / 16 &&;amp; intervalCYL < durCPS + 3 * cycle / 16) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 3 * cycle / 16 && intervalCYL < delayCPS + cycle / 4) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + cycle / 4 && intervalCYL < durCPS + cycle / 4) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + cycle / 4 && intervalCYL < delayCPS + 5 * cycle / 16) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 5 * cycle / 16 && intervalCYL < durCPS + 5 * cycle / 16) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 5 * cycle / 16 && intervalCYL < delayCPS + 3 * cycle / 8) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 3 * cycle / 8 && intervalCYL < durCPS + 3 * cycle / 8) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 3 * cycle / 8 && intervalCYL < delayCPS + 7 * cycle / 16) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 7 * cycle / 16 && intervalCYL < durCPS + 7 * cycle / 16) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 7 * cycle / 16 && intervalCYL < delayCPS + cycle / 2) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + cycle / 2 && intervalCYL < durCPS + cycle / 2) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + cycle / 2 && intervalCYL < delayCPS + 9 * cycle / 16) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 9 * cycle / 16 && intervalCYL < durCPS + 9 * cycle / 16) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 9 * cycle / 16 && intervalCYL < delayCPS + 5 * cycle / 8) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 5 * cycle / 8 && intervalCYL < durCPS + 5 * cycle / 8) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 5 * cycle / 8 && intervalCYL < delayCPS + 11 * cycle / 16) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 11 * cycle / 16 && intervalCYL < durCPS + 11 * cycle / 16) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 11 * cycle / 16 && intervalCYL < delayCPS + 3 * cycle / 4) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 3 * cycle / 4 && intervalCYL < durCPS + 3 * cycle / 4) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 3 * cycle / 4 && intervalCYL < delayCPS + 13 * cycle / 16) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 13 * cycle / 16 && intervalCYL < durCPS + 13 * cycle / 16) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 13 * cycle / 16 && intervalCYL < delayCPS + 7 * cycle / 8) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 7 * cycle / 8 && intervalCYL < durCPS + 7 * cycle / 8) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 7 * cycle / 8 && intervalCYL < delayCPS + 15 * cycle / 16) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= delayCPS + 15 * cycle / 16 && intervalCYL < durCPS + 15 * cycle / 16) {
outStateCPS = LOW;
digitalWriteFast(outCPS, outStateCPS);
}
if (intervalCYL >= durCPS + 15 * cycle / 16 ) {
outStateCPS = HIGH;
digitalWriteFast(outCPS, outStateCPS);
}
}
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag so the main loop can
// do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
I now had a system where I could do all the programming and debugging
at my desk. I hooked up the outputs from my crank timer board to another
microprocessor board and I was ready to program the main board. One
advantage of doing this was that it allowed me to use the development
suite extensively and move up the learning curve. With this system
connected and the Serial Monitor in the Arduino IDE is opened it asks
for a RPM input. When it’s entered the crank timer board changes the
interval timing so I could check my spark and injection timing at
various simulated crank velocities. The first photo is of the
oscilloscope screen of the simulated CYL and CPS signals. The second
photo is of the simulated CYL and TDC signals.
No comments:
Post a Comment