My engine has two ignition devices that pulse at up to 6000PPM. The pulse is a 12V output though the manufacturer of the device has provision for installation of a zener diode to drop the voltage to 5V (I don't suppose it would hurt anything to use a different zener to get 3.3V if necessary). I need to read the pulses and determine the time difference between them. Ideally they should be pulsing at exactly the same time but of course they could diverge by some amount and not be an issue. I want to be able to generate an alert if the pulses diverge by more than 3 degrees of rotation.
Initially I was thinking of using two pro minis to do the timing and then another to drive the display. I believe I need to rethink this because timing divergence would require sensing the input on the same device for best accuracy. I think that I will need to use two interrupts and measure the delta between pulses. I understand the examples I've found with single interrupts but haven't found any samples with multiple interrupts and acting on information about them or how quickly the arduino can handle each interrupt.
How are multiple interrupts handled by the arduino? Does it see the first one and act on it then the second then back to the first and so on? If I set a variable to the time of the state change to HI on the first interrupt then wait for the second to change to HI, what is the potentially smallest amount of time between populating those to variables? 6000PPM is equal to 3000RPM so for example I calculate at 2700RPM (5400PPM) the crank rotates one degree in .000061 seconds. If I am running at 2700RPM, the arduino sees the first pulse then waits for the second, I am wondering about the smallest time because I need an alert generated if the divergence is more than 3 degrees - or about .00018 seconds.
You'd be better off not using interrupts. I would connect both inputs to the same port and read that port in a tight loop until one of the bits you are interested in changes. Then read the timer 2 register. Then wait until the other bit changes (unless it changed at the same time), then read timer 2 again. This will give you resolution of a few microseconds. If the timer interrupt occurs during this process then it will give you an incorrect interval, but you can detect that and throw away that reading.
Probably the most precise method is to use an Arduino Mega since it has multiple input capture pins. The input capture features takes a snapshot of one of the timers when an I/O pin changes.
At 16 MHz, you can then get resolution of 1/16e6 = 62.5 nanoseconds. If you need 0.00018 seconds (180 microseconds) of resolution then 62.5 nanoseconds is 2880 times better than that
This suggests you could just use the sit-in-a-tight-loop approach. As long as you're not doing anything else in your code it shouldn't have any trouble achieving 180 microseconds of resolution.
--
The Ruggeduino: compatible with Arduino UNO, 24V operation, all I/O's fused and protected
I don't understand 'read until one of the bits changes'. If I have two inputs (simply at 5V pulse) I can see putting them on the same pin but I don't see where the 'bit changes' fits.
@rugged The mega capability sounds great. I am hoping to avoid the size of the mega though. I will research to see if there is another smaller arduino that can do the pin capture.
No, if you have two inputs you would not put them on the same pin; you would use two different pins. Then your code might look like:
void setup(void) {
pinMode(TACH1, INPUT); // #define TACH1 and TACH2 to be your input pins
pinMode(TACH2, INPUT);
Serial.begin(38400);
}
void loop(void) {
unsigned long trap1, trap2;
while (digitalRead(TACH1)==HIGH) /* do nothing until pin goes LOW */ ; // <--note semicolon
trap1 = TCNT2;
while (digitalRead(TACH2)==HIGH) /* do nothing until pin goes LOW */ ; // <--note semicolon
trap2 = TCNT2;
Serial.println(trap2-trap1);
}
Now there are lots of ways to improve the above: what happens if one pin is already low (the code assumes both pins start high), do you need pullup resistors, etc. etc. But I believe the code represents the basics of what was suggested.
--
The Gadget Shield: accelerometer, RGB LED, IR transmit/receive, speaker, microphone, light sensor, potentiometer, pushbuttons
That code assumes TACH1 will go low before TACH2 but if I understand OP right it can also be the other way.
This variation
void loop(void) {
unsigned long trap1, trap2;
while (digitalRead(TACH1) == digitalRead(TACH2)); /* do nothing until one pin changes
trap1 = TCNT2;
while (digitalRead(TACH1) != digitalRead(TACH2)); /* do nothing until they are the same again
trap2 = TCNT2;
Serial.println(trap2 - trap1);
}
@rob - That sounds really good except as I read pulseIn() it times the duration of a high or low input. I believe I would need to time 'rising edge to rising edge' to measure the time between pulses, correct?
pmn1: @rob - That sounds really good except as I read pulseIn() it times the duration of a high or low input. I believe I would need to time 'rising edge to rising edge' to measure the time between pulses, correct?
The output of an XOR gate is logic high when its 2 inputs are different (one high and one low). Therefore, the output will go high at the rising edge of the first pulse and remain high until the rising edge of the second pulse, at which point it will go low again. The same will happen if one pulse ends before the other. So the output comprises 2 pulses; the width of the first is the difference in time between the rising edges of the 2 input pulses, and the width of the second is the difference in time between the falling edges of the pulses, assuming the pulses overlap. Therefore, if you can use pulsein() to measure the width of the first pulse and ignore the second one, it will do what you want.
Ah! You are most correct. I even have that drawn on my whiteboard but didn't make the correlation between rise/drop relationship from the xor. I went to the local supply store and picked up a couple 7486 XOR ICs. Will give it a go this weekend. Thanks!