So the project is to control a small steam engine with an Arduino UNO board. We wanted to put a hall sensor on the crank and use that input (once per rev) to open and close a couple solenoids to control the flow of steam into the cylinder. Eventually we would like to add in an abilities to throttle the engine, advance or retard the timing as RPM changes, monitor steam pressure on the boiler and adjust the flame accordingly, maybe display this info to an LCD, but right now just a flat timing map just to run the engine will be a good first step.
This is the code so far, and it appears to work well, expect one problem: every few seconds it appears to hiccup. I'm wondering if I'm using the delay command incorrectly and that's causing problems. Another thought was maybe it runs out of memory (since the micros numbers get pretty big, pretty quick), the code just simply isn't written correctly and this approach is just wrong, or the maybe the UNO isn’t the best board for the job? I’m not sure.
I set up a couple LED’s on a bread board to simulate the intake and exhaust solenoid. I took a video of it running at a consistent 600rpm so you guys can get a better idea what I'm talking about. We are using a function generator to simulate the hall sensor input right now, its set at 10hz. Here is a link to the video. The green LED represents the intake solenoid, the red is exhaust.
I found this thread , where Newman180 is trying to accomplish something similar, but I wasn’t able to find what I was looking there.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1289168643/all
I did my best to comment the code as clearly as possible. I’m going to monitor this thread consistently, so if there is something in the code you don’t understand, or something I failed to clarify in this post, just ask and I’ll explain ASAP.
Thanks in advance guys, I’m looking forward to getting this running!
unsigned long revPeriod; // Microseconds for 1 revolution of crankshaft
unsigned long prevTDCtime; // Previous time Hall Sensor Picked up
unsigned long TDCtime; // Current TDC Time
unsigned long crankAngle; // Microseconds per angle of Crankshaft Rotation
unsigned long intake; // Variable in microseconds for intake valve to open
unsigned long intake2; // Variable in microseconds for intake valve to close
unsigned long exhaust; // Variable in microseconds for exhaust valve to open
unsigned long exhaust2; // Variable in microseconds for exhaust valve to close
unsigned int RPM; // define RPM, used only as a serial output
int number = 0; // number used to stop loop from running continuously
void setup()
{
Serial.begin(9600); // Communicate to Serial Port
pinMode (8, OUTPUT); // set pin 8 (intake) as an output
pinMode (11, OUTPUT); // set pin 11 (exhaust) as an output
attachInterrupt(0,TDCinterrupt, RISING); // Interrupt 0 is Pin 2 Hall Effect Sensor
}
void TDCinterrupt()
{
prevTDCtime = TDCtime; // sets prevTDCtime equal to the last time the TDC sensor was triggered (used later to calculate angle)
TDCtime = micros(); // sets TDCtime equal to the current micros counter
number = 1; // sets "number" equal to 1 which will allow the next if statement to run
}
void loop ()
{
if (number == 1)
{
revPeriod = (TDCtime - prevTDCtime); // rev period is Microseconds for 1 revolution of crankshaft
crankAngle = (revPeriod/360); // microseconds per angle of Crankshaft Rotation
RPM = (60000000/revPeriod); // divide 60 million (number of microseconds in a min) by the time it took the crank to go around once, to get RPM
intake = ((crankAngle * 2)/1000); //how long to wait in microseconds to open the intake valve then divide by 1000 to get milliseconds
intake2 = ((crankAngle * 100)/1000); //how long to wait in microseconds to close the intake valve then divide by 1000 to get milliseconds
exhaust = ((crankAngle * 30)/1000); //how long to wait in microseconds to open the exhaust valve then divide by 1000 to get milliseconds
exhaust2 = ((crankAngle * 100)/1000); //how long to wait in microseconds to close the exhaust valve then divide by 1000 to get milliseconds
//we found the delayMicroseconds didn't work as expected, which is the justification for converting micro to millis^^
delay(intake); // delay "intake" number of milliseconds
digitalWrite (8, HIGH); // open intake valve
delay(intake2); // delay "intake2" number of milliseconds
digitalWrite (8, LOW); // close intake valve
delay(exhaust); // delay "exhaust" number of milliseconds
digitalWrite (11, HIGH); // open exhaust valve
delay(exhaust2); // delay "exhaust2" number of milliseconds
digitalWrite (11, LOW); // close exhaust valve
Serial.print(" "); // print out all the numbers just so we can see them and confirm the math was correct.
Serial.print(prevTDCtime);
Serial.print(" ");
Serial.print(revPeriod);
Serial.print(" ");
Serial.print(crankAngle);
Serial.print(" ");
Serial.print(RPM);
Serial.println();
Serial.print(intake);
Serial.print(" ");
Serial.print(intake2);
Serial.print(" ");
Serial.print(exhaust);
Serial.print(" ");
Serial.print(exhaust2);
Serial.println();
Serial.println(number);
}
number = 0; // set number to 0 so the loop won't run again until the interrupt sets it back to 1 (simplest way I could think to do it)
}