-
Notifications
You must be signed in to change notification settings - Fork 25
Allows for separate angles with Intake and Exhaust plus removed the print statements from the interrupt callback. #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| // An Arduino program for controlling valve timing on a 6.5ph Predator engine from Harbor Freight. | ||
| // | ||
| // Wesley Kagan, 2020 | ||
| // Ric Allinson, 2020 | ||
|
|
||
| // Control variables. | ||
| const int DEG_PER_MAGNET = 6; // Number of degrees for each magnet. | ||
| const int FREEVALVE_OFFSET_TOP = 0; // The amount of off set from TDC (needs to be multiples of DEG_PER_MAGNET). | ||
| const int FREEVALVE_OFFSET_BOTTOM = 180 + FREEVALVE_OFFSET_TOP; | ||
|
|
||
| // Pins assignment. | ||
| const int HALL_MAGNET = 2; | ||
| const int EXHAUST_V = 12; | ||
| const int INTAKE_V = 13; | ||
|
|
||
| int cad; // Crank Angle Degrees (CAD). | ||
| int hallCounter; // The number of magnets after the last TDC. | ||
| bool cycle; // "true" for Intake, "false" for Exhaust. | ||
| bool printLog; // Used to trigger a print in the loop. | ||
| unsigned long timeGap; // Function level time between interrupts. | ||
| unsigned long lastTimeGap; // Global level time between interrupts. | ||
|
|
||
| void setup() { | ||
| Serial.begin(115200); | ||
| pinMode(HALL_MAGNET, INPUT); | ||
| attachInterrupt(0, magnetDetect, RISING); | ||
| pinMode(INTAKE_V, OUTPUT); | ||
| pinMode(EXHAUST_V, OUTPUT); | ||
| } | ||
|
|
||
| void loop() { | ||
| if(printLog){ | ||
| Serial.print(lastTimeGap); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should be plenty of time between interrupts but anything written out to serial should first be copied into a local variable and then written out to avoid the possibility of a race condition. Its probably not a big deal now, but could garble the output if this conditional gets interrupted.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. After thinking on it more I'm inclined to go with the current value. Removing the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, keeping the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue isn't the printLog variable, it the variables being written out to the UART. If this part of the code is interrupted by the magnetDetect() interrupt, when the context switches back you could be in the middle of writing a variable that is now different leading to a garbled output (this would be best case scenario as you would know there was an issue). The other issue would be that its gets interrupted between Serial.print() so you could have lastGapTime be from the previous interrupt and cycle and cad from the most recent interrupt (this could go unnoticed and mess with analysis, or lead to confusion if things don't line up). I don't think any Arduino function are thread safe, so if you want to rely on the output of the log for debugging or data logging, you'll need to take some precautions such as: Again, probably not going to be a big deal until you start dumping lots of data out onto the bus or lots of other things start happening in the loop() function.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seem declaring them as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its all a trade off, copying everything to a temporary variable is fast so you don't have to worry about getting everything out before the interrupt triggers. Ideally you'd be writing into one side of a log buffer and dumping it to the UART from the other side. The tempVars won't change even if the loop() is interrupted: To avoid the issue of a missed block when the interrupt happens in the middle of the loop(), you can move the printLog = false; to the beginning of the loop. That way if the interrupt hits somewhere in the middle, the new data will be spit out on the next pass. |
||
| Serial.print(cycle); | ||
| Serial.print(cad); | ||
| printLog = false; | ||
| } | ||
| } | ||
|
|
||
| // This function will be called about every 15.79ms at the maximum RPM of 3800. | ||
| void magnetDetect() { | ||
| // Increment the counter to keep track of the position. | ||
| hallCounter++; | ||
| // Get the time gap between this interrupt and the last. | ||
| timeGap = millis() - lastTimeGap; | ||
|
|
||
| // Find missing tooth for Top Dead Center (TDC). | ||
| if (timeGap >= lastTimeGap * 3 / 2) { | ||
| // Reset the hall counter. | ||
| hallCounter = 1; | ||
| // Flip the cycle phase. | ||
| cycle = !cycle; | ||
| } | ||
|
|
||
| // Store the last time difference so we can use it in the next interrupt. | ||
| lastTimeGap = timeGap; | ||
|
|
||
| // Store the current crank angle for logging. | ||
| cad = hallCounter * DEG_PER_MAGNET; | ||
|
|
||
| // Every rotation of the crank alternates between Intake and Exhaust. | ||
| if (cycle) { | ||
| // If the crank angle degree is in the intake range open it, otherwise close it. | ||
| digitalWrite(INTAKE_V, cad > FREEVALVE_OFFSET_TOP && cad <= FREEVALVE_OFFSET_BOTTOM); | ||
| } else { | ||
| // If the crank angle degree is in the exhaust range open it, otherwise close it. | ||
| digitalWrite(EXHAUST_V, cad >= FREEVALVE_OFFSET_BOTTOM || cad < FREEVALVE_OFFSET_TOP); | ||
| } | ||
| printLog = true; | ||
| } | ||
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate variables are necessary for intake/exhaust open/close angles (4 distinct values) as 4 stroke engine cam phases usually are not symmetrical mostly due to flow inertia (you can look them up in google - "camshaft timing chart").
For engine with free phases separate values are even more important - they will be changed by some algorithm depending on RPM and other values from sensors and lookup tables.
I guess, @Tamaren1 will come up with new code after his findings in 2nd video where he is measuring cam phases.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also solenoid inertia should be coded or looked up in some table, I think. Similarly to how ECUs have injector opening delay lookup tables depending on system voltage and RPM ..
It will be fun to code as it depends on opening/closing rate and is a "real time"/not angle value :)
Not in scope of this PR though :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super feedback. Thanks. I've started on another branch to work in the intake/exhaust open/close. Just saw @Tamaren1 latest video. Exciting to see how the engine runs after mapping.