#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(13, OUTPUT); // LED
digitalWrite(13, LOW); // LED ENABLED
}
void readAll() {
newTime = micros();
periodTime = newTime-oldTime; // длительность всего периода (от закрытия до закрытия)
chargeTime = newTime-midTime; // отрезок цикла от открытия шторки до закрытия (зарядка катушки)
rpm = 60000000/periodTime; // число оборотов
oldTime = micros();
}
void loop() {
detector = digitalRead(IN);
if(detector == LOW && oldDetector == HIGH) { // момент когда шторка открылась
digitalWrite(OUT, LOW); // отключаем катушку в любом случае (ИСКРА) 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 == HIGH && oldDetector == LOW) { // момент когда шторка закрылась
digitalWrite(OUT, HIGH); // включаем катушку (ЗАРЯДКА) HIGH; digitalWrite(OUT, HIGH);
oldDetector = detector; // oldDetector = LOW
midTime = micros(); // отметка начала зарядки катушки (середина цикла)
advanceGranted = 1; // блок опережения разрешён
// антисбой датчика
//delayMicroseconds(periodTime/5);
}
if(micros() - midTime >= ignitionAdvance && advanceGranted == 1) { // собственно само опережение
digitalWrite(OUT, LOW); // отключаем катушку (ИСКРА) LOW; digitalWrite(OUT, LOW);
advanceGranted = 0; // больше сюда не возвращаемся до следующего цикла.
}
if(micros() - fuseTime >= 1000000) { // предохранитель, если катушка заряжается больше 1 секунды
digitalWrite(OUT, LOW); // отключаем катушку LOW; digitalWrite(OUT, LOW);
}
}
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;
}
Что и где там я конкретно должен увидеть, там только про коммерциюТолько на стенде можно понять даёт это что то или нет, ну вы этот вопрос по изучайте, я как бы 30лет в спорте, ездил на электронике правда буржуйской, там максимум 25гр, найдите там у них есть инструкция полистайте https://www.power-spark.de/index_en.html
#define IN 4 // Входной пин (датчик)
#define OUT 5 // Выходной пин (катушка)
bool detector = false, oldDetector = false, advanceGranted = false;
unsigned long fuseTime, oldTime, midTime, periodTime, chargeTime, ignitionAdvance;
int ignitionDegree = 0;
long rpm = 0;
unsigned long lastActionTime = 0; // Время последнего действия
unsigned long antiChatterDelay = 0; // Задержка для антисбой (как delayMicroseconds(periodTime / 5))
unsigned long lastCoilAction = 0; // Время последнего действия с катушкой
bool antiChatterEnabled = trueутпдшырвутenasd; // Флаг для включения/выключения функции антисбой
// Структура для хранения диапазона оборотов и соответствующего угла опережения
struct RPMRange {
int minRPM;
int maxRPM;
int ignitionDegree;
};
// Карта значений для угла опережения зажигания (равномерное распределение углов от 0° до 33°)
const RPMRange rpmTable[] = {
{0, 700, 0}, // 0-700 оборотов -> 0°
{700, 800, 1}, // 700-800 оборотов -> 1°
{800, 900, 2}, // 800-900 оборотов -> 2°
{900, 1000, 3}, // 900-1000 оборотов -> 3°
{1000, 1100, 4}, // 1000-1100 оборотов -> 4°
{1100, 1200, 5}, // 1100-1200 оборотов -> 5°
{1200, 1300, 6}, // 1200-1300 оборотов -> 6°
{1300, 1400, 7}, // 1300-1400 оборотов -> 7°
{1400, 1500, 8}, // 1400-1500 оборотов -> 8°
{1500, 1600, 9}, // 1500-1600 оборотов -> 9°
{1600, 1700, 10}, // 1600-1700 оборотов -> 10°
{1700, 1800, 11}, // 1700-1800 оборотов -> 11°
{1800, 1900, 12}, // 1800-1900 оборотов -> 12°
{1900, 2000, 13}, // 1900-2000 оборотов -> 13°
{2000, 2100, 14}, // 2000-2100 оборотов -> 14°
{2100, 2200, 15}, // 2100-2200 оборотов -> 15°
{2200, 2300, 16}, // 2200-2300 оборотов -> 16°
{2300, 2400, 17}, // 2300-2400 оборотов -> 17°
{2400, 2500, 18}, // 2400-2500 оборотов -> 18°
{2500, 2600, 19}, // 2500-2600 оборотов -> 19°
{2600, 2700, 20}, // 2600-2700 оборотов -> 20°
{2700, 2800, 21}, // 2700-2800 оборотов -> 21°
{2800, 2900, 22}, // 2800-2900 оборотов -> 22°
{2900, 3000, 23}, // 2900-3000 оборотов -> 23°
{3000, 3100, 24}, // 3000-3100 оборотов -> 24°
{3100, 3200, 25}, // 3100-3200 оборотов -> 25°
{3200, 3300, 26}, // 3200-3300 оборотов -> 26°
{3300, 3400, 27}, // 3300-3400 оборотов -> 27°
{3400, 3500, 28}, // 3400-3500 оборотов -> 28°
{3500, 3600, 29}, // 3500-3600 оборотов -> 29°
{3600, 3700, 30}, // 3600-3700 оборотов -> 30°
{3700, 3800, 31}, // 3700-3800 оборотов -> 31°
{3800, 3900, 32}, // 3800-3900 оборотов -> 32°
{3900, 4000, 33}, // 3900-4000 оборотов -> 33°
{4000, 999999, 33} // 4000+ оборотов -> 33° (максимальное значение)
};
const int tableSize = sizeof(rpmTable) / sizeof(rpmTable[0]); // Количество элементов в таблице
void setup() {
pinMode(IN, INPUT); // D2 от прерывателя (датчик)
pinMode(OUT, OUTPUT); // D1 к драйверу катушки
pinMode(2, OUTPUT); // LED для визуализации
digitalWrite(2, LOW); // Выключаем LED
oldTime = micros(); // Начальное время для отсчёта
fuseTime = micros(); // Начальный отсчёт для предохранителя
}
void readAll() {
// Считываем только время для подсчёта оборотов и зарядки катушки
unsigned long newTime = micros();
periodTime = newTime - oldTime; // Время одного цикла
chargeTime = newTime - midTime; // Время зарядки катушки
rpm = 60000000 / periodTime; // Расчёт оборотов в минуту
oldTime = newTime; // Обновляем старое время для следующего цикла
}
int getIgnitionDegree(int rpm) {
// Поиск угла опережения на основе оборотов из таблицы
for (int i = 0; i < tableSize; i++) {
if (rpm >= rpmTable[i].minRPM && rpm < rpmTable[i].maxRPM) {
return rpmTable[i].ignitionDegree; // Возвращаем угол для данного диапазона оборотов
}
}
return 0; // Если обороты не входят в диапазон таблицы, возвращаем 0
}
void setIgnition() {
ignitionDegree = getIgnitionDegree(rpm); // Получаем угол из таблицы значений
ignitionAdvance = chargeTime - ((periodTime / 360) * ignitionDegree); // Угол опережение
}
void controlCoil(bool state) {
// Управление катушкой зажигания (включение/выключение)
if (state) GPOS = (1 << OUT); // Включаем катушку
else GPOC = (1 << OUT); // Отключаем катушку
}
void loop() {
detector = digitalRead(IN); // Чтение входного сигнала от датчика
// Обработка "закрытия" шторки
if (detector == HIGH && oldDetector == LOW) { // шторка закрыта
if (antiChatterEnabled) {
// Выполним действия с катушкой, если прошло нужное время и функция антисбой включена
if ((micros() - lastCoilAction) >= antiChatterDelay) {
controlCoil(false); // отключаем катушку
oldDetector = detector;
readAll(); // Подсчёт всех параметров цикла
setIgnition(); // Получение угла опережения
fuseTime = micros(); // Начало отсчёта для предохранителя
antiChatterDelay = periodTime / 5; // Установка времени для функции антисбой
lastCoilAction = micros(); // Обновляем время последнего действия
}
} else {
// Когда защита от сбоев выключена, просто отключаем катушку
controlCoil(false);
oldDetector = detector;
readAll();
setIgnition();
fuseTime = micros();
}
}
// Обработка "открытия" шторки
if (detector == LOW && oldDetector == HIGH) { // шторка открыта
if (antiChatterEnabled) {
if ((micros() - lastCoilAction) >= antiChatterDelay) {
controlCoil(true); // включаем катушку
oldDetector = detector;
midTime = micros(); // начало зарядки катушки
advanceGranted = true; // блок опережения разрешён
antiChatterDelay = periodTime / 5; // Устанавливаем время для функции антисбой
lastCoilAction = micros(); // Обновляем время последнего действия
}
} else {
// Когда защита от сбоев выключена, сразу включаем катушку
controlCoil(true);
oldDetector = detector;
midTime = micros();
advanceGranted = true; // блок опережения разрешён
}
}
// Опережение зажигания
if (micros() - midTime >= ignitionAdvance && advanceGranted) {
controlCoil(false); // Отключаем катушку
advanceGranted = false; // Блок опережения выключен
}
// Предохранитель (если катушка заряжается более 1 секунды)
if (micros() - fuseTime >= 1000000) {
controlCoil(false); // Отключаем катушку
}
}
Тут судя по свече может быть и детонация, топливо не горит правильно, конечно если гильза +поршень+кольца без вопросов, ну и степень сжатия правильная. К стати спрошу по путно а вот в эту ATtiny85 что то еще засунуть можно, к примеру дисплей с вольтами или оборотами, будет достаточно 2е цифры, или то и другое с переключением, или у неё памяти едва на зажигалку хватает ?Поставлю 30 градусов, возможности проверить или не верить всё равно не имеется.
И еще масло на кольце нехорошо, компрессия слабая и вам приходится лить в него топливо что бы он ехал, ну то-е вы едете не на компрессии, а на перерасходе топлива.Эта свеча проехала километров эдак 150 на этом моторе,
Спрашиваешь конечно интересноЕсли интересно, я сейчас тестирую вот такой скетч,
Схематически такая возможность есть https://arduinoprosto.ru/q/80290/attiny85-dht11-tm1637#gsc.tab=0К стати спрошу по путно а вот в эту ATtiny85 что то еще засунуть можно, к примеру дисплей с вольтами или оборотами, будет достаточно 2е цифры, или то и другое с переключением, или у неё памяти едва на зажигалку хватает ?
#define IN 0 // Входной пин (датчик)
#define OUT 1 // Выходной пин (катушка)
bool detector = false, oldDetector = false, advanceGranted = false;
unsigned long fuseTime, oldTime, midTime, periodTime, chargeTime, ignitionAdvance;
int ignitionDegree = 0;
long rpm = 0;
// Карта значений для угла опережения зажигания (равномерное распределение углов от 0° до 33°)
const struct {
int minRPM, maxRPM, ignitionDegree;
} rpmTable[] = {
{0, 700, 0}, // 0-700 оборотов -> 0°
{700, 800, 1}, // 700-800 оборотов -> 1°
{800, 900, 2}, // 800-900 оборотов -> 2°
{900, 1000, 3}, // 900-1000 оборотов -> 3°
{1000, 1100, 4}, // 1000-1100 оборотов -> 4°
{1100, 1200, 5}, // 1100-1200 оборотов -> 5°
{1200, 1300, 6}, // 1200-1300 оборотов -> 6°
{1300, 1400, 7}, // 1300-1400 оборотов -> 7°
{1400, 1500, 8}, // 1400-1500 оборотов -> 8°
{1500, 1600, 9}, // 1500-1600 оборотов -> 9°
{1600, 1700, 10}, // 1600-1700 оборотов -> 10°
{1700, 1800, 11}, // 1700-1800 оборотов -> 11°
{1800, 1900, 12}, // 1800-1900 оборотов -> 12°
{1900, 2000, 13}, // 1900-2000 оборотов -> 13°
{2000, 2100, 14}, // 2000-2100 оборотов -> 14°
{2100, 2200, 15}, // 2100-2200 оборотов -> 15°
{2200, 2300, 16}, // 2200-2300 оборотов -> 16°
{2300, 2400, 17}, // 2300-2400 оборотов -> 17°
{2400, 2500, 18}, // 2400-2500 оборотов -> 18°
{2500, 2600, 19}, // 2500-2600 оборотов -> 19°
{2600, 2700, 20}, // 2600-2700 оборотов -> 20°
{2700, 2800, 21}, // 2700-2800 оборотов -> 21°
{2800, 2900, 22}, // 2800-2900 оборотов -> 22°
{2900, 3000, 23}, // 2900-3000 оборотов -> 23°
{3000, 3100, 24}, // 3000-3100 оборотов -> 24°
{3100, 3200, 25}, // 3100-3200 оборотов -> 25°
{3200, 3300, 26}, // 3200-3300 оборотов -> 26°
{3300, 3400, 27}, // 3300-3400 оборотов -> 27°
{3400, 3500, 28}, // 3400-3500 оборотов -> 28°
{3500, 3600, 29}, // 3500-3600 оборотов -> 29°
{3600, 3700, 30}, // 3600-3700 оборотов -> 30°
{3700, 3800, 31}, // 3700-3800 оборотов -> 31°
{3800, 3900, 32}, // 3800-3900 оборотов -> 32°
{3900, 4000, 33}, // 3900-4000 оборотов -> 33°
{4000, 999999, 33} // 4000+ оборотов -> 33° (максимальное значение)
};
void setup() {
pinMode(IN, INPUT); // от датчика
pinMode(OUT, OUTPUT); // к коммутатору
oldTime = micros(); // Начальное время для отсчёта
fuseTime = micros(); // Начальный отсчёт для предохранителя
}
void readAll() {
// Считываем только время для подсчёта оборотов и зарядки катушки
unsigned long newTime = micros();
periodTime = newTime - oldTime; // Время одного цикла
chargeTime = newTime - midTime; // Время зарядки катушки
rpm = 60000000 / periodTime; // Расчёт оборотов в минуту
oldTime = newTime; // Обновляем старое время для следующего цикла
}
int getIgnitionDegree(long rpm) {
// Поиск угла опережения на основе оборотов из таблицы
for (int i = 0; i < sizeof(rpmTable) / sizeof(rpmTable[0]); ++i) {
if (rpm >= rpmTable[i].minRPM && rpm < rpmTable[i].maxRPM) {
return rpmTable[i].ignitionDegree; // Возвращаем угол для данного диапазона оборотов
}
}
return 0; // Если обороты не входят в диапазон таблицы, возвращаем 0
}
void setIgnition() {
ignitionDegree = getIgnitionDegree(rpm); // Получаем угол из таблицы значений
ignitionAdvance = chargeTime - ((periodTime / 360) * ignitionDegree); // Угол опережение
}
void controlCommutator(bool state) {
// Управление коммутатором
if (state) digitalWrite(OUT, HIGH);
else digitalWrite(OUT, LOW);
}
void loop() {
detector = digitalRead(IN); // Чтение входного сигнала от датчика
// Обработка шторки
if (detector == LOW && oldDetector == HIGH) {
controlCommutator(false);
oldDetector = detector;
readAll();
setIgnition();
// delayMicroseconds(periodTime/5); // если при открытии заслонки мотор душится, то нужно раскомментировать эту строку
}
// Обработка шторки
if (detector == HIGH && oldDetector == LOW) {
controlCommutator(true);
oldDetector = detector;
midTime = micros();
fuseTime = micros();
advanceGranted = true; // блок опережения разрешён
// delayMicroseconds(periodTime/5); // если при открытии заслонки мотор душится, то нужно раскомментировать эту строку
}
// Опережение зажигания
if (micros() - midTime >= ignitionAdvance && advanceGranted) {
controlCommutator(false);
advanceGranted = false; // Блок опережения выключен
}
// Предохранитель (если катушка заряжается более 1 секунды)
if (micros() - fuseTime >= 1000000) {
controlCommutator(false);
}
}
// Карта значений для угла опережения зажигания
const struct {
int minRPM, maxRPM, ignitionDegree;
} rpmTable[] = {
{0, 700, 0}, {700, 800, 1}, // и т. д.
};
int getIgnitionDegree(long rpm) {
for (const int& range : rpmTable) {
if (rpm >= range.minRPM && rpm < range.maxRPM) {
return range.ignitionDegree;
}
}
//return 0; //здесь можно вернуть 0, если ничего не найдется
}
const int tableSize = sizeof(rpmTable) / sizeof(rpmTable[0]); // Эта строка уже не потребуется