PHP код:
//авто запуск по звонку мобильного телефона или от дополнительного выхода автосигнаизвции с функцией автоматической и безопасной зарядки аккумулятора телефона
//Настройки
#include <Servo.h> //библиотека серво
#include <PID_v1.h> //библиотека ПИД-ругулятора
double Setpoint, Input, Output; //переменные пид регулятора
Servo myservo; //серво привод
PID myPID(&Input, &Output, &Setpoint, 3, 0.5, 1, DIRECT); //создаем ПИД-регулятор
boolean revers; //переменная ПИД-регулятора
int val = 0; //переменная для хранения состояния датчика темппературы
unsigned long micros_th = 0; //переменная изменяемая для хранения значений прерываний
volatile int th; //переменная для хранения значений в об/мин
volatile int tz; //переменная для сброса значений тахометра
unsigned long ENGINE_WARM_TIME = 1200000; //В миллисекундах время работы мотора после запуска 1200000 миллисекунд = 20 минут
int ENGINE_START_MAX_TIME = 10; //В секундах масимальное время работы стартера типично 3 -10 сек
// select pins for input
const int sensorPin = A0; //объявляем аналоговый вход А0 для подключения датчика температуры
const int sensorZarad = A1; //А1 заряд акб телефона
const int knopkaPusk = A3;//а3 кнопка запуска двигателя
const int hand_brake_in = 3; //d3 adruino Контакт стояночного тормоза "-"
const int start_in = 4; //d4 adruino Сигнал команды на старт от мобильного телефона вибра звонка
const int sharging_in = 5; //d5 adruino сигнал от лампы заряда или давления масла
const int sharging_on = 0; // 0 когда во время работы генератора или от датчика давления масла на этом входе низкое состояние , 1 когда на лампе генератора при работе генератора высокое состояние
const int hand_brake_on = 0; // 0= поднятый датчик ручника замыкает на массу тормоз активен (жигули), 1= датчик ручника в поднятом состоянии выдает высокий уровень напряжения
// select pins for output
const int ledPin = 12; //объявляем цифровой выход 13 для индикации включения автоподсоса
const int pech = 10; //объявляем цифровой выход 8 для подключения печки
const int outpinZarad = 16;//А2 пин подключение реле заряда акб телефона
//------------------------выходы управления сигналкой-------------------------
//const int outpinSigOff = 18;//А4 пин подключение реле отключения сигналки
//const int outpinSigOn = 19;//А5 пин подключение реле включения сигналки
//---------------------------------------------------------------------------
const int starter_out = 7; //d6 adruino реле стартера
const int engine_out = 6; //d7 adruino зажигание
const int secpower_out = 8; //d8 цепи вторичного питания печка, фары итд
const int status_out = 11; //d9 светодиод статуса системы горит = система готова к работе(включена, ручник стоит). одно мигание запущен с первой попытки 2 со второй 3 с третьей
//светодиод подключать с этого пина на массу
// variable for actual mode
int actual_mode = 0; // 2 engine started
int left_start_try = 0; // переменная для хранения остатка числа попыток запуска
int knopkaPuskState = 0;//переменная для хранения положения кнопки запуска двигателя
unsigned long last_start_time = 0; //время в тысячных секунды когда был запущен движок
void setup() {
//---- настройка входов и выходов контроллера --------------
// init selected pins
// init inputs
pinMode(knopkaPusk, INPUT);
// digitalWrite(knopkaPusk, LOW);
pinMode(sensorPin, INPUT);
// digitalWrite(sensorPin, HIGH);
pinMode(sensorZarad, INPUT);
// digitalWrite(sensorZarad, HIGH);
pinMode(hand_brake_in, INPUT); // enable input
digitalWrite(hand_brake_in, HIGH); //если подтяжка реализована аппаратно то тут ненадо
pinMode(start_in, INPUT); // enable input
// digitalWrite(start_in, LOW); //pullup resustor enable
pinMode(sharging_in, INPUT); // enable input
// digitalWrite(sharging_in, LOW); //generator LOW normaly
// init outputs
//-------------------управление сигналкой---------------------------
// pinMode(outpinSigOff, OUTPUT); // enable output
// digitalWrite(outpinSigOff, LOW); //set digital 0
// pinMode(outpinSigOn, OUTPUT); // enable output
// digitalWrite(outpinSigOn, LOW); //set digital 0
//------------------------------------------------------------------
pinMode(outpinZarad, OUTPUT); // enable output
digitalWrite(outpinZarad, LOW); //set digital 0
pinMode(pech, OUTPUT); // enable output
digitalWrite(pech, LOW); //set digital 0
pinMode(ledPin, OUTPUT); // enable output
digitalWrite(ledPin, LOW); //set digital 0
pinMode(starter_out, OUTPUT); // enable output
digitalWrite(starter_out, LOW); //set digital 0
pinMode(engine_out, OUTPUT); // enable output
digitalWrite(engine_out, LOW); //set digital 0
pinMode(secpower_out, OUTPUT); // enable output
digitalWrite(secpower_out, LOW); //set digital 0
pinMode(status_out, OUTPUT); // enable output
digitalWrite(status_out, LOW); //set digital 0
Serial.begin(115200); //включаем передачу по сериал монитор
attachInterrupt(0, tahometr, RISING); //включаем прерывание по фронтам импульса и запускаем функцию тахометра
Setpoint = 1500; //здесь мы устанавливаем заданные обороты прогрева двигателя
Input = th; //присваиваем входу ПИД-регулятора значение тахометра в об/мин
myPID.SetOutputLimits(0, 180); //устанавливаем границы выходного сигнала для ПИД-регулятора
if (Setpoint < Input) //если начальные обороты больше заданных
{
revers = true; //
myPID.SetControllerDirection(REVERSE); //ПИД-регулятор используем обратный
}
myPID.SetMode(AUTOMATIC); //включаем ПИД-регулятор
//---- конец настройки входов и выходов контроллера --------------
}
void loop()
{
//---- собственно это и есть весь код программы --------------
// Serial.println(th); //печатаем в монитор значение тахоьетра в об/мин
tz = tz - 1; //арифметические операции для тахометра
if (tz == 0) {
th = 0; //если переменная тз равна нулю, переменная th обнуляется
}
val = analogRead(sensorPin);
zaradAkkum(); //контроль заряда аккумулятора телефона
//*********************************запуск от кнопки********************************************
knopkaPuskState = digitalRead(knopkaPusk);
if (knopkaPuskState != 0)
{
zapuskKnopka();
}
else {
knopkaPuskState = 0;
}
if (digitalRead(sharging_in) != sharging_on ) // проверяем что генератор не работает
{
digitalWrite(secpower_out, LOW); //выключаем фары итд
delay(1);
digitalWrite(pech, LOW); //выключаем печку
delay(1);
digitalWrite(ledPin, LOW); //выключаем светодиод индикации режима включения автоподсоса
delay(1);
digitalWrite(engine_out, LOW); //выключаем зажигание
}
if (actual_mode < 2 ) { //если двигатель не запущен
check_start(); //Управляем режимом запуска
}
else // иначе
{
check_for_shutdown(); //Управляем режимом ожидания окончания прогрева
} //но хорошая привычка фигурные скобки ставить всегда
set_status_led(); //независимо от режима Управляем светодиодом статуса
//------------------конец основного кода -----------------
}
//---- а дальше идут используемые функции и подфункции --------------
void check_start()
{
if (digitalRead(start_in) == 1 && left_start_try == 0) // 1 is command for start - 1 значит импульс старта пришел с дистанционного управления <--- тут определяется полярность импульса запуска
{
left_start_try = 3; // указываем что нужно попытаться трижды запустить движок
}
if ( left_start_try > 0 )
{ //------------------------------отключение сигналки----------------------------
//digitalWrite(outpinSigOff, HIGH);//сигнал на отключение сигналки
// delay(1000); //удержание 1 сек
//digitalWrite(outpinSigOff, LOW);//сброс сигнала
//delay(500);
//-------------------------------------------------------------------------------
digitalWrite(engine_out, HIGH); //включаем зажигание
// digitalWrite(secpower_out, HIGH); //включаем печку фары итд
delay(3000); // останавливаем код на 3 секунды чтобы бензонасос набрал давление
if (digitalRead(hand_brake_in) != hand_brake_on) //без ручника не делаем запуск
{
actual_mode = 2; // заканчиваем попытки запустить движок
left_start_try = 0; //без ручника другие попытки бесполезны
return;
}
if (digitalRead(sharging_in) != sharging_on ) // проверяем что генератор не работает
{
do_start(); // пытаемся запустить движок
left_start_try = left_start_try - 1 ; //уменьшаем число попыток
if (left_start_try == 0 )
actual_mode = 2; // заканчиваем попытки запустить движок
} // конец проверки что ручник стоит а генератор не работает
}
} // конец процедуры старта
void do_start()//тут будет запуск движка
{
digitalWrite(engine_out, HIGH); //включаем зажигание
digitalWrite(secpower_out, HIGH); //включаем печку фары итд
ataches();
servo_start();
digitalWrite(secpower_out, LOW); //выключаем печку фары итд
delay(1000);
//----------------------------------------------------------------------------------- цикл стартера
digitalWrite(starter_out, HIGH); //включаем стартер
for (int secs = 0; secs <= ENGINE_START_MAX_TIME ; secs++) //
{
delay(1000); // и продолжаем его держать включенным 1 секунду
if (digitalRead(sharging_in) == sharging_on) //если зарядка пошла то
break; // прерываем цикл
}
//-----------------------------------------------------------------------------------
digitalWrite(starter_out, LOW); //отключаем стартер
if (digitalRead(sharging_in) == sharging_on) //еще раз смотрим что зарядка пошла
{
actual_mode = 2; //Запоминаем что движок запущен
last_start_time = millis(); // запоминаем время запуска движка
}
else
{
ataches(); //
otkluchenie();
digitalWrite(secpower_out, LOW); //выключаем печку фары итд
digitalWrite(ledPin, LOW); //выключаем светодиод индикации режима включения автоподсоса
delay(1000);
digitalWrite(engine_out, LOW); //выключаем зажигание чтбы разблокировать реле стартера
delay(5000); // останавливаем код на 5 секунд
}
}
void check_for_shutdown()
{
//сюда мы попадаем когда контроллер считает что движок работает
if (val >= 1000 && th >= 0 ) //если температура более 85 и обороты более или ровны 0 то,
{
ataches(); //
otkluchenie();
}
if (digitalRead(sharging_in) != sharging_on ) //проверяем что движок случайно не заглох
{ do_shutdown();
digitalWrite(ledPin, LOW); //выключаем светодиод индикации режима включения автоподсоса
}
else
digitalWrite(secpower_out, HIGH); //включаем фары итд
if (digitalRead(hand_brake_in) != hand_brake_on ) //проверяем что если злодеи сняли с ручника то глушим мотор
{
digitalWrite(ledPin, LOW); //выключаем светодиод индикации режима включения автоподсоса
do_shutdown();
left_start_try = 0; // и больше не заводим
}
if (val < 1000 && th >= 750) //если темп менее 85 и обороты более или ровны 750, запускаем ПИД-регулятор
{
ataches(); //звпускаем функцию
pid();
}
if (digitalRead(start_in) == 1 ) // 1команда на отключение движка - 1 значит импульс старта пришел с дистанционного управления <--- тут определяется полярность импульса запуска
{
do_shutdown();
digitalWrite(ledPin, LOW); //выключаем светодиод индикации режима включения автоподсоса
}
//тут будем контролировать чтоб если забыли машинку заведенной она не молотила до скончания бензобака а выключалась через какоето время
if (actual_mode != 0 ) //значит не выключили заглохший двигатель только что
{
// милисекунды в ардуино обнуляются каждые 49 суток
// для того чтобы в случае если запуск произошел в течении последних 20 минут до обнуления мотор не молотил еще 49 суток
// нужно обнулить и время старта, при этом мотор максимум будет прогреваться вдвое больше обычного
if (millis() < last_start_time)
{
last_start_time = 0;
}
if (millis() > last_start_time + ENGINE_WARM_TIME) // если текущее время больше чем время старта + время прогрева
{
digitalWrite(ledPin, LOW); //выключаем светодиод индикации режима включения автоподсоса
do_shutdown();
left_start_try = 0; // и больше не заводим
}
}
}
void do_shutdown()
{
ataches();
otkluchenie();
digitalWrite(secpower_out, LOW); //выключаем печку фары итд
delay(1000);
digitalWrite(ledPin, LOW); //выключаем светодиод индикации режима включения автоподсоса
digitalWrite(engine_out, LOW); //вырубаем зажигание
actual_mode = 0; // движок выключили запомним это
last_start_time = 0; // ну и забудем о том что он был включен
//---------------------------управление сигналкой при активации раскомментировать-----------------------
// digitalWrite(outpinSigOn, HIGH);//сигнал включения сигналки
//delay(1000);//удержание 1 сек
// digitalWrite(outpinSigOn, LOW);// сброс сигнала включения
//------------------------------------------------------------------------------------------------------
delay(3000);
}
void set_status_led()
{
if (digitalRead(hand_brake_in) != hand_brake_on ) //Если ручник не стоит то выкл светодиод нечего ему в пути мигать попусту
{
digitalWrite(status_out, LOW);
return; //прерываем выполнение функции
}
if (actual_mode == 2) //Движок запущен
status_led_flash(); // показываем с какой попытки был прошлый запуск
else
digitalWrite(status_out, HIGH); // постоянное свечение - показываем что готов к следующему запуску
}
void status_led_flash()
{
static unsigned long big_interval = 0;
static unsigned long flash_interval = 0;
unsigned long flash_count = 0;
flash_count = 3 - left_start_try; //сколько раз мигать
//1 секндный интервал
if (millis() > flash_interval + 1000L)
flash_interval = millis() ; //задаем счетчие от 0 до 1 секунды
//задаем 6 секунд
if (millis() > big_interval + 6000L)
{
big_interval = millis() ; //задаем счетчие от 0 до 10секунд
flash_interval = big_interval;
}
if (millis() < big_interval + flash_count * 1000L) // делим 6 секндный интервал на два периода, в первый мигаем количество раз соответствующее числу израсходованных попыток
{ //мигает
if (millis() > flash_interval + 500L)
digitalWrite(status_out, HIGH);
else
digitalWrite(status_out, LOW);
}
else
{ // негорит
digitalWrite(status_out, LOW); //set digital 0
}
}
//************************************измеряем частоту на входе тахометра по прерыванию***********
void tahometr()
{
th = ((60000000 / ( micros() - micros_th)) / 2); //считаем об/мин
micros_th = micros(); // присваиваем новое значение от пришедшего импульса
tz = 10; //
}
void ataches() //**********************функция отключения и повторного включения сервопривода***************************
{
myservo.detach(); //отключаемся
delay(3); //ждем 3 мс
myservo.attach(9); //подключаемся
delay(3); //ждем 3 мс
}
void servo_start() {
val = analogRead(sensorPin);
myservo.attach(9, 630, 2500); //подключаем серву на 9 цифровом пине с заданным углом концевых положений
val = map(val, 0, 1023, 0, 180); //устанавливаем серво в положение соответствующее температуре двигателя.преобразуем темпер в положение сервы
myservo.write(val); // поворачиваем серву в расчинанное положение
delay(2000); //задерка 3 секунды для стабилизации сервы.
digitalWrite(ledPin, HIGH); //подаем на 12 цифровой пин +5 и включаем светодиод режима включения автоподсоса
myservo.detach();
}
void pid() {
digitalWrite(ledPin, HIGH); //зажигаем светодиод индикации автоподсоса
Input = th; //читаем на вход ПИД-регулятора обороты двигателя
myPID.Compute(); //считаем выходной сигнал ПИД-регулятора
myservo.attach(9, 630, 2500); //включаем серву на 3 цифровом пине, с длинной импульса от 630 до 2540(указываем границы поворота сервы)
delay(10); //задержка 10 мс
if (revers) //если пид регулятор обратный, то сервой управляем также относительно противоположной крайней точки
myservo.write(180 - Output); //
else //если регулятор прямой то,
myservo.write(Output); //крутим серву от 0 до 180
delay(10); //ждем серву 10 мс
myservo.detach(); //отключаемся от сервы
if (val < 1000 && val > 750 && th >= 750) //если температура менее 85 но более 60 и обороты больше или ровны 750 об/мин то,
{
digitalWrite(pech, HIGH); //включаем на пине 8 печку автомобиля
}
}
void otkluchenie() {
digitalWrite(pech, LOW); //выключаем печку
digitalWrite(ledPin, LOW); //выключаем светодиод индикации режима включения автоподсоса
myservo.write(180); //
{
delay(5);
} //замедляем серву
delay(1500);
myservo.detach(); //отключаемся от сервы
delay(10); //задержка0,001 секунда
}
//**************************контроль заряда аккумулятора телефона***********************
void zaradAkkum() {
float sensorVoltage = analogRead(sensorZarad);
sensorVoltage = sensorVoltage * 0.0048828125;
if (sensorVoltage <= 3.40) {
digitalWrite(outpinZarad, HIGH);
}
if (sensorVoltage >= 4.20) {
digitalWrite(outpinZarad, LOW);
}
delay(1);
// Serial.println(sensorVoltage);//для тестов. вывод напряжения акб на монитор
}
void zapuskKnopka() {
if (digitalRead(sharging_in) != sharging_on ) // проверяем что генератор не работает
{
digitalWrite(engine_out, HIGH); //включаем зажигание
delay(10);
ataches();
servo_start();
//----------------------------------------------------------------------------------- цикл стартера
digitalWrite(starter_out, HIGH); //включаем стартер
for (int secs = 0; secs <= ENGINE_START_MAX_TIME ; secs++) //
{
delay(1000); // и продолжаем его держать включенным 1 секунду
if (digitalRead(sharging_in) == sharging_on) //если зарядка пошла то
break; // прерываем цикл
}
//-----------------------------------------------------------------------------------
digitalWrite(starter_out, LOW); //отключаем стартер
delay(1000); //временно
if (digitalRead(sharging_in) == sharging_on) //еще раз смотрим что зарядка пошла
{
ataches();
myservo.write(180); //
{
delay(5);
} //замедляем серву
delay(1500);
myservo.detach(); //отключаемся от сервы
delay(10); //задержка0,001 секунда
digitalWrite(secpower_out, HIGH); //включаем фары итд
}
else {
digitalWrite(secpower_out, LOW); //выключаем фары
digitalWrite(engine_out, LOW); //выключаем зажигание
}
}
else {
digitalWrite(secpower_out, LOW); //выключаем фары итд
delay(1000);
digitalWrite(pech, LOW); //выключаем печку
delay(1000);
digitalWrite(ledPin, LOW); //выключаем светодиод индикации режима включения автоподсоса
delay(1000);
digitalWrite(engine_out, LOW); //выключаем зажигание
}
}
а енто уже готовый скетч того о чем вы долго думали, еще и с запуском по телефону