Finns det någon där ute som kan hjälpa mig med mitt program och se om det går att göra ännu mer tillförlitligt och driftsäkert? Jag behöver även hjälp med hur jag ska testa systemet/programmet för att se att tändkurvan stämmer i verkligheten. Jag kan ju så klart testa på en motor direkt, men det tar lite tid. Jag funderar på att testa på gräsklipparen innan jag kör på en bilmotor.
Här är en video på min labbplatta med vevaxelsimulator (propellern) och två dioder som visar signalerna till tändboxen.
Det är anpassat för "smarta" wasted spark tändboxar (2 tändstift per spole) med inbyggd logik.
Jag bifogar ett utkast på en systembeskrivning och kod.
Koden är även här (uppdaterad 2016-01-19):
Kod: Markera allt
#include <Avr/interrupt.h>
#include <Avr/io.h>
//Pin definitions:
const byte HallPin1 = 2; // Pin nr 2 to Hall sensor
const byte HallPin2 = 3; // Pin nr 3 is also to Hall sensor
const int Ign1Pin = 8; // (PORTB,0)
const int Ign2Pin = 11; // (PORTB,3)
volatile long int microseconds; // The microsecondcounter value.
volatile unsigned int cranktime; // Time from 3 degrees to where the coil should start to load.
volatile byte IgnSystem; // Statusword for active ign system.
volatile byte dwellTime; // The time the coil should charge (default is 0,004 seconds.
// RPM variables:
volatile byte half_revolutions;
volatile unsigned int rpm;
volatile unsigned int timeold;
/***********************************************************************/
void setup() {
crankingDwellTime = 4000; //in uS
runningDwelltime = 3000; //in uS
half_revolutions = 0;
rpm = 0;
timeold = 0;
IgnSystem = 0; // No ignition system is active.
pinMode(Ign1Pin, OUTPUT); // Initialize the Ignition 1 pin as an output.
pinMode(Ign2Pin, OUTPUT); // -"-
digitalWrite(Ign2Pin, LOW); // bitClear(PORTB, 3); Turn the ignition off in case it's on
digitalWrite(Ign1Pin, LOW); // bitClear(PORTB, 0); // -"-
attachInterrupt(digitalPinToInterrupt(HallPin1), SensorOn, RISING); //Hall sensor DI for Ignition 1
attachInterrupt(digitalPinToInterrupt(HallPin2), SensorOff, FALLING); //-"- 2
/********** Setup timer2*************/
noInterrupts();
TCCR2A = 0; // Turn off Control register for waveform generation
TCCR2B = 0; // Turn off noise cancelling, turn off edge select, waveform gen mode 0, no clock source
TCCR2A |= (1 << WGM21); // Turn on CTC mode (so it will start again) automatically
TIMSK2 |= (1 << OCIE2A); // Set interrupt on compare match.
OCR2A = 8; // Prescaler of 64 gives 4uS per tick, 4uS * 8 = 32uS (32uS = 1 degree at ~5100rpm).
TCNT2 = 0; // Reset timer counter to 0
microseconds = 0; // Reset the ms counter variable.
interrupts();
}
//========================================================================
/* The interrupt action for magnet 1: The Timer starts to count up 32 uS at a time.
**********************/
void SensorOn () {
if ((rpm < 300) & (IgnSystem == 0)) { // When cranking (starting), the coil nr 2 will charge at once.
digitalWrite(Ign2Pin, HIGH); // bitSet(PORTB, 3); (Turn on coil 2 charging immediately.)
dwelltime = crankingDwelltime; //Setting the dwelltime for cranking.
IgnSystem = 2; // Statusword to know witch system is to be hot.
}
if ((rpm >= 300) & (IgnSystem == 2) ) { // When running (not starting), the coil nr 1 will charge after cranktime in the ISR below.
dwelltime = runningDwelltime; //setting the dwelltime for running
IgnSystem = 1; //Statusword to know witch system is to be hot.
}
TCCR2B |= (1 << CS22); // Load 64 prescaler / And this starts the timer2!
/********* RPM calculations: **********/
half_revolutions++;
if (half_revolutions >= 2) {
rpm = 60 * 1000000 / (micros() - timeold) * half_revolutions;
timeold = micros();
half_revolutions = 0;
}
}
/*========================================================================
The interrupt action for magnet 2: The Timer starts to count up 32uS at a time.
********************************/
void SensorOff () {
if ((rpm < 300) & (IgnSystem == 0)) { // When cranking (starting), the coil nr 1 will charge at once.
digitalWrite(Ign1Pin, HIGH); // bitSet(PORTB, 0); (Turn on coil 1 charging immediately,)
dwelltime = crankingDwelltime; //setting the dwelltime for cranking
IgnSystem = 1; //Statusword to know witch system is to be hot.
}
if ((rpm >= 300) & (IgnSystem == 1) ) { // When running (not starting), the coil nr 2 will charge after cranktime in the ISR below.
dwelltime = runningDwelltime; //setting the dwelltime for running
IgnSystem = 2; //Statusword to know witch system is to be hot.
}
TCCR2B |= (1 << CS22); // Load 64 prescaler / And this starts the timer2!
/********* RPM calculations: **********/
half_revolutions++;
if (half_revolutions >= 2) {
rpm = 60 * 1000000 / (micros() - timeold) * half_revolutions;
timeold = micros();
half_revolutions = 0;
}
}
/*=============================================================================
The Interrupt Service Routine for Timer2 that will be executed each time the timer reach the compare match register (1ms).
*****************Milliseconds****************/
ISR(TIMER2_COMPA_vect) {
/*********Counting microseconds*****************/
microseconds = microseconds + 32; // Increases the variable "microseconds" by 32 every time the ISR is executed).
/************ coil charging*****************************/
if (microseconds >= cranktime) { //When the microseconds reaches the cranktime, then do this:
if (IgnSystem == 1) { //If ignitionsystem 1 is selected and not on, then:
digitalWrite(Ign1Pin, HIGH); //bitSet(PORTB, 0); (Turn on coil 1 charging.)
} if (IgnSystem == 2) { // -"-
digitalWrite(Ign2Pin, HIGH); //bitSet(PORTB, 3); (Coil 2 charging.)
}
}
/***********Discharge coilspark*******************************************/
//When the microseconds has reached the cranktime and dwelltime, then:
if (microseconds >= (cranktime + dwellTime)) {
microseconds = 0; // reset the uS counter variable
//Turn off timer.
TCCR2B &= ~ (1 << CS22); //clear the prescaler .
TCNT2 = 0; // Reset the timer count to 0
digitalWrite(Ign1Pin, LOW); //bitClear(PORTB, 0); ( Stop charging coil 1. (Gives spark))
digitalWrite(Ign2Pin, LOW); //bitClear(PORTB, 3); (-"-)
}
// If the engine has stopped or are still cranking, the IgnSystem is set to starting advance degrees.
if (rpm < 300) {
IgnSystem = 0;
}
}
/***********************************************************/
void loop() {
//Calculate the cranktime dependent on the rpm. (cranktime= advance time - dwellTime)
/********************Cranktime calculations ************
RPM Advance Degrees Cranktime Time change
-degrees BTDC from Sensor (uS) for each RPM (uS)
300 -3 180 100000 -100000
400 9 171 71250 -288
600 8 172 47778 -117
1000 7 173 28833 -47
1700 17 163 15980 -18
2800 26 154 9167 -6
3100 28 152 8172 -3
4000 29 151 6292 -2
*/
if (rpm <= 300) {
cranktime = 0;
} if ((rpm > 300) && (rpm <= 400)) {
cranktime = (186400 - (rpm * 288)) - dwellTime; // = (cranktime - (rpm - 300) * Time change for each RPM) - dwellTime;
} if ((rpm > 400) && (rpm <= 600)) {
cranktime = (118050 - (rpm * 117)) - dwellTime; // = (71250 - (rpm - 400) * 117) - dwellTime;
} if ((rpm > 600) && (rpm <= 1000)) {
cranktime = (75978 - (rpm * 47)) - dwellTime;
} if ((rpm > 1000) && (rpm <= 1700)) {
cranktime = (46833 - (rpm * 18)) - dwellTime;
} if ((rpm > 1700) && (rpm <= 2800)) {
cranktime = (26180 - (rpm * 6)) - dwellTime;
} if ((rpm > 2800) && (rpm <= 3100)) {
cranktime = (10007 - (rpm * 3)) - dwellTime;
} if ((rpm > 3100) && (rpm <= 4000)) {
cranktime = (8732 - (rpm * 2)) - dwellTime;
}
}