#define IN 4
#define OUT 5
bool detector;
bool oldDetector;
bool advanceGranted;
unsigned long fuseTime;
unsigned long newTime;
unsigned long oldTime;
unsigned long midTime;
unsigned long periodTime;
unsigned long chargeTime;
unsigned long ignitionAdvance;
int ignitionDegree;
long int rpm;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // Start the Serial communication to send messages to the computer
Serial.println("\n");
oldTime = micros(); // сразу нужно установить, чтобы readAll() не споткнулся
fuseTime = micros(); // устанавливается время до выключения катушки
pinMode(IN, INPUT); // D2 от прерывателя
pinMode(OUT, OUTPUT); // D1 к драйверу
pinMode(2, OUTPUT); // LED
digitalWrite(2, LOW); // LED ENABLED
}
void readAll() {
newTime = micros();
periodTime = newTime-oldTime; // длительность всего периода (от закрытия до закрытия)
chargeTime = newTime-midTime; // отрезок цикла от открытия шторки до закрытия (зарядка катушки)
rpm = 60000000/periodTime; // число оборотов
oldTime = micros();
}
/* Схема оптодатчика https://www.drive2.ru/b/481766688824492718/
* Если светодиод светится, на выходе с датчика - 0
* Если светодиод не светится, на выходе с датчика - 1
* Логика инверсная: на входе коммутатора - 0, на выходе коммутатора - 1.
* Роль отражателя выполняет сектор 120 градусов.
x---------x------------------------------x-----------x---------> + 12V от батареи
| | | |
| | к входу ардуино/esp | |
| | * | | 10kOm |
| | 1kOm | | 63kOm | | | |
| | | | | | |
| | \ / D1 \ / Led1 |
| | --- --- --- C1 100nf
|оптопара | | | ---
| |----. |-------------------x |
\ / -> |/ |__ |/ |
--- -> |\ |\ Q1 |
| | | |
| | | |
| | | |
x---------x----------x-------------------------------x---------* GND
*/
/*
* Все измерения производятся относительно состояния датчика.
* Логика инверсная: если на входе контроллера 0, то на выходе 1.
* Когда шторка открыта (Led1 горит), на входе контроллера 0.
* chargeTime - период зарядки КЗ, если нет опережения.
* ignitionAdvance - период зарядки КЗ, если есть опережение.
* под delay подразумевается delayMicroseconds(periodTime/5);
oldTime midTime newTime
\ | /
\ | /
x===================x | x
# # | #
# # | #
# HIGH # | LOW #
# # / #
# # / #
# #/ #
x x====================x
<-ignitionAdvance->
<-----chargeTime----->
<-delay-> <-delay->
<---------------periodTime--------------->
*/
void loop() {
detector = digitalRead(IN);
if(detector == HIGH && oldDetector == LOW) { // момент когда шторка закрылась
GPOC = (1 << OUT); // отключаем катушку в любом случае (ИСКРА) LOW; digitalWrite(OUT, LOW);
oldDetector = detector; // oldDetector = HIGH
readAll(); // подсчёт всех параметров цикла
// калькулятор положения коленвала на всякий случай: http://www.torqsoft.net/piston-position.html#gudgeon
// примерный расчёт коэфициентов взят отсюда: https://customcult.netlify.app/
if(rpm >= 0 && rpm <= 700) {
ignitionDegree = 0;
goto bailout;
}
if(rpm >= 700 && rpm <= 1000) { // 0 - 2.2
ignitionDegree = 0.007 * rpm + (-4.800);
goto bailout;
}
if(rpm >= 1000 && rpm <= 2000) { // 2.2 - 15
ignitionDegree = 0.013 * rpm + (-10.800);
goto bailout;
}
if(rpm >= 2000 && rpm <= 3000) { // 15 - 30
ignitionDegree = 0.015 * rpm + (-15.000);
goto bailout;
}
if(rpm >= 3000 && rpm <= 4000) { // 30 - 40
ignitionDegree = 0.010 * rpm + (0.000);
goto bailout;
}
if(rpm > 4000) {
ignitionDegree = 40;
}
bailout:
ignitionAdvance = chargeTime - ((periodTime / 360) * ignitionDegree);
fuseTime = micros(); // начало отсчёта для предохранителя (отключение катушки зажигания при простое)
// антисбой датчика
delayMicroseconds(periodTime/5);
}
if(detector == LOW && oldDetector == HIGH) { // момент когда шторка открылась
GPOS = (1 << OUT); // включаем катушку (ЗАРЯДКА) HIGH; digitalWrite(OUT, HIGH);
oldDetector = detector; // oldDetector = LOW
midTime = micros(); // отметка начала зарядки катушки (середина цикла)
advanceGranted = 1; // блок опережения разрешён
// антисбой датчика
delayMicroseconds(periodTime/5);
}
if(micros() - midTime >= ignitionAdvance && advanceGranted == 1) { // собственно само опережение
GPOC = (1 << OUT); // отключаем катушку (ИСКРА) LOW; digitalWrite(OUT, LOW);
advanceGranted = 0; // больше сюда не возвращаемся до следующего цикла.
}
if(micros() - fuseTime >= 1000000) { // предохранитель, если катушка заряжается больше 1 секунды
GPOC = (1 << OUT); // отключаем катушку LOW; digitalWrite(OUT, LOW);
}
}