ARDUINO ПОМОЩЬ . Автозапуск для машины при использовании дешевого блока и кнопки старт-стоп

bAd

✩✩✩✩✩✩✩
10 Окт 2025
4
1
P.S. Данный пост не говорит как делать правильно, а лишь описывает путь пройденный мной и с чем я столкнулся . Никого не призываю повторять, если только есть опытный в этом человек так как код может быть не идеален .

1 часть

Есть такая задача. Сделать не дорогой автозапуск для авто с простейшими элементами и с минимум вложений , чтобы был лишь автозапуск без лишнего геморроя и со всеми нужными функциями.
Что мы имеем ?
1. Сама сигнализация, стоимость её около 10у.е.( да ребят я из Беларуси=)
7cc6abas-960.jpg
2.Arduino nano
3.Огромное желание что то смастерить самому без знания основ программирования.

Наше ТЗ
1.Чтобы машина запускалась с задержкой после включения зажигания ( так как выходной сигнал на стартер с этого модуля около 1 секунды, наша задача выждать время для прогрева свечей в зимнее время или для срабатывания подкачивающих насосов и так далее)
2. Чтобы было отключение стартера поле того как машина завелась ( реализация такова что когда машина завелась на лампочку генератора приходит +12 Вольт, эти 12 вольт будут сигналом для отключения программы ардуино)
3. Чтобы задержка перед пуском была на разное время ( меня интересует 2 режима работы, когда двигатель холодный то задержка перед подачей сигнала на стартер должно составлять 10 секунд , когда двигатель уже 40 градусов или более то задержка 2 секунды и на запуск, сигнал на запуск не менее 4 секунд, реализовать это не сложно так как датчик ОЖ(охлаждающей жидкости) это обычный NTC терморезистор и из него нужно вынуть показания, пределы таковы если R<=150 Om (тогда задержка 2 секунды) если R>=400 Ом (тогда задержка 10 секунд) промежуточное значение от 150 до 400 (так же с задержкой 10 секунд)
4. После завершения сигнала на выход или получения сигнала +12 вольт с генератора программа должна остановиться и ждать следующего сигнала на запуск с модуля.

Я человек в этой истории новый но знаю про ИИ) Поэтому изначально обратился к нему за просьбой, после суток извращения с ним и разными предложениями по написанию кода со всеми проверками на WOKWI я нашел единственно работающий примерно по моему ТЗ код .

Самая большая проблема и мольва о помощи, помочь допилить код со всеми доработками и правильными измерениями.

Вот такое ТЗ я поставил ИИ :

Давай напишем новый код для ардуино нано. Действия программы такие:
При кратковременной подаче напряжения +12В на пин запускалась программа.
Программа должна измерять какое NTC сопротивления подаеться на ввод, есть два выбора работы программы.
1 если сопротивление ровно 150 Ом и до 0 Ом тогда программа задерживает сигнал на 2 секунды и дает на выход сигнал длинною 4 секунд
2 если сопротивление ровно 400 Ом и до 1000 Ом тогда программа задерживает сигнал на 10 секунды и дает на выход сигнал длинною 4 секунд
Должен быть еще пин который управляется кратковременным подачей +12 вольт , при появлении на нем +12 вольт или истечению времени выходного сигнала программа должна остановиться и запустить лишь тогда когда снова подадим на ввод +12 вольт
все действия должны писать Serial.println


Не кидайте камнями я вообще в этом ДУБ ) Есть только желание что то сделать самому и не тратить очень много времени для написания одной программы.

ВОТ ЧТО МНЕ ДАЛ ИИ (Сделано ИИ , используете на свой страх и риск)

C++:
const int inputPin = 2; // Пин старта (активен +5V)

const int stopPin = 3; // Пин СТОП (активен GND)

const int outputPin = 4; // Выход

const int resistancePin = A0; // Пин сопротивления

// Пороги сопротивления (настроить!)

const int RESISTANCE_150OHM = 680;

const int RESISTANCE_400OHM = 350;

// Переменные состояния

bool buttonPressed = false;

unsigned long triggerTime = 0;

unsigned long lastDebounceTime = 0;

const int debounceDelay = 50; // мс

void setup() {

pinMode(inputPin, INPUT); // БЕЗ подтяжки к VCC!

pinMode(stopPin, INPUT_PULLUP);

pinMode(outputPin, OUTPUT);

digitalWrite(outputPin, LOW);

Serial.begin(9600);

attachInterrupt(digitalPinToInterrupt(stopPin), interruptHandler, FALLING);

}

void loop() {

// Чтение кнопки START с защитой от дребезга

int currentState = digitalRead(inputPin);

if (currentState == HIGH && !buttonPressed) {

if (millis() - lastDebounceTime > debounceDelay) {

buttonPressed = true;

triggerTime = millis();

Serial.println("Старт! Таймер запущен");

}

lastDebounceTime = millis();

}

// Логика таймера

if (buttonPressed) {

int sensorValue = analogRead(resistancePin);

unsigned long delayTime = 10000; // По умолчанию 10 сек

if (sensorValue >= RESISTANCE_150OHM) {

delayTime = 2000;

Serial.println("Режим 150 Ом (2 сек)");

}

else if (sensorValue <= RESISTANCE_400OHM) {

delayTime = 10000;

Serial.println("Режим 400 Ом (10 сек)");

}

if (millis() - triggerTime >= delayTime) {

digitalWrite(outputPin, HIGH);

Serial.println("Выход ВКЛ");

delay(5000); // Удерживаем 5 сек

digitalWrite(outputPin, LOW);

Serial.println("Выход ВЫКЛ");

buttonPressed = false;

}

}

}

void interruptHandler() {

digitalWrite(outputPin, LOW);

buttonPressed = false;

Serial.println("СТОП! Сброс таймера");

}


P.S. для проверки на WOWKI я указал что входной сигнал +5 В а сигнал стоп это GND . На самом деле было очень много кодов сделанных ИИ но это примерно похожий по логике работы который нужен мне.

Заранее извиняюсь если есть какие либо ошибки по добавлению поста или темы .

Не знаю выйдет из этого поста что либо но очень надеюсь что найдется знающий человек который будет готов помочь в данном деле. Заранее всех благодарю за содействие и огромный привет Alex


2 часть

Прошло несколько недель с момента первой примерки кода и проверки его ) На данный момент логика немного переработана и сделана более податлива для дальнейших настроек в случае если кто то захочет повторить. Код был немного доработан и собран для проверке на машине. Пока все проверки проводились на столе с использованием резисторов для понимания как работает программа , какая погрешность и в чем проблемы.

Что необходимо:
Для управления входных сигналов - реле 12 вольт
Для выходного сигнала - реле 5 вольт (так как нужно коммутировать 12 вольтовый сигнал)
Для защиты - парочка диодов
Для подтягивающего сопротивления - взято сопротивление 5 кОм
Для эталонного сопротивления - взято сопротивление 10 кОм
Для управления - Ардуино нано
Для питания ардуино - 5 вольтовый стабилизатор

Для ардуино сделан такой код. (Сделано ИИ , используете на свой страх и риск)

Новый код .:
#include <avr/wdt.h>
#include <avr/pgmspace.h> // Для работы с PROGMEM

// Константы пинов и общие параметры
const int startPin = 4;
const int stopPin = 3;
const int outputPin = 6;
const int sensorPin = A0;

const float R_25 = 10000.0;
const float VCC = 5.0;

// Обновлённые калибровочные данные из изображения
const int numPoints = 12;
// Таблицы перенесены в программную память для экономии ОЗУ
const float resistanceTable[numPoints] PROGMEM = {
    7500.0, 6500.0, 4000.0, 3000.0, 2000.0, 1200.0,
    900.0, 700.0, 500.0, 350.0, 270.0, 180.0
};
const float temperatureTable[numPoints] PROGMEM = {
    -10.0, 0.0, 10.0, 20.0, 30.0, 40.0,
    50.0, 60.0, 70.0, 80.0, 90.0, 100.0
};

// Объявление состояний системы
enum SystemState {
  IDLE,
  DELAY_PHASE,
  OUTPUT_PHASE,
  WAIT_START_RELEASE
};

// Переменные состояния
volatile SystemState currentState = IDLE;
volatile bool stopRequested = false; // Флаг для обработки прерывания в loop()

unsigned long lastDebounceTime = 0;
const unsigned long DEBOUNCE_DELAY = 50;
unsigned long phaseStartTime;
unsigned long currentDelayTime;

// Прототипы функций
float readTemperatureFromTable(float resistance);
float readTemperature(float* resistanceValue);
void printReadyState();

void setup() {
  wdt_disable();
  pinMode(startPin, INPUT); // Используем внешний pull-down резистор
  pinMode(stopPin, INPUT); // Используем внешний pull-down резистор
  pinMode(outputPin, OUTPUT);
  digitalWrite(outputPin, LOW);
  Serial.begin(9600);

  // Прерывание по нарастающему фронту (кнопка замыкает на +5V)
  attachInterrupt(digitalPinToInterrupt(stopPin), emergencyStop, RISING);

  Serial.println("=== ТЕРМОРЕГУЛЯТОР (С КАЛИБРОВКОЙ) ===");
  printReadyState();
  wdt_enable(WDTO_8S);
}

void loop() {
  wdt_reset();

  // Обработка флага экстренной остановки, установленного в прерывании
  if (stopRequested) {
    digitalWrite(outputPin, LOW);
    currentState = WAIT_START_RELEASE;
    stopRequested = false; // Сброс флага
    Serial.println("\n!!! АВАРИЙНЫЙ СТОП !!!");

  }

  handleThermoregulator();
}

void handleThermoregulator() {
  // Кнопка нажата, когда читается HIGH
  int startButtonState = digitalRead(startPin);
  int stopButtonState = digitalRead(stopPin);

  switch(currentState) {
    case IDLE:
      if (startButtonState == HIGH && (millis() - lastDebounceTime > DEBOUNCE_DELAY)) {
        lastDebounceTime = millis();
        startSystem();
      }
      break;
    case WAIT_START_RELEASE:
      // В этом состоянии кнопка должна быть отпущена (LOW), чтобы вернуться в IDLE
      if (startButtonState == LOW && (millis() - lastDebounceTime > DEBOUNCE_DELAY) && (stopButtonState == LOW)) {
        lastDebounceTime = millis();
        currentState = IDLE;
 
        printReadyState();
      }
      break;
    case DELAY_PHASE:
      if (millis() - phaseStartTime >= currentDelayTime) {
        startOutputPhase();
      }
      break;
    case OUTPUT_PHASE:
      if (millis() - phaseStartTime >= 2500) {
        completeCycle();
      }
      break;
  }
}

void startSystem() {
  float resistance;
  float temp = readTemperature(&resistance);
  if (temp == -999.0) {
    Serial.println("Система не запущена из-за ошибки датчика.");
    return;
  }
  Serial.print("\nСтарт системы. Температура: ");
  Serial.print(temp, 2);
  Serial.print(" °C | Сопротивление: ");
  Serial.print(resistance, 0);
  Serial.println(" Ом");
  currentDelayTime = (temp >= 10.0) ? 1000 : 10000;
  Serial.print("Задержка: ");
  Serial.print(currentDelayTime / 1000.0);
  Serial.println(" сек");
  currentState = DELAY_PHASE;
  phaseStartTime = millis();
}

void startOutputPhase() {
  currentState = OUTPUT_PHASE;
  phaseStartTime = millis();
  digitalWrite(outputPin, HIGH);
  Serial.println("Выход АКТИВИРОВАН (2,5 сек)");
}

void completeCycle() {
  digitalWrite(outputPin, LOW);
  Serial.println("Цикл завершен");
  currentState = WAIT_START_RELEASE;
}

// Функцию прерывания делаем максимально быстрой
void emergencyStop() {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  if (interruptTime - lastInterruptTime > DEBOUNCE_DELAY) {
    stopRequested = true; // Просто устанавливаем флаг
  }
  lastInterruptTime = interruptTime;
}

// Функция для чтения температуры из таблицы с интерполяцией
float readTemperatureFromTable(float resistance) {
  // Получаем первое значение сопротивления из PROGMEM
  float firstResistance = pgm_read_float_near(resistanceTable);
  // Если сопротивление выше максимального значения в таблице
  if (resistance >= firstResistance) {
    return pgm_read_float_near(temperatureTable);
  }
  // Получаем последнее значение сопротивления из PROGMEM
  float lastResistance = pgm_read_float_near(&resistanceTable[numPoints - 1]);
  // Если сопротивление ниже минимального значения в таблице
  if (resistance <= lastResistance) {
    return pgm_read_float_near(&temperatureTable[numPoints - 1]);
  }
  // Линейная интерполяция
  for (int i = 0; i < numPoints - 1; i++) {
    float res1 = pgm_read_float_near(&resistanceTable[i]);
    float res2 = pgm_read_float_near(&resistanceTable[i + 1]);
    if (resistance <= res1 && resistance >= res2) {
      float temp1 = pgm_read_float_near(&temperatureTable[i]);
      float temp2 = pgm_read_float_near(&temperatureTable[i + 1]);
      float tempDiff = temp2 - temp1;
      float resDiff = res1 - res2;
      float resDelta = res1 - resistance;
      return temp1 + (resDelta / resDiff) * tempDiff;
    }
  }
  return -999.0;
}

// Функция чтения температуры с датчика, с добавленной отладочной информацией
float readTemperature(float* resistanceValue) {
  int adcValue = analogRead(sensorPin);

  Serial.print("ОТЛАДКА: Значение АЦП: ");
  Serial.println(adcValue);

  if (adcValue <= 0 || adcValue >= 1023) {
    Serial.println("Ошибка датчика: нереалистичные показания АЦП!");
    if (resistanceValue) *resistanceValue = 0;
    return -999.0;
  }
  // Расчёт сопротивления термистора. Предполагается: Rx -> GND, R25 -> VCC
  float resistance = R_25 * (float)adcValue / (1023.0 - (float)adcValue);
  if (resistanceValue) *resistanceValue = resistance;

  Serial.print("ОТЛАДКА: Рассчитанное сопротивление: ");
  Serial.print(resistance, 0);
  Serial.println(" Ом");

  float temp = readTemperatureFromTable(resistance);

  Serial.print("ОТЛАДКА: Интерполированная температура: ");
  Serial.print(temp, 2);
  Serial.println(" °C");

  if (temp == -999.0 || temp < -50.0 || temp > 150.0) {
    Serial.print("Ошибка датчика: аномальная температура (");
    Serial.print(temp);
    Serial.println(" °C).");
    return -999.0;
  }
  return temp;
}

void printReadyState() {
  Serial.println("Система готова к работе");
  Serial.println("Для запуска подай +5В на pin2");
  Serial.println("----------------------------");
}
Данный код можно подправлять под каждые показания своего термистора . Сделать это не сложно зная значение сопротивление термистора при его температуре. Чем больше данных тем точнее работа и правильность показаний.
Данные расчеты будут верны если эталонное сопротивление будет подключено к 5 вольт и к аналоговому входу а0, а уже наш термистор соответственно через GND к а0.

Логика работы кода:
При кратковременной подаче напряжения +12В на пин запускается программа.
Программа измеряет какое NTC сопротивления подаеться на ввод. Дальше есть два выбора работы программы.
1 если температура больше или равна 10 *С программа задерживает сигнал на 1 секунду и дает на выход сигнал длинною 2.5 секунд
2 если температура меньше 10 *С тогда программа задерживает сигнал на 10 секунды и дает на выход сигнал длинною 2.5 секунд
Аварийный стоп ( в моем случаем +12 вольт после того как пошла зарядка генератора, можно использовать что то другое) как только появился сигнал программа прекращает работы и ждет следующей подачи сигнала 12 вольт на управляющий пин. Все действия пишуться в Serial.println для отладки работы программы ( комментаторы говорят что это мешает работы программы, следуя их совету после полной проверки лучше удалить).



Что получилось на макетной плате.

5BWwO7sXr52puoAXbn8Xlfo3pZegxWnMsI5QECaz6QqnkzwmZvCFuMmqaz0QXUgsv3Q2aIEriPqes5KVIEzM2uNA.jpg
212112.jpg


Не судите строго ) Понятное дело что можно сделать лучше, но для моих нужд достаточно. Лучше все проверить внимательно, схема предоставлена для наглядности

На данном этапе вся схема работает исправно все сигналы видит правильно, расчет сопротивления верный , есть погрешность но для моих целей этого более чем достаточно.

Если есть идеи как что либо улучшить, предлагайте.
 
Изменено:

Мишутк

★✩✩✩✩✩✩
29 Мар 2025
69
30
Самая большая проблема и мольва о помощи, помочь допилить код со всеми доработками и правильными измерениями.
Код ИИ сгенерированый новичками в проектах новичков не допиливается в принципе. Самая большая проблема в том, что новички этого не понимают. Уважающий себя специалист даже не смотрит в такой код.

Рекомендации. С таким опытом как ваш в проект сначала должна быть подобрана элементная база: вы должны научиться обрабатывать показания каждого датчика. Потом научиться управлять каждым исполнительным устройством. После этого собирается прототип выдающий показания и управляемый кнопками - вы вручную наблюдая за датчиками подаете кнопками команды на исполнение.
Как только получилось - только тогда пишете алгоритмы на эмуляторе.
И только потом на свой страх и риск ставите на реальный объект, не забыв про множество аварийных независимых защитных цепей.
 
  • Лойс +1
Реакции: bAd

bAd

✩✩✩✩✩✩✩
10 Окт 2025
4
1
@Мишутк, я для этого и пришел в этот форум чтобы люди помогли разобрать этот код, в эмуляторе он исправно работает за исключением измерением сопротивления, я Вас не прошу участвовать в этом , если у меня не выйдет, то увы это останется лишь проектом .На данном этапе я пока очень надеюсь что все выйдет. Чтобы на данном этапе изучать весь курс программирования и написания кода для Ардуино, потратить для этого не один месяц изучения я не готов, я либо найду альтернативы либо допилю со знающими людьми . А Вам спасибо за совет и комментарий

Рекомендации. С таким опытом как ваш в проект сначала должна быть подобрана элементная база: вы должны научиться обрабатывать показания каждого датчика. Потом научиться управлять каждым исполнительным устройством.
По элементам всего 1 один и это типичный NTC терморезистор у которого есть график в открытом доступе, второй датчик он просто выдает сигнал. Я думаю что человек который имеет малейшее понятие как пишется код сделает его за 20 мин.
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
749
183
Чтобы было отключение стартера поле того как машина завелась ( реализация такова что когда машина завелась на лампочку генератора приходит +12 Вольт
А что будет, если не пришли эти 12 вольт? Ну не заводится, например, или обрыв, или щетки генератора стерлись? Ваш проект так и будет крутить стартер, пока из него не выйдет загадочный сизый дымок, на котором работает вся электроника?
 

bort707

★★★★★★✩
21 Сен 2020
3,301
959
Есть такая задача. Сделать не дорогой автозапуск для авто
....
... сигнализация, стоимость её около 10у.е.( да ребят я из Беларуси=)
Судя по фото, в этой сигналке запуск с кнопки уже предусмотрен. Тогда совершенно непонятно, к чему этот колхоз на Ардуине.
Если же автозапуска нет - надо просто взять другую сигналку. Я уверен, что к вам в Беларусь их пачками везут из Европы, если не найдется за 10уе - найдется за 15

А на Ардуине вам на первый раз стоит собрать что-нить будь попроще и безопаснее - какие-нибудь часики или лампу разноцветную...
 

bAd

✩✩✩✩✩✩✩
10 Окт 2025
4
1
А что будет, если не пришли эти 12 вольт? Ну не заводится, например, или обрыв, или щетки генератора стерлись? Ваш проект так и будет крутить стартер, пока из него не выйдет загадочный сизый дымок, на котором работает вся электроника?
Изначально в программе на выходе сигнал работает 4 секунды потом программа прекращается. и ждет дальнейшей команду на пуск.

@bort707, прежде чем написать какой либо ответ, стоит прочесть тему и если вам это интересно попробовать разобраться. Задача не выполнить автозапуск с данной кнопки. В данном модули есть запуск машины с доп. канала сигнализации( открытие багажника) она исправно работает. но задержка перед включением и запуском стартера очень мала. и не реализовано в ней какие либо логические входы для понимания завелась машина или нет. она лишь после принятия сигнала с доп сигнала сигнализации включает зажигание и через пару секунд дает команду на запуск авто в течении 1 секунды чего тоже может быть не достаточно в холодное время года .
 

bort707

★★★★★★✩
21 Сен 2020
3,301
959
Кстати, заглянул в код и могу сказать, что он ГАРАНТИРОВАННО будет виснуть, потому что внутри прерывания нельзя использовать Serial.print(). Это лишь одна ошибка и, наверняка не единственная. Просто как иллюстрация к тому, что ИИ бесполезен для тех, кто не разбирается в предмете.
Образно говоря , ИИ - это подмастерье. Ему можно поручать простенькие задачки, которые лень делать самому. Но главное условие - ты должен понимать в предмете больше, чем ИИ - чтобы найти и исправить его ошибки, которые будут 100%.

То есть ИИ - это не замена знаний и мозгов, как думает ТС. Это инструмент для тех, кто понимает.
 
  • Лойс +1
Реакции: Sana956