Модуль автозапуска автомобиля, по каналу GSM.

vic163-163
Offline
Зарегистрирован: 06.03.2018

  Модуль автозапуска автомобиля, с голосовыми сообщениями работы авто, по каналу GSM, разрабатывался с целью отсутствия автозапуска в авто, как дополнение к любой “простой” или штатной сигнализации. А так-же не иметь привязки к интернету (дополнительные траты) и SMS сообщений (сообщения могут “зависнуть” на сервере провайдера сотовой связи). Способностью работы с любым телефоном, кнопочным или смартфоном. Модуль работает в сетях GSM, надежность связи блока зависит от покрытия связью провайдером связи. Он не является автосигнализацией, а дополнением для автосигнализации с возможностью дистанционного запуска двигателя авто с ручной коробкой передач.

  У модуля имеются следующие сервисные возможности.

  1. Режим пидстопа. Если при работающем двигателе включить ручной тормоз, начнут периодически включатся фонари поворотников, и включится вентилятор печки (в режим, установленный при монтаже модуля). И при этом извлечь ключ из замка зажигания двигатель будет работать еще 10 минут. Если позвонить в это время на номер SIM карты модуля он сообщит “в режиме пидстопа”.
  2. Если в режиме пидстопа выйти из авто, двигатель при этом продолжает работать, и закрыть брелком двери, поставить на охрану, то произойдет постановка на разрешение автозапуска.
  3. Если при работающем двигателе, сначала заглушить мотор, затем включить ручной тормоз, подготовки к автозапуску не произойдет.
  4. Если авто не было подготовлено к автозапуску, и при звонке на модуль попытаться подать команду на запуск, три раза сработает сигнал поворотников, сообщит “не в режиме запуска”.
  5. Автозапуск двигателя происходит четырьмя попытками, если не произошло запуска сообщит “повторный запуск”. 1 попытка прокрутка стартера 0,75 сек., последующие попытки старта прибавляют по 0,25 сек.
  6. Если после 4 попыток авто не завелось, сообщит “не получилось попробуйте еще раз”, три раза моргнет поворотником.
  7. Двигатель авто в режиме авто прогрева работает 10 минут, если Вы считаете, что этого недостаточно после первого цикла прогрева, позвоните и еще раз запустите двигатель. В режиме авто прогрева периодически включаются фонари поворотников.
  8. Если авто было подготовлено к автозапуску и открыли дверь авто, то режим автозапуска сбросится. И дистанционного запуска не произойдет.
  9. Если авто находится в режиме авто прогрева, двигатель работает и открыть двери (взять или положить в салон авто что ни будь), а затем авто поставить вновь на сигнализацию. То будет проведено разрешение на автозапуск для следующего раза.
  10. Если авто находится в режиме авто прогрева. И позвонить в это время сообщит “уже прогреваюсь”.
  11. Если авто уже работает и не включен ручной тормоз, возможно авто в движении, то модуль при входящем звонке сообщит “двигатель уже запущен”.
  12. Если у Вашей установленной или штатной сигнализации, на брелке имеется кнопка открытия багажника ее можно задействовать как старт для автозапуска авто, подготовленного к старту, подав команду нажав на кнопку открытия багажника.
  13. При срабатывании “колокола” автосигнализации, модуль перезвонит вам и сообщит “сработала сигнализация авто”. Можно прослушать или не отвечать на звонок, сбросить.
  14. Если авто ставилось на охрану сигнализацией и колокол “пикнул”, то при открытии двери модуль перезвонит вам и сообщит “открыта дверь авто”. Полезна тем что, если сняли авто с охраны сканером она Вам перезвонит. Можно не отвечать на звонок, сбросить. Что бы модуль не звонил Вам при открытии двери, необходимо позвонив на модуль, подать команду 56  или ставить на охрану беззвучно. Не забудьте потом включить контроль открытия дверей командой 65.
  15. Если в авто включено зажигание, но не работает мотор, то модуль при входящем звонке сообщит “ включено зажигание”.
  16. Если авто в режиме прогрева, при звонке на модуль будет сообщение “уже прогреваюсь”.

  Управление модулем следующее.

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

После этого можно подавать следующие команды с клавиатуры телефона;

  1. 45   прозвучит “контроль связи”, модуль отключит Вас и перезвонит на номер записанный на SIM карте. Опция необходима для проверки находится ли авто в зоне уверенного приема сотового оператора. Или что бы 1 раз в три месяца модуль перезвонил Вам, в противном случае возможно отключение SIM карты от сети.
  2.  03   прозвучит “все поняла завожу”, если была проведена процедура подготовки авто к запуску. Модуль проведет запуск двигателя, от 1 до 4 попыток. Будет сообщать о режимах “зажигание”, “стартер”, “повторный запуск”, об успешном запуске “двигатель запушен” или не успешном “не запустилась! попробуйте еще раз!” и автоматически отключится. Если не было подготовки авто к запуску прозвучит “не в режиме запуска”, 3 раза моргнет поворотниками и отключится.
  3.  30 прозвучит “стоп прогрева”, модуль остановит двигатель, если авто было в режиме прогрева и автоматически отключится.
  4.  56 прозвучит “ отключен контроль дверей”, отключит автодозвон при открытии двери авто и автоматически отключится
  5.  65 прозвучит “ включен контроль дверей”, включит автодозвон при открытии двери авто и автоматически отключится.
  6.  89 прозвучит “ двигатель блокирован”, заблокирует двигатель (блокировка реле бензонасоса), будет включен периодический сигнал клаксона, моргание дальним светом фар и фонарями поворотников, для привлечения внимания. Автоматического отключения звонка не произойдет. Полезна для поиска авто на крупном паркинге.
  7.  98 прозвучит “ продолжайте движение”, разблокирует двигатель (разблокирует реле бензонасоса), отключит периодический сигнал клаксона и моргание дальним светом фар и фонари поворотников, автоматически отключится.

Основная часть интерфейса построена, из следующих функциональных блоков;

  1. Основная монтажная плата.
  2. Две платы Arduino_Promini 328-5V, 1я плата программная, 2я обработчик тахометра
  3. GSM модуль SIM800L.
  4. Стабилизатора напряжения mini360, для питания gsm модуля.
  5. Платы преобразователя уровня тахометра
  6. Блока внешних реле, выполненных “на проводах”

Принципиальная схема.

Рис1.

 

Пояснения входов схемы;

Podxvat        выход на реле зажигания Podxvat

Start             выход на реле стартера

Block           выход на реле блокировки двигателя

Klaxon  Ligh     выход на реле дальнего света и клаксона

Parking         вход на датчик паркинга или ручника

Stop             вход от концевика педали тормоза

Ignition1      вход от замка зажигания для контроля наличия ключа в замке

Ignition 2     вход для контроля работы при отсутствии ключа в замке

Alarm          вход при срабатывании колокола сигнализации авто

Tahometr       вход от сигнала тахометра или форсунки

CentrZamok     вход сигнала от центрального замка при закрытии дверей, замыканием на массу

ACC              выход для вторичных приборов авто, мотор печки

Pusk_Sig       вход на запуск от автосигнализации, команда открытия багажника

Blinks           выход моргать поворотником

Door- или Door+ -  в зависимости кокой уровень сигнала при срабатывании датчика двери

автомобиля.

Immo – Deton   На реле обходчика иммобилайзера и отключения датчика детонации.

 

 В схеме не прорисованы обмотки катушек реле и их коммутационные цепи.

Некоторые реле коммутирующие цепи автомобиля расположены на печатной плате, как  будет осуществлятся коммутация, зависит откомплектации авто.

   Схема блока дополнительных реле:

 Особенно обратить внимание каким сигналом управляется клаксон плюсом или массой.

  Так же если в эл. схеме авто присутствуют силовые реле клаксона и дальнего света то можно исключить дополнительные силовые реле.

Собранное устройство напоминает технологию “бутерброд”, из-за экономии места, и следствия доработок.

    Процесс сборки, когда готова печатная плата, в моем случае изготовлялась способом ЛУТ.

    Сначала монтируются все оптопары и smd резисторы, так как две оптопары и резисторы находятся под SIM модулем. Затем монтируется GSM SIM модуль. SIM модуль, 1я (arduino) плата программная (нижняя) и 2я (arduino) обработчик тахометра (верхняя) устанавливаются при монтаже на штырьках. Печатные платы в Sprint-Layout6 и PDF прилагаются в архиве.

    Стабилизатор mini360, впаивается вертикально рядом с SIM модулем, предварительно установив на нем 4,0 вольта, так как GSM модулю для работы, согласно документации, необходимо 3,6-4,2 вольта. Вход (12V.) и выход (4.0V) стабилизатора соединены к контактным площадкам основной платы проводниками.

  Далее необходимо запрограммировать GSM SIM модуль для работы в Российских сетях сотовой связи. Мною была использована терминальная программа SIM900 DIALOG. Подключение, к примеру, по следующей схеме.

Отправив в терминальной программе, GSM модулю, по отдельности, следующие команды;

AT+IPR=9600

ATE1

AT+DDET=1

AT+CMGF=0

AT+CMCB=1

AT+CSCS="gsm"

AT+CNMI=2,1,0,0,0

AT+VTD=1

AT+CMEE=1

AT+COLP=1

AT&W

На каждую из команд должен прийти ответ ОК, в терминальной программе.

Не отключая модуля от компьютера, необходимо записать во внутреннюю flash память GSM модуля, голосовые файлы с расширением amr. Делается это через программу Sim800 Series ArmFile Download v1.00, следующие сообщения;

// 1   открываю двери! (зарезервировано на будущие доработки)

// 2   двигатель запущен, двигатель запущен!...

// 3   оп, повторный запуск!

// 4   закрываю двери!  (зарезервировано на будущие доработки)

// 5   уже, прогреваюсь!

// 6   стоп прогрева!

// 7   все поняла, завожу!

// 8   двигатель блокирован, двигатель блокирован...

// 9   продолжайте движение!

// 10  оп, двигатель уже запущен!

// 11  контроль связи!

// 12  низкое напряжение!

// 13  короткие гудки  (зарезервировано на будущие доработки)

// 14  нарушение охраны!

// 15  открыта! дверь! авто!

// 16  Включена Тихая Блокировка. (зарезервировано на будущие доработки)

// 17  отключен! контроль! двери!

// 18  включен! контроль! двери!

// 19  Стартер

// 20  не в режиме запуска

// 21  Зажигание!

// 22  SMS

// 23  Включено! Зажигание!

// 24  не запустилась! попробуйте еще раз!...

// 25  авто! в режиме! пидстопа!

 В комплекте прилагается программа и голосовые файлы. Так как программа, ArmFile Download, не может записать одновременно более 10 файлов. То для удобства (что бы не прописывать каждый раз путь к файлам), на диск D:\ копируем папку Voice_files, с amr. файлами. И перед каждым запуском программы, для удобства, подменяем Config.ini в папке с программой ArmFile Download, прилагаемыми файлами (Config1.ini _ Config2.ini _ Config3.ini.), из папки Voice_files, переименовывая их в Config.ini.

  После того как все запрограммировали, проверяем работоспособность GSM SIM800L модуля, например программой SIM900 DIALOG. Установив в модуль sim карту, подключив к питанию, запускаем терминальную программу, звоним на номер сим карты модуля. Увидев в терминале сообщение о входящем звонке, отправляем команду ответа на звонок АТА. Когда соединение произойдет можно проиграть записанные arm. файлы, отправив в окне терминала следующее.

  Воспроизвести файл "в телефон" с уровнем громкости 90%:  AT+CREC=4,"C:\User\9.amr",0,90 (где 9.amr это номер голосового сообщения).

   Убедившись, что все голосовые сообщения нормально проигрываются. Отключаем модуль для дальнейшей сборки.

   Впаиваем на штырьках из комплекта Arduino остальные платы и рядом плату преобразователя уровней тахометра. Соединяем недостающие соединения проводниками. Так как у процессора Arduino 1й программной платы использованы все ножки, включая TX-RX, предназначенные для программирования и работы в мониторе порта, программирование при этом происходит нормально так как в Arduino присутствует загрузчик. И чтобы модуль мог корректно определять напряжение аккумуляторной батареи авто, необходимо вычислить коэффициент деления АЦП процессора, из-за разброса параметров резисторов на pin A6. Загружаем в плату скетч ACP_pin, наблюдая через монитор порта подбираем значение float m1 = ХХ.ХХ в скетче и сверяя с показанием тестера, измеряя напряжение питания модуля. Вычислив коэффициент АЦТ (ХХ.ХХ), записываем это значение в основном скетче Programs. Программируем обе платы Arduino нижнюю программную скетчем Programs (со скорректированным коэффициентом АЦП), верхнюю частотомера скетчем Frequency_meter. Подсоединяем необходимые внешние силовые реле.       

Проверяем полностью собранное устройство на столе, вместо исполнительных устройств авто подключаем тумблера, кнопки и светодиоды. В качестве источника частоты тахометра, использовал трансформатор 220/3V. Работа скетчей расписана в них самих. Подключение к авто согласно схемы конкретного автомобиля. 

ACP_pin.ino

//Настройка АЦП канала

#include <SoftwareSerial.h>
#define BAT_Pin        A6          // вход на батарею, через делитель напряжения 47kom / 10 кОм

float Vbat1, Vbat1Start, V_min1 ;  // переменная хранящая напряжение бортовой сети1
// делитель для перевода АЦП1 в вольты для резистров 47/10kOm, подбор напряжения индикации АЦП в мониторе порта.
// больше значение меньше напряжение в мониторе порта
float m1 = 36.45;                  // уменьшаю увеличивается значение напряжения питания
unsigned long Time1 = 0;           // время выполнения detection1

void setup() {
  Serial.begin(9600);             //скорость порта            
  detachInterrupt(0);             // отключаем обработку внешнего прерывания на Pin2
  detachInterrupt(1);             // отключаем обработку внешнего прерывания на Pin3
}

void loop() {
  if (millis() > Time1 + 500) Time1 = millis(), detection1();      // выполняем функцию detection1 () каждые 0,5 сек
}

void detection1() {        // условия проверяемые каждые 10 сек
  Vbat1 = VoltRead1();     // замеряем напряжение на батарее, на A6
  Serial.println("");  
}

//---  замеряем напряжение на батарее и переводим значения в вольты ----------
float VoltRead1() {
  float ADCC1 = analogRead(BAT_Pin);
  ADCC1 = ADCC1 / m1 ;
  Serial.print(ADCC1);                // ОТКЛЮЧИТЬ ПОСЛЕ НАСТРОЙКИ АЦП
  if (ADCC1 < V_min1) V_min1 = ADCC1;     // переводим данные ацп1 в вольты
  return (ADCC1);
}

 

 

Programs.ino

// ---  2_system7  //  рисунок sxema_34
// -----КОМАНДЫ DTMF------
// "45" обратный звонок
// "03"  старт
// "30"  стоп
// "56"  отключение контроля дверей
// "65"  включение контроля дверей
// "89"  блокировка двигателя
// "98"  снятие блокировки двигателя
// -----Voice -- голосовые сообщения------
// ------1   откываю двери!...
// 2   двигатель запущен,  двигатель запущен!...
// 3   оп, повторный запуск!...
// ----- 4   закрываю двери!...
// 5   уже, прогреваюсь!...
// 6   стоп прогрева!...
// 7   все поняла, завожу!...
// 8   двигатель блокирован, двигатель блокирован...
// 9   продолжайте движение!...
// 10  оп, двигатель уже запущен!...
// 11  контроль связи!...
// 12  низкое напряжение!...
// 13  короткие гудки
// 14  нарушение охраны!...
// 15  открыта! дверь! авто!
// 16  нажат тормоз!
// 17  отключен! контроль! двери!
// 18  включен! контроль! двери!
// 19  Стартер+
// 20  не в режиме запуска+
// 21  Зажигание!+
// 22  SMS
// 23  Включено! Зажигание!
// 24  не запустилась! попробуйте еще раз!...
// 25  авто! в режиме! пидстопа!

#include <SoftwareSerial.h>
SoftwareSerial SIM800(7, 6);       // для новых плат начиная с версии RX,TX

#define Podxvat        12          // выход на реле зажигания Podxvat + реле датчик детонации-иммобилайзер
#define Start          10          // выход на реле стартера
#define Block          13          // выход на реле блокировки двигателя с клаксоном
#define ObrabotkaCall  A5          // вывод для отработки обратного звонка
#define Klaxon         8           // выход на реле дальнего света и клаксона 
#define BAT_Pin        A6          // вход на батарею, через делитель напряжения 47kom / 10 кОм
#define Parking        A1          // вход на датчик паркинга или ручник, HIGH на паркинге(программно)
#define StopPin        A2          // вход на концевик педали тормоза, HIGH
#define Ignition       A3          // вход на провод от замка зажигания, HIGH
#define Alarm          2           // вход для звонка при срабатывания сигналки
#define Door           3           // вход для звонка при срабатывании дверей, на массу, LOW
#define ObrabotkaDveri A4          // вывод для обработки открытой двери
#define ZapretDoor     A0          // вывод для обработки, отключения контроля открытия двери
#define Tahometr       5           // вывод Tahometr, HIGH  есть подсчет импульсов от тахометра
#define RazrAutoZap    11          // вывод для обработки разрешения на авто запуск, HIGH
#define CentrZamok     4           // вход сигнала от центр замка при закрытии дверей, на массу, LOW
#define ACC            9           // выход для вторичных приборов авто, HIGH
#define Pusk_Sig       A7          // вход от авто сигнализации на запуск
#define Blinks9        1           // выход 3 раза моргнуть поворотником, не в режиме запуска
#define Blinks10       0           // выход моргать поворотником в режиме прогрева

//------- настройки переменных --------
String pin = "";                   // строковая переменная набираемого пинкода
bool ring = false;                 // флаг момента снятия трубки
float Vbat1, V_min1 ;              // переменные хранящие напряжение бортовой сети1
float m1 = 36.88;                  // делитель для перевода АЦП1 в вольты для резистров 47/10kOm, подбор напряжения индикации АЦП в мониторе порта.
float Vbat2, V_min2 ;              // переменная хранящая напряжение бортовой сети2
float m2 = 100.00;                 // делитель для перевода АЦП2 в вольты
unsigned long Time1 = 0;           // время выполнения detection1
unsigned long Time2 = 0;           // время выполнения detection2
unsigned long StartTimeON = 0;     // время работы стартера
unsigned long previousMillis = 0;  // Зададим начальное значение для счетчика millis
int Timer = 0;                     // таймер времени прогрева двигателя по умолчанию = 0
bool heating = false;              // переменная состояния режим прогрева двигателя
int count = 0;                     // для счетчиков запуска

unsigned long PsoTime4 = 0;        // для таймера в цикле отработки временного пидстопа
bool timer4 = 0;                   // флаг включен ли таймер, 0 - выключен, 1 - включен
uint32_t TimePush4 = 600000;       // Время срабатывания  600000 мсек.= 10 мин

unsigned long PsoTime5 = 0;        // для таймера в цикле отработки обратного звонка
bool timer5 = 0;                   // флаг включен ли таймер, 0 - выключен, 1 - включен
uint16_t TimePush5 = 500;         // Время срабатывания вывод для отработки обратного звонка
bool call_is_made5 = false;        // флаг "звонок выполнен" (в цикле отработки обратного звонка)

unsigned long PsoTime6 = 0;        // для таймера в цикле срабатывания сигналки
bool timer6 = 0;                   // флаг включен ли таймер
uint16_t TimePush6 = 2500;         // Время срабатывания сигналки
bool call_is_made6 = false;        // флаг "звонок выполнен" (в цикле срабатывания сигналки)

unsigned long PsoTime7 = 0;        // для таймера в цикле срабатывания двери
bool timer7 = 0;                   // флаг включен ли таймер
uint16_t TimePush7 = 500;          // Время срабатывания двери
bool call_is_made7 = false;        // флаг "выполнения" (в цикле срабатывания двери)

unsigned long PsoTime8 = 0;        // для таймера в цикле включения опции обработки для срабатыванияобратных звонков сигналки и двери
bool timer8 = 0;                   // флаг включен ли таймер
uint16_t TimePush8 = 10;           // Время включения опции обработки для срабатывания двери
bool call_is_made8 = false;        // флаг "выполнения" (в цикле включения опции обработки для срабатывания двери)

int k2 = 0;                        // для счетчика последний момент времени, когда состояние светодиода изменялось
unsigned long previousMillis2 = 0;
long OnTime9 = 500;                // длительность свечения светодиода (в миллисекундах)
long OffTime9 = 700;               // светодиод не горит (в миллисекундах)
bool state9 = 0;                   //
int Blinks9state9 = LOW;           // состояние выхода, 3 раза моргнуть поворотником

unsigned long previousMillis3 = 0;
long OnTime10 = 500;               // длительность свечения светодиода (в миллисекундах)
long OffTime10 = 3000;             // светодиод не горит (в миллисекундах)
bool state10 = 0;                  //
int Blinks10state10 = LOW;         // состояние выхода, моргать поворотником

unsigned long previousMillis4 = 0;     // Зададим начальное значение для счетчика millis для Gygok()
long OnTime11 = 500;                   // длительность свечения светодиода (в миллисекундах)
long OffTime11 = 500;                   // светодиод не горит (в миллисекундах)
bool state11 = 0;                       //
int Klaxonstate11 = LOW;               // состояние выхода Klaxon

bool gabarit = false;

void setup() {
  pinMode(Podxvat, OUTPUT);
  pinMode(Start, OUTPUT);
  pinMode(Block, OUTPUT);
  pinMode(ObrabotkaCall, OUTPUT);
  pinMode(Klaxon, OUTPUT);
  //  pinMode(Parking, INPUT);
  //  pinMode(StopPin, INPUT);
  //  pinMode(Ignition, INPUT);
  pinMode(Alarm, INPUT_PULLUP);   // указываем пин на вход для с внутричипной подтяжкой к +V, для звонка при срабатывания сигналки
  pinMode(Door, INPUT_PULLUP);    // указываем пин на вход для с внутричипной подтяжкой к +V, для звонка при срабатывании двери
  pinMode(ObrabotkaDveri, OUTPUT);
  pinMode(ZapretDoor, OUTPUT);
  //  pinMode(Tahometr, INPUT);       // Tahometr HIGH есть подсчет импульсов от счетчика оборотов
  pinMode(RazrAutoZap, OUTPUT);
  pinMode(CentrZamok, INPUT_PULLUP);
  pinMode(ACC, OUTPUT);
  pinMode(Blinks9, OUTPUT);
  pinMode(Blinks10, OUTPUT);

  delay(100);
  SIM800.begin(9600);             //скорость связи с модемом
  detachInterrupt(0);             // отключаем обработку внешнего прерывания на Pin2
  detachInterrupt(1);             // отключаем обработку внешнего прерывания на Pin3
  digitalWrite(Podxvat, LOW);
  digitalWrite(Block, LOW);
  digitalWrite(ObrabotkaCall, LOW);
  digitalWrite(RazrAutoZap, LOW);
  digitalWrite(Blinks9, LOW);
  digitalWrite(Blinks10, LOW);
  //  SIM800_reset();
}

/*  ---- - Перезагрузка МОДЕМА SIM800L  ----//на некоторых модемах не работает
  void SIM800_reset() {
  delay(10000); SIM800.println("AT+CMGDA=\"DEL ALL\"");  // Удаляем все СМС чекрез 10 сек, после старта SIM модуля
  }*/

void loop() {
  if (SIM800.available())  resp_modem();                            // если что-то пришло от SIM800 в Ардуино отправляем для разбора
  if (Serial.available())  resp_serial();                           // если что-то пришло от Ардуино отправляем в SIM800
  if (millis() > Time1 + 2000) Time1 = millis(), detection1();      // выполняем функцию detection1 () каждые 2 сек
  if (millis() > Time2 + 100) Time2 = millis(), detection2();       // выполняем функцию detection2 () каждые 0,1 сек
  if (heating == true && digitalRead(StopPin) == HIGH)  heatingstop(1), delay(1000), digitalWrite(RazrAutoZap, LOW); // если нажали на педаль тормоза в режиме прогрева, сброс прогрева и RazrAutoZap
  if (heating == true && digitalRead(Podxvat) == HIGH && digitalRead(Parking) == LOW) heatingstop(1), delay(1000), digitalWrite(RazrAutoZap, LOW); // если выключили Parking в режиме прогрева, сброс прогрева и RazrAutoZap

  //----моргаем реле дальнего света и клаксона, при блокировке мотора-------------
  if (digitalRead(Block) == HIGH) Gygok();
  if (digitalRead(Block) == LOW) digitalWrite(Klaxon, LOW);

  //--- подхват зажигания Podxvat при заведнном двигателе и включенном ручнике, режим пидстопа -------
  if (digitalRead(Ignition) == HIGH && digitalRead(Parking) == HIGH && digitalRead(Tahometr) == HIGH && digitalRead(RazrAutoZap) == LOW) {
    digitalWrite(Podxvat, HIGH);
    delay(1);
    digitalWrite(ACC, HIGH);
  }
  // заглох мотор отключить подхват зажигания Podxvat
  if (digitalRead(Podxvat) == HIGH && digitalRead(Parking) ==  HIGH && digitalRead(Tahometr) == LOW) {
    delay(1);
    heatingstop(1);
    delay(1);
    timer4 = 0;
  }
  //включение разрешения автозапуска RazrAutoZap, при закрытии дверей центр. замком
  if (digitalRead(Tahometr) == HIGH && digitalRead(Podxvat) == HIGH && digitalRead(Door) == HIGH && digitalRead(CentrZamok) == LOW) {
    delay(1);
    digitalWrite(RazrAutoZap, HIGH);
    delay(1);
    heatingstop(1);
  }

  //если открыли дверь авто после постановки на авто запуск, сброс RazrAutoZap в LOW
  if (heating == false && digitalRead(RazrAutoZap) == HIGH && digitalRead(Door) == LOW) {
    delay(1);
    digitalWrite(RazrAutoZap, LOW);
  }
  //если нажали на тормоз после постановки на авто запуск, сброс RazrAutoZap в LOW
  if (digitalRead(StopPin) == HIGH && digitalRead(RazrAutoZap) == HIGH && heating == false) {
    delay(1);
    digitalWrite(RazrAutoZap, LOW);
  }

  // отключился Podxvat, отключаем АСС
  if (digitalRead(Podxvat) == LOW) {
    delay(1);
    digitalWrite(ACC, LOW);
  }

  //---- обработка времени выполнения пидстопа ---------
  if (!timer4 && digitalRead(Ignition) == HIGH && digitalRead(Parking) == HIGH && digitalRead(Tahometr) == HIGH && digitalRead(Podxvat) == HIGH && heating == false) {
    timer4 = 1;  // если условия выполнены  запускаем таймер на пидстоп
    PsoTime4 = millis();
  }
  if (digitalRead(Parking) == LOW && digitalRead(Tahometr) == HIGH && digitalRead(Podxvat) == HIGH && heating == false) {
    timer4 = 0;                // если Parking выключен выключаем таймер, сбрасываем флаг
    digitalWrite(Podxvat, LOW);
  }
  if (timer4 && millis() - PsoTime4 > TimePush4)  // если таймер был включен и кончился,
  {
    timer4 = 0;                                                  // выключаем таймер и
    digitalWrite(Podxvat, LOW); // если флаг выполнен то выключаем подхват зажигания Podxvat
  }

  // включился АСС моргать поворотником, отключился не моргаем
  if (digitalRead(ACC) == LOW) digitalWrite(Blinks10, LOW);
  if (digitalRead(ACC) == HIGH) Blinker();

  // 3 раза моргнуть поворотником, не в режиме запуска
  unsigned long currentMillis2 = millis();   // текущее время в миллисекундах, выясняем не настал ли момент сменить состояние светодиода
  // если светодиод включен и светится больше чем надо
  if ((Blinks9state9 == HIGH) && (currentMillis2 - previousMillis2 >= OnTime9))
  {
    Blinks9state9 = LOW;                   // выключаем
    previousMillis2 = currentMillis2;   // запоминаем момент времени
    digitalWrite(Blinks9, Blinks9state9);   // реализуем новое состояние
    k2++;
    if (k2 > 2 ) state9 = 1;    // если больше переводим в другое состояние
  }
  else if ((Blinks9state9 == LOW) && (currentMillis2 - previousMillis2 >= OffTime9) && !state9)    //здесь проверяем 3 пунктом это состояние
  {
    Blinks9state9 = HIGH;                   // включаем
    previousMillis2 = currentMillis2 ;   // запоминаем момент времени
    digitalWrite(Blinks9, Blinks9state9);    // реализуем новое состояние
  }

  //---- обработка обратного звонка  -----------
  if (!timer5 && digitalRead(ObrabotkaCall) == HIGH) {
    timer5 = 1;  // если таймер выключен и ObrabotkaCall == HIGH запускаем таймер
    PsoTime5 = millis();
  }
  if (digitalRead(ObrabotkaCall) == LOW) {
    timer5 = 0;  // если ObrabotkaCall == LOW молчит выключаем таймер, сбрасываем флаг "звонок выполнен"
    call_is_made5 = 0;
  }
  if (timer5 && millis() - PsoTime5 > TimePush5)  // если таймер был включен и кончился,
  {
    timer5 = 0;                                   // выключаем таймер и
    if (call_is_made5 == 0) call1();              // если флаг "звонок выполнен" в фальсе то звоним хозяину
  }

  //----------------срабатывание сигналки-----------------
  if (!timer6 && digitalRead(Alarm) == LOW) {
    timer6 = 1;  // если таймер выключен и работает колокол запускаем таймер, 2,5 сек
    PsoTime6 = millis();
  }
  if (digitalRead(Alarm) == HIGH) {
    timer6 = 0;  // если колокол молчит выключаем таймер, сбрасываем флаг "звонок выполнен"
    call_is_made6 = 0;
  }
  if (timer6 && millis() - PsoTime6 > TimePush6)        // если таймер был включен и кончился,
  {
    timer6 = 0;                                         // выключаем таймер и
    heatingstop(1);                                     // стоп прогрева
    if (call_is_made6 == 0) call2();                    // если флаг "звонок выполнен" то звоним хозяину
  }

  //----------------срабатывание дверей-----------------
  if (!timer7 && digitalRead(Door) == LOW && digitalRead(ObrabotkaDveri) == HIGH) {
    timer7 = 1;  // если таймер выключен и открыты двери запускаем таймер, 0,5 сек
    PsoTime7 = millis();
  }
  if (digitalRead(Door) == HIGH && digitalRead(ObrabotkaDveri) == HIGH) {
    timer7 = 0;  // если дверь закрыли выключаем таймер, сбрасываем флаг
    call_is_made7 = 0;
  }
  if (timer7 && millis() - PsoTime7 > TimePush7)         // если таймер был включен и кончился,
  {
    timer7 = 0;                                          // выключаем таймер и
    if (call_is_made7 == 0) call3();                     // если флаг "звонок выполнен" в фальсе то звоним хозяину
  }

  //---- запуск обработки на срабатывание открытых дверей ---------
  //---- что бы звонок проходил только, после постановки/снятия с охраны --------
  if (!timer8 && digitalRead(Alarm) == LOW && digitalRead(ZapretDoor) == LOW) {
    timer8 = 1;  // если таймер выключен и пикнул колокол запускаем таймер, 10 мсек
    PsoTime8 = millis();
  }
  if (digitalRead(Alarm) == HIGH) {
    timer8 = 0;                // если колокол молчит выключаем таймер, сбрасываем флаг
    call_is_made8 = 0;
  }
  if (timer8 && millis() - PsoTime8 > TimePush8)                  // если таймер был включен и кончился,
  {
    timer8 = 0;                                                  // выключаем таймер и
    if (call_is_made8 == 0)  digitalWrite(ObrabotkaDveri, HIGH); // если флаг выполнен в фальсе то включаем ObrabotkaDveri
  }
}

//----------------обратный звонок------------------
void call1() {
  delay(100);
  SIM800.println("AT+CPBR=1"); // считывает запись с индексом 1 телефонной книги SIM-карты
  delay(200);
  SIM800.println("ATD>1");   // позвонить на 1 номер  телефонной книги SIM-карты, читает номер с sim карты но не набирает, поэтому->
  delay(200);
  SIM800.println("ATDL");    // позвонить на последний номер
  delay(100);
  if (SIM800.find("OK"));
  while (1) {                    // ожидание ответа вызова
    SIM800.println("AT+CPAS");        // при каждой итерации опрашиваем модуль
    if (SIM800.find(":")) break;      // если :, то выходим из цикла while
    delay(100);
  }
  delay(1000);
  SIM800.print("AT+CREC=4,\"C:\\User\\"), SIM800.println("11.amr\",0,95");    //голосовое сообщение "контроль связи"
  delay(4000);
  SIM800.println("ATH0");
  call_is_made5 = 1;                // флаг "звонок выполнен" в труе
  digitalWrite(ObrabotkaCall, LOW);
}

//--------звонок при срабатывании сигналки------------
void call2() {
  delay(100);
  SIM800.println("AT+CPBR=1"); // считывает запись с индексом 1 телефонной книги SIM-карты
  delay(200);
  SIM800.println("ATD>1");   // позвонить на 1 номер  телефонной книги SIM-карты, читает номер с sim карты но не набирает, поэтому->
  delay(200);
  SIM800.println("ATDL");    // позвонить на последний номер
  delay(100);
  if (SIM800.find("OK"));
  while (1) {                    // ожидание ответа вызова
    SIM800.println("AT+CPAS");        // при каждой итерации опрашиваем модуль
    if (SIM800.find(":")) break;      // если :, то выходим из цикла while
    delay(100);
  }
  delay(1000);
  SIM800.print("AT+CREC=4,\"C:\\User\\"), SIM800.println("14.amr\",0,95");    //голосовое сообщение "нарушение охраны"
  delay(4000);
  SIM800.println("ATH0");
  call_is_made6 = 1;                // флаг "звонок выполнен" в труе
}

//----звонок при срабатывании двери-----------
void call3() {
  delay(100);
  SIM800.println("AT+CPBR=1"); // считывает запись с индексом 1 телефонной книги SIM-карты
  delay(200);
  SIM800.println("ATD>1");   // позвонить на 1 номер  телефонной книги SIM-карты, читает номер с sim карты но не набирает, поэтому->
  delay(200);
  SIM800.println("ATDL");    // позвонить на последний номер
  delay(100);
  if (SIM800.find("OK"));
  while (1) {                    // ожидание ответа вызова
    SIM800.println("AT+CPAS");        // при каждой итерации опрашиваем модуль
    if (SIM800.find(":")) break;      // если :, то выходим из цикла while
    delay(100);
  }
  delay(1000);
  SIM800.print("AT+CREC=4,\"C:\\User\\"), SIM800.println("15.amr\",0,95");    //голосовое сообщение "открыта дверь авто"
  delay(4000);
  SIM800.println("ATH0");
  call_is_made7 = 1;                // флаг "звонок выполнен" в труе
  if (digitalRead(Alarm) == HIGH) digitalWrite(ObrabotkaDveri, LOW); //сброс ObrabotkaDveri, до следующего импульса с сигналки
}

// -------  ТРАНСЛИРУЕМ КОМАНДЫ из ПОРТА В МОДЕМ  ----------------
void resp_serial () {
  String at = "";
  int k = 0;
  while (Serial.available()) k = Serial.read(), at += char(k), delay(1);
  SIM800.println(at), at = "";
}

//------  AНАЛИЗИРУЕМ БУФЕР ВИРТУАЛЬНОГО ПОРТА МОДЕМА -------------
void resp_modem () {
  String at = "";           // набиваем в переменную at
  int k = 0;
  while (SIM800.available()) k = SIM800.read(), at += char(k), delay(1);
  Serial.println(at);

  if (at.indexOf("RING")  > -1) {      // входящий звонок
    delay(200), SIM800.println("ATA"), ring = true;
  }
  else if (at.indexOf("+DTMF: ")  > -1)        {
    String key = at.substring(at.indexOf("") + 9, at.indexOf("") + 10);
    pin = pin + key;
    if (pin.indexOf("*") > -1 ) pin = "";
  }
  else if (at.indexOf("NO CARRIER") > -1 ) {
    SIM800.println("AT+CLIP=1;+DDET=1"); // Активируем АОН и декодер DTMF
  }
  at = "";            // Возвращаем ответ можема в монитор порта , очищаем переменную

  if (pin.indexOf("45") > -1 ) {
    pin = "", Voice(11), delay (3000), SIM800.println("ATH0"), delay (100), digitalWrite(ObrabotkaCall, HIGH);   //обратный звонок
  }

  else if (pin.indexOf("89") > -1 ) {
    pin = "", Voice(8), digitalWrite(Block, HIGH), heatingstop(1); // блокировка двигателя "двигатель блокирован", без сброса звонка
  }

  else if (pin.indexOf("98") > -1 ) {
    pin = "", Voice(9), digitalWrite(Block, LOW), delay (3000), SIM800.println("ATH0"); //снятие сблокировки двигателя "продолжайте движение"
  }

  else if (pin.indexOf("03") > -1 ) {           // команда на пуск запуска
    pin = "";
    if (digitalRead(Block) == HIGH)  // если на блокировке
    {
      Voice(8), delay (4000), SIM800.println("ATH0");  // "двигатель блокирован"
    }
    else if (digitalRead(Podxvat) == LOW && digitalRead(Ignition) == LOW && digitalRead(StopPin) == LOW && digitalRead(RazrAutoZap) == HIGH && digitalRead(Block) == LOW)
    {
      Voice(7), delay (2000), enginestart(4); // "все поняла завожу" // запуск (4) попытки
    }
    else if (heating == true)   // если на прогреве
    {
      Voice(5), delay (3000), SIM800.println("ATH0");   // "уже, прогреваюсь!..."
    }
    else if (digitalRead(RazrAutoZap) == LOW)        // если нет разрешения автозапуска
    {
      Voice(20), delay (3000), SIM800.println("ATH0");   // "не врежиме запуска"
      delay (1);
      k2 = 0;       //обнуление счетчика к2 и state9, что бы 3 раза моргнуть поворотником
      state9 = 0;
    }
    else if (digitalRead(Ignition) == HIGH && digitalRead(Tahometr) == HIGH && digitalRead(Block) == LOW)  // если двигатель запущен ключем
    {
      Voice(10), delay (3000), SIM800.println("ATH0");   // "оп, двигатель уже запущен!..."
    }
  }

  else if (pin.indexOf("30") > -1 ) {  // команда стоп прогрева
    pin = "";
    if (heating == true)
    {
      Voice(6), delay(2000), heatingstop(1); // (стоп прогрева)
      SIM800.println("ATH0");
    }
    else if (heating == false)
    {
      false;
      SIM800.println("ATH0");
    }
  }

  else if (pin.indexOf("56") > -1 ) {
    pin = "", Voice(17), digitalWrite(ZapretDoor, HIGH), delay (3000), SIM800.println("ATH0"); // "отключено! срабатывание! двери!"
  }

  else if (pin.indexOf("65") > -1 ) {
    pin = "", Voice(18), digitalWrite(ZapretDoor, LOW), delay (3000), SIM800.println("ATH0"); // "включено! срабатывание! двери!"
  }

  //------голосовые сообщения при входящем звонке-----------
  if (ring == true) {
    ring = false, delay (2000), pin = ""; // обнуляем пин

    if (digitalRead(Alarm) == LOW && digitalRead(Block) == LOW) {    //сработала сигнализация на авто
      Voice(14);    // "нарушение охраны"
    }
    else if (digitalRead(Block) == HIGH) { //авто находится в режиме блокирови Voice(8)
      Voice(8);    // "двигатель блокирован"
    }
    else if (digitalRead(Podxvat) == LOW && digitalRead(Ignition) == HIGH && digitalRead(Block) == LOW && digitalRead(Tahometr) == HIGH && heating == false) {  //включено зажигание, подхват зажигания и нет прогрева от arduino
      Voice(10);                          //   Voice(10) "двигатель уже запущен"
    }
    else if (digitalRead(Podxvat) == HIGH && digitalRead(Block) == LOW && digitalRead(Tahometr) == HIGH && heating == false) {  //включено зажигание, подхват зажигания и нет прогрева от arduino
      Voice(25);                          // Voice(25) "авто! в режиме! пидстопа!"
    }
    else if (digitalRead(Podxvat) == LOW && digitalRead(Ignition) == HIGH && digitalRead(Block) == LOW && digitalRead(Tahometr) == LOW && heating == false) {
      Voice(23);          // "включено зажигание"
    }
    else if (Vbat1 < 10.5) {               // "низкое напряжение"
      Voice(12);
    }
    else if (digitalRead(Podxvat) == LOW && digitalRead(Ignition) == LOW && digitalRead(Tahometr) == LOW && digitalRead(Block) == LOW) {
      Voice(22);       //при входящем звонке тональный гудок 22
    }
    else if (heating == true) {
      Voice(5);          // "уже прогреваюсь"
    }
  }
}

void detection1() {        // условия проверяемые каждые 2 сек
  Vbat1 = VoltRead1();     // замеряем напряжение на батарее, на A6
  if (Timer > 0) Timer--;  //если кол-во попыток запуска >0, запускаем таймер
  if (heating == true && Timer < 1) heatingstop(0);  // остановка прогрева если закончился таймер
  if (heating == true && Vbat1 < 10.00) heatingstop(1);  // остановка прогрева если напряжение просело ниже 10 вольт
}

void detection2() {         // условия проверяемые каждые 0,1 сек
  Vbat2 = VoltRead2();      // замеряем напряжение на A7
  if (Vbat2 >= 5.00 && digitalRead(RazrAutoZap) == HIGH && digitalRead(Ignition) == LOW && digitalRead(Podxvat) == LOW) enginestart(4); // запуск с пульта сигналки
  else if (Vbat2 >= 5.00 && digitalRead(RazrAutoZap) == LOW) {
    k2 = 0;       //обнуление счетчика к2 и state9, что бы 3 раза моргнуть поворотником
    state9 = 0;
  }
}

//  ----  программа запуска двигателя  -----------
void enginestart(int Attempts) {                 // () заданное количество попыток запуска
  int StTime = constrain(StTime, 750, 3000);    // ограничиваем диапазон работы стартера от 0,75 до 6 сек
  Timer = constrain(Timer, 300, 300);          // ограничиваем таймер - Timer в значениях от 10 до 10 минут
  count = 0;                                      // переменная хранящая число совершенных попыток запуска

  // если напряжение АКБ больше 10 вольт, зажигание выключено, счетчик заданного числа попыток ( enginestart(4)
  while (Vbat1 > 10.00 && digitalRead(Ignition) == LOW && count < Attempts) {
    count++;
    delay (1000);                 // пауза на включение Podxvat
    Voice(21);          // "Зажигание"
    digitalWrite(Podxvat, HIGH);      // включаем зажигание, и выжидаем 3 сек.
    delay (3000);        // пауза для анализа ЭБУ авто

    // если есть разрешение на автозапуск то включаем реле стартера на время StTime
    if (digitalRead(RazrAutoZap) == HIGH && digitalRead(Podxvat) == HIGH && digitalRead(Parking) == HIGH) {  // если разрешен автозапусск(RazrAutoZap) == HIGH)
      Voice(19);  // "Стартер"
      StartTimeON = millis();
      digitalWrite(Start, HIGH);         // включаем реле стартера
    }
    delay (10);
    while (millis() < (StartTimeON + StTime) && digitalRead(RazrAutoZap) == HIGH);  //закончилось время стартера и RazrAutoZap == HIGH
    digitalWrite(Start, LOW);  // отключаем стартер
    delay (4000);   //ждем 4 сек, что бы двигатель стабильно заработал

    // включился подхват зажигания, на паркинге, тахометр HIGH и есть разрешение запуска
    if (digitalRead(Podxvat)  == HIGH && digitalRead(Parking) == HIGH && digitalRead(Tahometr) == HIGH && digitalRead(RazrAutoZap) == HIGH) {
      Voice(2);                 //"Двигатель запущен, Двигатель запущен"
      heating = true;
      delay (4000);
      digitalWrite(ACC, HIGH);  // включаем реле выхода для вторичных приборов авто, через 4 сек
      break;                    // считаем старт успешным, выходим из цикла запуска двигателя
    }

    Voice(3);                  // "повторный запуск" если авто не запустилось
    StTime = StTime + 250;     // увеличиваем время следующего старта на 0,25 сек.
    heatingstop(0);            // отключаем все реле без обнуления таймера
    delay(10000);              // пауза между попытками запуска
  }
  if (heating == false) {
    Voice(24), Timer = 0;    // не запустилась! попробуйте еще раз!/ обнуляем таймер если запуска не произошло
    k2 = 0;       //обнуление счетчика к2 и state9, что бы 3 раза моргнуть поворотником
    state9 = 0;
  }
  delay(3000), SIM800.println("ATH0"); // вешаем трубку (для SIM800)
}

//------ программа остановки прогрева двигателя -------------
void heatingstop (bool reset_timer) {
  digitalWrite(ACC, LOW), delay (2000);
  digitalWrite(Podxvat, LOW), delay (10);
  heating = false, delay(1000);
  if (reset_timer == true) Timer = 0;  // обнуляем таймер если авто прогревалось
  timer4 = 0;    // сбрасываем таймер пидстопа
}

//---  замеряем напряжение на батарее и переводим значения в вольты ----------
float VoltRead1() {
  float ADCC1 = analogRead(BAT_Pin);
  ADCC1 = ADCC1 / m1 ;
  if (ADCC1 < V_min1) V_min1 = ADCC1;     // переводим данные ацп1 в вольты
  return (ADCC1);
}

float VoltRead2() {
  float ADCC2 = analogRead(Pusk_Sig);
  ADCC2 = ADCC2 / m2 ;
  if (ADCC2 < V_min2) V_min2 = ADCC2;     // переводим данные ацп2 в вольты
  return (ADCC2);
}

//проговаривание голосовых треков из SIM800
void Voice(int Track) {
  SIM800.print("AT+CREC=4,\"C:\\User\\"), SIM800.print(Track), SIM800.println(".amr\",0,95");
}

//моргать поворотником в режиме прогрева или пидстопа
void Blinker() {
  unsigned long currentMillis3 = millis();   // текущее время в миллисекундах, выясняем не настал ли момент сменить состояние светодиода
  if ((Blinks10state10 == HIGH) && (currentMillis3 - previousMillis3 >= OnTime10)) // если светодиод включен и светится больше чем надо
  {
    Blinks10state10 = LOW;                   // выключаем
    previousMillis3 = currentMillis3;   // запоминаем момент времени
    digitalWrite(Blinks10, Blinks10state10);   // реализуем новое состояние
  }
  else if ((Blinks10state10 == LOW) && (currentMillis3 - previousMillis3 >= OffTime10) && !state10)    //здесь проверяем 3 пунктом это состояние
  {
    Blinks10state10 = HIGH;                   // включаем
    previousMillis3 = currentMillis3 ;   // запоминаем момент времени
    digitalWrite(Blinks10, Blinks10state10);    // реализуем новое состояние
  }
}

//--Выполняем моргание реле дальнего света и клаксона, при блокировке мотора-------
void Gygok() {
  unsigned long currentMillis4 = millis();   // текущее время в миллисекундах, выясняем не настал ли момент сменить состояние светодиода
  if ((Klaxonstate11 == HIGH) && (currentMillis4 - previousMillis4 >= OnTime11)) // если светодиод включен и светится больше чем надо
  {
    Klaxonstate11 = LOW;                   // выключаем
    previousMillis4 = currentMillis4;   // запоминаем момент времени
    digitalWrite(Klaxon, Klaxonstate11);   // реализуем новое состояние
  }
  else if ((Klaxonstate11 == LOW) && (currentMillis4 - previousMillis4 >= OffTime11) && !state11)    //здесь проверяем состояние
  {
    Klaxonstate11 = HIGH;                   // включаем
    previousMillis4 = currentMillis4 ;   // запоминаем момент времени
    digitalWrite(Klaxon, Klaxonstate11);    // реализуем новое состояние
  }
}

 

frequency_meter.ino

#define Out_LED 4                      //Вывод счетчика 
#define Taho 3                         //Вход сигнал тахометра
#define ObrabotkaTaho  5               //Выход обработанного счетчика, задержка 0.5 сек

volatile unsigned int RPM_ON_LED = 200;          //Включать Led при достижении оборотов, об/мин
volatile unsigned long microcod = 0;             //Предыдущее значение таймера
volatile unsigned int rpm2 = 0;                  //Обороты коленвала, об/мин
volatile unsigned int rpm2OFF = 0;               //Обороты коленвала для отключения коротких каналов, об/мин
volatile byte sr = 0;                            //счетчик обнуления
volatile boolean st = false;                     //триггер

unsigned long previousMillis = 0;  // Зададим начальное значение для счетчика millis
unsigned long PsoTime5 = 0;        // для таймера в цикле отработки задержки сигнала счетчика
bool timer5 = 0;                   // флаг включен ли таймер, 0 - выключен, 1 - включен
uint16_t TimePush5 = 3000;          // Время срабатывания вывода для отработки задержки сигнала счетчика

void setup() {
  Serial.begin(9600);   // для контроля в Serial, считает или нет, можно закомментировать
  pinMode(Out_LED, OUTPUT);
  pinMode(Taho, INPUT);
  pinMode(ObrabotkaTaho, OUTPUT);

  //  При включении зажигания выключить LED
  digitalWrite(Out_LED, LOW);        //По умолчанию LED выключено
  //Устанавливаем вход тахометра
  digitalWrite(Taho, HIGH);         //Внутренняя подтяжка
  digitalWrite(ObrabotkaTaho, LOW);        //По умолчанию выключено

  detachInterrupt(0);            // отключаем обработку внешнего прерывания на Pin2
  attachInterrupt(1, RPM2, FALLING); //Устанавливаем считывание оборотов через прерывание, при смене значения на порту с HIGH на LOW

}
void loop() {
 
  //---- обработка задержки сигнала счетчика тахометра  -----------
  // при старте в авто в линии тахометра мусор, его отфильтровываем
  if (!timer5 && digitalRead(Out_LED) == HIGH) {
    timer5 = 1;  // если таймер выключен и ObrabotkaTaho == HIGH запускаем таймер
    PsoTime5 = millis();
  }
  if (digitalRead(Out_LED) == LOW) {
    timer5 = 0;  // если ObrabotkaTaho == LOW молчит выключаем таймер, сбрасываем флаг "звонок выполнен"
    digitalWrite(ObrabotkaTaho,  LOW);
  }
  if (timer5 && millis() - PsoTime5 > TimePush5)  // если таймер был включен и кончился,
  {
    timer5 = 0;                                   // выключаем таймер и
    digitalWrite(ObrabotkaTaho,  HIGH);              // если флаг выполнен в фальсе то
  }

  Serial.println(rpm2);   // для контроля в Serial, считает или нет, можно закомментировать
  if (sr != 0) {
    sr--;
  } else {
    rpm2 = 0;
  }
  rpm2OFF = rpm2 + 4000;  // время подсчета пропусков оборотов +1--+100, чем больше, тем точнеев подсчет

  //Если текущие обороты больше или равны заданным, с учетом времени реакции, то включаем LED.
  //В противном случае выключаем LED
  if (rpm2 >= RPM_ON_LED) {         //Включать Led при достижении оборотов, об/мин
    digitalWrite(Out_LED, HIGH);
  } else if (rpm2 < RPM_ON_LED) {   //Выключать Led при достижении оборотов, об/мин
    digitalWrite(Out_LED, LOW);
  }
  delay(50);
}
//Считывание оборотов
void RPM2() {
  if (!st) {
    microcod = millis();
  } else {
    rpm2 = (1000 / (millis() - microcod)) * 60 / 2; //об/мин. импульсы 1 раза на один оборот
  }                                             //(если 2 импульса за оборот * 60 / 2; смотреть в мониторе порта).
  st = !st;
  sr = 20;     // счетчик обнуления, чем больше, тем больше время сброса LED в LOW, 1000~~15сек
}

Архивные файлы с печатной платой, по адресу; https://disk.yandex.ru/d/0Okfvvu34RQPVw

vic163-163
Offline
Зарегистрирован: 06.03.2018
//ACP_pin.ino
//Настройка АЦП канала

#include <SoftwareSerial.h>
#define BAT_Pin        A6          // вход на батарею, через делитель напряжения 47kom / 10 кОм

float Vbat1, Vbat1Start, V_min1 ;  // переменная хранящая напряжение бортовой сети1
// делитель для перевода АЦП1 в вольты для резистров 47/10kOm, подбор напряжения индикации АЦП в мониторе порта.
// больше значение меньше напряжение в мониторе порта
float m1 = 36.45;                  // уменьшаю увеличивается значение напряжения питания
unsigned long Time1 = 0;           // время выполнения detection1

void setup() {
  Serial.begin(9600);             //скорость порта            
  detachInterrupt(0);             // отключаем обработку внешнего прерывания на Pin2
  detachInterrupt(1);             // отключаем обработку внешнего прерывания на Pin3
}

void loop() {
  if (millis() > Time1 + 500) Time1 = millis(), detection1();      // выполняем функцию detection1 () каждые 0,5 сек
}

void detection1() {        // условия проверяемые каждые 10 сек
  Vbat1 = VoltRead1();     // замеряем напряжение на батарее, на A6
  Serial.println("");  
}

//---  замеряем напряжение на батарее и переводим значения в вольты ----------
float VoltRead1() {
  float ADCC1 = analogRead(BAT_Pin);
  ADCC1 = ADCC1 / m1 ;
  Serial.print(ADCC1);                // ОТКЛЮЧИТЬ ПОСЛЕ НАСТРОЙКИ АЦП
  if (ADCC1 < V_min1) V_min1 = ADCC1;     // переводим данные ацп1 в вольты
  return (ADCC1);
}

 

 

ACP_pin

vic163-163
Offline
Зарегистрирован: 06.03.2018

Programs

// Programs.ino
//  рисунок sxema_34
// -----КОМАНДЫ DTMF------
// "45" обратный звонок
// "03"  старт
// "30"  стоп
// "56"  отключение контроля дверей
// "65"  включение контроля дверей
// "89"  блокировка двигателя
// "98"  снятие блокировки двигателя
// -----Voice -- голосовые сообщения------
// ------1   откываю двери!...
// 2   двигатель запущен,  двигатель запущен!...
// 3   оп, повторный запуск!...
// ----- 4   закрываю двери!...
// 5   уже, прогреваюсь!...
// 6   стоп прогрева!...
// 7   все поняла, завожу!...
// 8   двигатель блокирован, двигатель блокирован...
// 9   продолжайте движение!...
// 10  оп, двигатель уже запущен!...
// 11  контроль связи!...
// 12  низкое напряжение!...
// 13  короткие гудки
// 14  нарушение охраны!...
// 15  открыта! дверь! авто!
// 16  нажат тормоз!
// 17  отключен! контроль! двери!
// 18  включен! контроль! двери!
// 19  Стартер+
// 20  не в режиме запуска+
// 21  Зажигание!+
// 22  SMS
// 23  Включено! Зажигание!
// 24  не запустилась! попробуйте еще раз!...
// 25  авто! в режиме! пидстопа!

#include <SoftwareSerial.h>
SoftwareSerial SIM800(7, 6);       // для новых плат начиная с версии RX,TX

#define Podxvat        12          // выход на реле зажигания Podxvat + реле датчик детонации-иммобилайзер
#define Start          10          // выход на реле стартера
#define Block          13          // выход на реле блокировки двигателя с клаксоном
#define ObrabotkaCall  A5          // вывод для отработки обратного звонка
#define Klaxon         8           // выход на реле дальнего света и клаксона 
#define BAT_Pin        A6          // вход на батарею, через делитель напряжения 47kom / 10 кОм
#define Parking        A1          // вход на датчик паркинга или ручник, HIGH на паркинге(программно)
#define StopPin        A2          // вход на концевик педали тормоза, HIGH
#define Ignition       A3          // вход на провод от замка зажигания, HIGH
#define Alarm          2           // вход для звонка при срабатывания сигналки
#define Door           3           // вход для звонка при срабатывании дверей, на массу, LOW
#define ObrabotkaDveri A4          // вывод для обработки открытой двери
#define ZapretDoor     A0          // вывод для обработки, отключения контроля открытия двери
#define Tahometr       5           // вывод Tahometr, HIGH  есть подсчет импульсов от тахометра
#define RazrAutoZap    11          // вывод для обработки разрешения на авто запуск, HIGH
#define CentrZamok     4           // вход сигнала от центр замка при закрытии дверей, на массу, LOW
#define ACC            9           // выход для вторичных приборов авто, HIGH
#define Pusk_Sig       A7          // вход от авто сигнализации на запуск
#define Blinks9        1           // выход 3 раза моргнуть поворотником, не в режиме запуска
#define Blinks10       0           // выход моргать поворотником в режиме прогрева

//------- настройки переменных --------
String pin = "";                   // строковая переменная набираемого пинкода
bool ring = false;                 // флаг момента снятия трубки
float Vbat1, V_min1 ;              // переменные хранящие напряжение бортовой сети1
float m1 = 36.88;                  // делитель для перевода АЦП1 в вольты для резистров 47/10kOm, подбор напряжения индикации АЦП в мониторе порта.
float Vbat2, V_min2 ;              // переменная хранящая напряжение бортовой сети2
float m2 = 100.00;                 // делитель для перевода АЦП2 в вольты
unsigned long Time1 = 0;           // время выполнения detection1
unsigned long Time2 = 0;           // время выполнения detection2
unsigned long StartTimeON = 0;     // время работы стартера
unsigned long previousMillis = 0;  // Зададим начальное значение для счетчика millis
int Timer = 0;                     // таймер времени прогрева двигателя по умолчанию = 0
bool heating = false;              // переменная состояния режим прогрева двигателя
int count = 0;                     // для счетчиков запуска

unsigned long PsoTime4 = 0;        // для таймера в цикле отработки временного пидстопа
bool timer4 = 0;                   // флаг включен ли таймер, 0 - выключен, 1 - включен
uint32_t TimePush4 = 600000;       // Время срабатывания  600000 мсек.= 10 мин

unsigned long PsoTime5 = 0;        // для таймера в цикле отработки обратного звонка
bool timer5 = 0;                   // флаг включен ли таймер, 0 - выключен, 1 - включен
uint16_t TimePush5 = 500;         // Время срабатывания вывод для отработки обратного звонка
bool call_is_made5 = false;        // флаг "звонок выполнен" (в цикле отработки обратного звонка)

unsigned long PsoTime6 = 0;        // для таймера в цикле срабатывания сигналки
bool timer6 = 0;                   // флаг включен ли таймер
uint16_t TimePush6 = 2500;         // Время срабатывания сигналки
bool call_is_made6 = false;        // флаг "звонок выполнен" (в цикле срабатывания сигналки)

unsigned long PsoTime7 = 0;        // для таймера в цикле срабатывания двери
bool timer7 = 0;                   // флаг включен ли таймер
uint16_t TimePush7 = 500;          // Время срабатывания двери
bool call_is_made7 = false;        // флаг "выполнения" (в цикле срабатывания двери)

unsigned long PsoTime8 = 0;        // для таймера в цикле включения опции обработки для срабатыванияобратных звонков сигналки и двери
bool timer8 = 0;                   // флаг включен ли таймер
uint16_t TimePush8 = 10;           // Время включения опции обработки для срабатывания двери
bool call_is_made8 = false;        // флаг "выполнения" (в цикле включения опции обработки для срабатывания двери)

int k2 = 0;                        // для счетчика последний момент времени, когда состояние светодиода изменялось
unsigned long previousMillis2 = 0;
long OnTime9 = 500;                // длительность свечения светодиода (в миллисекундах)
long OffTime9 = 700;               // светодиод не горит (в миллисекундах)
bool state9 = 0;                   //
int Blinks9state9 = LOW;           // состояние выхода, 3 раза моргнуть поворотником

unsigned long previousMillis3 = 0;
long OnTime10 = 500;               // длительность свечения светодиода (в миллисекундах)
long OffTime10 = 3000;             // светодиод не горит (в миллисекундах)
bool state10 = 0;                  //
int Blinks10state10 = LOW;         // состояние выхода, моргать поворотником

unsigned long previousMillis4 = 0;     // Зададим начальное значение для счетчика millis для Gygok()
long OnTime11 = 500;                   // длительность свечения светодиода (в миллисекундах)
long OffTime11 = 500;                   // светодиод не горит (в миллисекундах)
bool state11 = 0;                       //
int Klaxonstate11 = LOW;               // состояние выхода Klaxon

bool gabarit = false;

void setup() {
  pinMode(Podxvat, OUTPUT);
  pinMode(Start, OUTPUT);
  pinMode(Block, OUTPUT);
  pinMode(ObrabotkaCall, OUTPUT);
  pinMode(Klaxon, OUTPUT);
  //  pinMode(Parking, INPUT);
  //  pinMode(StopPin, INPUT);
  //  pinMode(Ignition, INPUT);
  pinMode(Alarm, INPUT_PULLUP);   // указываем пин на вход для с внутричипной подтяжкой к +V, для звонка при срабатывания сигналки
  pinMode(Door, INPUT_PULLUP);    // указываем пин на вход для с внутричипной подтяжкой к +V, для звонка при срабатывании двери
  pinMode(ObrabotkaDveri, OUTPUT);
  pinMode(ZapretDoor, OUTPUT);
  //  pinMode(Tahometr, INPUT);       // Tahometr HIGH есть подсчет импульсов от счетчика оборотов
  pinMode(RazrAutoZap, OUTPUT);
  pinMode(CentrZamok, INPUT_PULLUP);
  pinMode(ACC, OUTPUT);
  pinMode(Blinks9, OUTPUT);
  pinMode(Blinks10, OUTPUT);

  delay(100);
  SIM800.begin(9600);             //скорость связи с модемом
  detachInterrupt(0);             // отключаем обработку внешнего прерывания на Pin2
  detachInterrupt(1);             // отключаем обработку внешнего прерывания на Pin3
  digitalWrite(Podxvat, LOW);
  digitalWrite(Block, LOW);
  digitalWrite(ObrabotkaCall, LOW);
  digitalWrite(RazrAutoZap, LOW);
  digitalWrite(Blinks9, LOW);
  digitalWrite(Blinks10, LOW);
  //  SIM800_reset();
}

/*  ---- - Перезагрузка МОДЕМА SIM800L  ----//на некоторых модемах не работает
  void SIM800_reset() {
  delay(10000); SIM800.println("AT+CMGDA=\"DEL ALL\"");  // Удаляем все СМС чекрез 10 сек, после старта SIM модуля
  }*/

void loop() {
  if (SIM800.available())  resp_modem();                            // если что-то пришло от SIM800 в Ардуино отправляем для разбора
  if (Serial.available())  resp_serial();                           // если что-то пришло от Ардуино отправляем в SIM800
  if (millis() > Time1 + 2000) Time1 = millis(), detection1();      // выполняем функцию detection1 () каждые 2 сек
  if (millis() > Time2 + 100) Time2 = millis(), detection2();       // выполняем функцию detection2 () каждые 0,1 сек
  if (heating == true && digitalRead(StopPin) == HIGH)  heatingstop(1), delay(1000), digitalWrite(RazrAutoZap, LOW); // если нажали на педаль тормоза в режиме прогрева, сброс прогрева и RazrAutoZap
  if (heating == true && digitalRead(Podxvat) == HIGH && digitalRead(Parking) == LOW) heatingstop(1), delay(1000), digitalWrite(RazrAutoZap, LOW); // если выключили Parking в режиме прогрева, сброс прогрева и RazrAutoZap

  //----моргаем реле дальнего света и клаксона, при блокировке мотора-------------
  if (digitalRead(Block) == HIGH) Gygok();
  if (digitalRead(Block) == LOW) digitalWrite(Klaxon, LOW);

  //--- подхват зажигания Podxvat при заведнном двигателе и включенном ручнике, режим пидстопа -------
  if (digitalRead(Ignition) == HIGH && digitalRead(Parking) == HIGH && digitalRead(Tahometr) == HIGH && digitalRead(RazrAutoZap) == LOW) {
    digitalWrite(Podxvat, HIGH);
    delay(1);
    digitalWrite(ACC, HIGH);
  }
  // заглох мотор отключить подхват зажигания Podxvat
  if (digitalRead(Podxvat) == HIGH && digitalRead(Parking) ==  HIGH && digitalRead(Tahometr) == LOW) {
    delay(1);
    heatingstop(1);
    delay(1);
    timer4 = 0;
  }
  //включение разрешения автозапуска RazrAutoZap, при закрытии дверей центр. замком
  if (digitalRead(Tahometr) == HIGH && digitalRead(Podxvat) == HIGH && digitalRead(Door) == HIGH && digitalRead(CentrZamok) == LOW) {
    delay(1);
    digitalWrite(RazrAutoZap, HIGH);
    delay(1);
    heatingstop(1);
  }

  //если открыли дверь авто после постановки на авто запуск, сброс RazrAutoZap в LOW
  if (heating == false && digitalRead(RazrAutoZap) == HIGH && digitalRead(Door) == LOW) {
    delay(1);
    digitalWrite(RazrAutoZap, LOW);
  }
  //если нажали на тормоз после постановки на авто запуск, сброс RazrAutoZap в LOW
  if (digitalRead(StopPin) == HIGH && digitalRead(RazrAutoZap) == HIGH && heating == false) {
    delay(1);
    digitalWrite(RazrAutoZap, LOW);
  }

  // отключился Podxvat, отключаем АСС
  if (digitalRead(Podxvat) == LOW) {
    delay(1);
    digitalWrite(ACC, LOW);
  }

  //---- обработка времени выполнения пидстопа ---------
  if (!timer4 && digitalRead(Ignition) == HIGH && digitalRead(Parking) == HIGH && digitalRead(Tahometr) == HIGH && digitalRead(Podxvat) == HIGH && heating == false) {
    timer4 = 1;  // если условия выполнены  запускаем таймер на пидстоп
    PsoTime4 = millis();
  }
  if (digitalRead(Parking) == LOW && digitalRead(Tahometr) == HIGH && digitalRead(Podxvat) == HIGH && heating == false) {
    timer4 = 0;                // если Parking выключен выключаем таймер, сбрасываем флаг
    digitalWrite(Podxvat, LOW);
  }
  if (timer4 && millis() - PsoTime4 > TimePush4)  // если таймер был включен и кончился,
  {
    timer4 = 0;                                                  // выключаем таймер и
    digitalWrite(Podxvat, LOW); // если флаг выполнен то выключаем подхват зажигания Podxvat
  }

  // включился АСС моргать поворотником, отключился не моргаем
  if (digitalRead(ACC) == LOW) digitalWrite(Blinks10, LOW);
  if (digitalRead(ACC) == HIGH) Blinker();

  // 3 раза моргнуть поворотником, не в режиме запуска
  unsigned long currentMillis2 = millis();   // текущее время в миллисекундах, выясняем не настал ли момент сменить состояние светодиода
  // если светодиод включен и светится больше чем надо
  if ((Blinks9state9 == HIGH) && (currentMillis2 - previousMillis2 >= OnTime9))
  {
    Blinks9state9 = LOW;                   // выключаем
    previousMillis2 = currentMillis2;   // запоминаем момент времени
    digitalWrite(Blinks9, Blinks9state9);   // реализуем новое состояние
    k2++;
    if (k2 > 2 ) state9 = 1;    // если больше переводим в другое состояние
  }
  else if ((Blinks9state9 == LOW) && (currentMillis2 - previousMillis2 >= OffTime9) && !state9)    //здесь проверяем 3 пунктом это состояние
  {
    Blinks9state9 = HIGH;                   // включаем
    previousMillis2 = currentMillis2 ;   // запоминаем момент времени
    digitalWrite(Blinks9, Blinks9state9);    // реализуем новое состояние
  }

  //---- обработка обратного звонка  -----------
  if (!timer5 && digitalRead(ObrabotkaCall) == HIGH) {
    timer5 = 1;  // если таймер выключен и ObrabotkaCall == HIGH запускаем таймер
    PsoTime5 = millis();
  }
  if (digitalRead(ObrabotkaCall) == LOW) {
    timer5 = 0;  // если ObrabotkaCall == LOW молчит выключаем таймер, сбрасываем флаг "звонок выполнен"
    call_is_made5 = 0;
  }
  if (timer5 && millis() - PsoTime5 > TimePush5)  // если таймер был включен и кончился,
  {
    timer5 = 0;                                   // выключаем таймер и
    if (call_is_made5 == 0) call1();              // если флаг "звонок выполнен" в фальсе то звоним хозяину
  }

  //----------------срабатывание сигналки-----------------
  if (!timer6 && digitalRead(Alarm) == LOW) {
    timer6 = 1;  // если таймер выключен и работает колокол запускаем таймер, 2,5 сек
    PsoTime6 = millis();
  }
  if (digitalRead(Alarm) == HIGH) {
    timer6 = 0;  // если колокол молчит выключаем таймер, сбрасываем флаг "звонок выполнен"
    call_is_made6 = 0;
  }
  if (timer6 && millis() - PsoTime6 > TimePush6)        // если таймер был включен и кончился,
  {
    timer6 = 0;                                         // выключаем таймер и
    heatingstop(1);                                     // стоп прогрева
    if (call_is_made6 == 0) call2();                    // если флаг "звонок выполнен" то звоним хозяину
  }

  //----------------срабатывание дверей-----------------
  if (!timer7 && digitalRead(Door) == LOW && digitalRead(ObrabotkaDveri) == HIGH) {
    timer7 = 1;  // если таймер выключен и открыты двери запускаем таймер, 0,5 сек
    PsoTime7 = millis();
  }
  if (digitalRead(Door) == HIGH && digitalRead(ObrabotkaDveri) == HIGH) {
    timer7 = 0;  // если дверь закрыли выключаем таймер, сбрасываем флаг
    call_is_made7 = 0;
  }
  if (timer7 && millis() - PsoTime7 > TimePush7)         // если таймер был включен и кончился,
  {
    timer7 = 0;                                          // выключаем таймер и
    if (call_is_made7 == 0) call3();                     // если флаг "звонок выполнен" в фальсе то звоним хозяину
  }

  //---- запуск обработки на срабатывание открытых дверей ---------
  //---- что бы звонок проходил только, после постановки/снятия с охраны --------
  if (!timer8 && digitalRead(Alarm) == LOW && digitalRead(ZapretDoor) == LOW) {
    timer8 = 1;  // если таймер выключен и пикнул колокол запускаем таймер, 10 мсек
    PsoTime8 = millis();
  }
  if (digitalRead(Alarm) == HIGH) {
    timer8 = 0;                // если колокол молчит выключаем таймер, сбрасываем флаг
    call_is_made8 = 0;
  }
  if (timer8 && millis() - PsoTime8 > TimePush8)                  // если таймер был включен и кончился,
  {
    timer8 = 0;                                                  // выключаем таймер и
    if (call_is_made8 == 0)  digitalWrite(ObrabotkaDveri, HIGH); // если флаг выполнен в фальсе то включаем ObrabotkaDveri
  }
}

//----------------обратный звонок------------------
void call1() {
  delay(100);
  SIM800.println("AT+CPBR=1"); // считывает запись с индексом 1 телефонной книги SIM-карты
  delay(200);
  SIM800.println("ATD>1");   // позвонить на 1 номер  телефонной книги SIM-карты, читает номер с sim карты но не набирает, поэтому->
  delay(200);
  SIM800.println("ATDL");    // позвонить на последний номер
  delay(100);
  if (SIM800.find("OK"));
  while (1) {                    // ожидание ответа вызова
    SIM800.println("AT+CPAS");        // при каждой итерации опрашиваем модуль
    if (SIM800.find(":")) break;      // если :, то выходим из цикла while
    delay(100);
  }
  delay(1000);
  SIM800.print("AT+CREC=4,\"C:\\User\\"), SIM800.println("11.amr\",0,95");    //голосовое сообщение "контроль связи"
  delay(4000);
  SIM800.println("ATH0");
  call_is_made5 = 1;                // флаг "звонок выполнен" в труе
  digitalWrite(ObrabotkaCall, LOW);
}

//--------звонок при срабатывании сигналки------------
void call2() {
  delay(100);
  SIM800.println("AT+CPBR=1"); // считывает запись с индексом 1 телефонной книги SIM-карты
  delay(200);
  SIM800.println("ATD>1");   // позвонить на 1 номер  телефонной книги SIM-карты, читает номер с sim карты но не набирает, поэтому->
  delay(200);
  SIM800.println("ATDL");    // позвонить на последний номер
  delay(100);
  if (SIM800.find("OK"));
  while (1) {                    // ожидание ответа вызова
    SIM800.println("AT+CPAS");        // при каждой итерации опрашиваем модуль
    if (SIM800.find(":")) break;      // если :, то выходим из цикла while
    delay(100);
  }
  delay(1000);
  SIM800.print("AT+CREC=4,\"C:\\User\\"), SIM800.println("14.amr\",0,95");    //голосовое сообщение "нарушение охраны"
  delay(4000);
  SIM800.println("ATH0");
  call_is_made6 = 1;                // флаг "звонок выполнен" в труе
}

//----звонок при срабатывании двери-----------
void call3() {
  delay(100);
  SIM800.println("AT+CPBR=1"); // считывает запись с индексом 1 телефонной книги SIM-карты
  delay(200);
  SIM800.println("ATD>1");   // позвонить на 1 номер  телефонной книги SIM-карты, читает номер с sim карты но не набирает, поэтому->
  delay(200);
  SIM800.println("ATDL");    // позвонить на последний номер
  delay(100);
  if (SIM800.find("OK"));
  while (1) {                    // ожидание ответа вызова
    SIM800.println("AT+CPAS");        // при каждой итерации опрашиваем модуль
    if (SIM800.find(":")) break;      // если :, то выходим из цикла while
    delay(100);
  }
  delay(1000);
  SIM800.print("AT+CREC=4,\"C:\\User\\"), SIM800.println("15.amr\",0,95");    //голосовое сообщение "открыта дверь авто"
  delay(4000);
  SIM800.println("ATH0");
  call_is_made7 = 1;                // флаг "звонок выполнен" в труе
  if (digitalRead(Alarm) == HIGH) digitalWrite(ObrabotkaDveri, LOW); //сброс ObrabotkaDveri, до следующего импульса с сигналки
}

// -------  ТРАНСЛИРУЕМ КОМАНДЫ из ПОРТА В МОДЕМ  ----------------
void resp_serial () {
  String at = "";
  int k = 0;
  while (Serial.available()) k = Serial.read(), at += char(k), delay(1);
  SIM800.println(at), at = "";
}

//------  AНАЛИЗИРУЕМ БУФЕР ВИРТУАЛЬНОГО ПОРТА МОДЕМА -------------
void resp_modem () {
  String at = "";           // набиваем в переменную at
  int k = 0;
  while (SIM800.available()) k = SIM800.read(), at += char(k), delay(1);
  Serial.println(at);

  if (at.indexOf("RING")  > -1) {      // входящий звонок
    delay(200), SIM800.println("ATA"), ring = true;
  }
  else if (at.indexOf("+DTMF: ")  > -1)        {
    String key = at.substring(at.indexOf("") + 9, at.indexOf("") + 10);
    pin = pin + key;
    if (pin.indexOf("*") > -1 ) pin = "";
  }
  else if (at.indexOf("NO CARRIER") > -1 ) {
    SIM800.println("AT+CLIP=1;+DDET=1"); // Активируем АОН и декодер DTMF
  }
  at = "";            // Возвращаем ответ можема в монитор порта , очищаем переменную

  if (pin.indexOf("45") > -1 ) {
    pin = "", Voice(11), delay (3000), SIM800.println("ATH0"), delay (100), digitalWrite(ObrabotkaCall, HIGH);   //обратный звонок
  }

  else if (pin.indexOf("89") > -1 ) {
    pin = "", Voice(8), digitalWrite(Block, HIGH), heatingstop(1); // блокировка двигателя "двигатель блокирован", без сброса звонка
  }

  else if (pin.indexOf("98") > -1 ) {
    pin = "", Voice(9), digitalWrite(Block, LOW), delay (3000), SIM800.println("ATH0"); //снятие сблокировки двигателя "продолжайте движение"
  }

  else if (pin.indexOf("03") > -1 ) {           // команда на пуск запуска
    pin = "";
    if (digitalRead(Block) == HIGH)  // если на блокировке
    {
      Voice(8), delay (4000), SIM800.println("ATH0");  // "двигатель блокирован"
    }
    else if (digitalRead(Podxvat) == LOW && digitalRead(Ignition) == LOW && digitalRead(StopPin) == LOW && digitalRead(RazrAutoZap) == HIGH && digitalRead(Block) == LOW)
    {
      Voice(7), delay (2000), enginestart(4); // "все поняла завожу" // запуск (4) попытки
    }
    else if (heating == true)   // если на прогреве
    {
      Voice(5), delay (3000), SIM800.println("ATH0");   // "уже, прогреваюсь!..."
    }
    else if (digitalRead(RazrAutoZap) == LOW)        // если нет разрешения автозапуска
    {
      Voice(20), delay (3000), SIM800.println("ATH0");   // "не врежиме запуска"
      delay (1);
      k2 = 0;       //обнуление счетчика к2 и state9, что бы 3 раза моргнуть поворотником
      state9 = 0;
    }
    else if (digitalRead(Ignition) == HIGH && digitalRead(Tahometr) == HIGH && digitalRead(Block) == LOW)  // если двигатель запущен ключем
    {
      Voice(10), delay (3000), SIM800.println("ATH0");   // "оп, двигатель уже запущен!..."
    }
  }

  else if (pin.indexOf("30") > -1 ) {  // команда стоп прогрева
    pin = "";
    if (heating == true)
    {
      Voice(6), delay(2000), heatingstop(1); // (стоп прогрева)
      SIM800.println("ATH0");
    }
    else if (heating == false)
    {
      false;
      SIM800.println("ATH0");
    }
  }

  else if (pin.indexOf("56") > -1 ) {
    pin = "", Voice(17), digitalWrite(ZapretDoor, HIGH), delay (3000), SIM800.println("ATH0"); // "отключено! срабатывание! двери!"
  }

  else if (pin.indexOf("65") > -1 ) {
    pin = "", Voice(18), digitalWrite(ZapretDoor, LOW), delay (3000), SIM800.println("ATH0"); // "включено! срабатывание! двери!"
  }

  //------голосовые сообщения при входящем звонке-----------
  if (ring == true) {
    ring = false, delay (2000), pin = ""; // обнуляем пин

    if (digitalRead(Alarm) == LOW && digitalRead(Block) == LOW) {    //сработала сигнализация на авто
      Voice(14);    // "нарушение охраны"
    }
    else if (digitalRead(Block) == HIGH) { //авто находится в режиме блокирови Voice(8)
      Voice(8);    // "двигатель блокирован"
    }
    else if (digitalRead(Podxvat) == LOW && digitalRead(Ignition) == HIGH && digitalRead(Block) == LOW && digitalRead(Tahometr) == HIGH && heating == false) {  //включено зажигание, подхват зажигания и нет прогрева от arduino
      Voice(10);                          //   Voice(10) "двигатель уже запущен"
    }
    else if (digitalRead(Podxvat) == HIGH && digitalRead(Block) == LOW && digitalRead(Tahometr) == HIGH && heating == false) {  //включено зажигание, подхват зажигания и нет прогрева от arduino
      Voice(25);                          // Voice(25) "авто! в режиме! пидстопа!"
    }
    else if (digitalRead(Podxvat) == LOW && digitalRead(Ignition) == HIGH && digitalRead(Block) == LOW && digitalRead(Tahometr) == LOW && heating == false) {
      Voice(23);          // "включено зажигание"
    }
    else if (Vbat1 < 10.5) {               // "низкое напряжение"
      Voice(12);
    }
    else if (digitalRead(Podxvat) == LOW && digitalRead(Ignition) == LOW && digitalRead(Tahometr) == LOW && digitalRead(Block) == LOW) {
      Voice(22);       //при входящем звонке тональный гудок 22
    }
    else if (heating == true) {
      Voice(5);          // "уже прогреваюсь"
    }
  }
}

void detection1() {        // условия проверяемые каждые 2 сек
  Vbat1 = VoltRead1();     // замеряем напряжение на батарее, на A6
  if (Timer > 0) Timer--;  //если кол-во попыток запуска >0, запускаем таймер
  if (heating == true && Timer < 1) heatingstop(0);  // остановка прогрева если закончился таймер
  if (heating == true && Vbat1 < 10.00) heatingstop(1);  // остановка прогрева если напряжение просело ниже 10 вольт
}

void detection2() {         // условия проверяемые каждые 0,1 сек
  Vbat2 = VoltRead2();      // замеряем напряжение на A7
  if (Vbat2 >= 5.00 && digitalRead(RazrAutoZap) == HIGH && digitalRead(Ignition) == LOW && digitalRead(Podxvat) == LOW) enginestart(4); // запуск с пульта сигналки
  else if (Vbat2 >= 5.00 && digitalRead(RazrAutoZap) == LOW) {
    k2 = 0;       //обнуление счетчика к2 и state9, что бы 3 раза моргнуть поворотником
    state9 = 0;
  }
}

//  ----  программа запуска двигателя  -----------
void enginestart(int Attempts) {                 // () заданное количество попыток запуска
  int StTime = constrain(StTime, 750, 3000);    // ограничиваем диапазон работы стартера от 0,75 до 6 сек
  Timer = constrain(Timer, 300, 300);          // ограничиваем таймер - Timer в значениях от 10 до 10 минут
  count = 0;                                      // переменная хранящая число совершенных попыток запуска

  // если напряжение АКБ больше 10 вольт, зажигание выключено, счетчик заданного числа попыток ( enginestart(4)
  while (Vbat1 > 10.00 && digitalRead(Ignition) == LOW && count < Attempts) {
    count++;
    delay (1000);                 // пауза на включение Podxvat
    Voice(21);          // "Зажигание"
    digitalWrite(Podxvat, HIGH);      // включаем зажигание, и выжидаем 3 сек.
    delay (3000);        // пауза для анализа ЭБУ авто

    // если есть разрешение на автозапуск то включаем реле стартера на время StTime
    if (digitalRead(RazrAutoZap) == HIGH && digitalRead(Podxvat) == HIGH && digitalRead(Parking) == HIGH) {  // если разрешен автозапусск(RazrAutoZap) == HIGH)
      Voice(19);  // "Стартер"
      StartTimeON = millis();
      digitalWrite(Start, HIGH);         // включаем реле стартера
    }
    delay (10);
    while (millis() < (StartTimeON + StTime) && digitalRead(RazrAutoZap) == HIGH);  //закончилось время стартера и RazrAutoZap == HIGH
    digitalWrite(Start, LOW);  // отключаем стартер
    delay (4000);   //ждем 4 сек, что бы двигатель стабильно заработал

    // включился подхват зажигания, на паркинге, тахометр HIGH и есть разрешение запуска
    if (digitalRead(Podxvat)  == HIGH && digitalRead(Parking) == HIGH && digitalRead(Tahometr) == HIGH && digitalRead(RazrAutoZap) == HIGH) {
      Voice(2);                 //"Двигатель запущен, Двигатель запущен"
      heating = true;
      delay (4000);
      digitalWrite(ACC, HIGH);  // включаем реле выхода для вторичных приборов авто, через 4 сек
      break;                    // считаем старт успешным, выходим из цикла запуска двигателя
    }

    Voice(3);                  // "повторный запуск" если авто не запустилось
    StTime = StTime + 250;     // увеличиваем время следующего старта на 0,25 сек.
    heatingstop(0);            // отключаем все реле без обнуления таймера
    delay(10000);              // пауза между попытками запуска
  }
  if (heating == false) {
    Voice(24), Timer = 0;    // не запустилась! попробуйте еще раз!/ обнуляем таймер если запуска не произошло
    k2 = 0;       //обнуление счетчика к2 и state9, что бы 3 раза моргнуть поворотником
    state9 = 0;
  }
  delay(3000), SIM800.println("ATH0"); // вешаем трубку (для SIM800)
}

//------ программа остановки прогрева двигателя -------------
void heatingstop (bool reset_timer) {
  digitalWrite(ACC, LOW), delay (2000);
  digitalWrite(Podxvat, LOW), delay (10);
  heating = false, delay(1000);
  if (reset_timer == true) Timer = 0;  // обнуляем таймер если авто прогревалось
  timer4 = 0;    // сбрасываем таймер пидстопа
}

//---  замеряем напряжение на батарее и переводим значения в вольты ----------
float VoltRead1() {
  float ADCC1 = analogRead(BAT_Pin);
  ADCC1 = ADCC1 / m1 ;
  if (ADCC1 < V_min1) V_min1 = ADCC1;     // переводим данные ацп1 в вольты
  return (ADCC1);
}

float VoltRead2() {
  float ADCC2 = analogRead(Pusk_Sig);
  ADCC2 = ADCC2 / m2 ;
  if (ADCC2 < V_min2) V_min2 = ADCC2;     // переводим данные ацп2 в вольты
  return (ADCC2);
}

//проговаривание голосовых треков из SIM800
void Voice(int Track) {
  SIM800.print("AT+CREC=4,\"C:\\User\\"), SIM800.print(Track), SIM800.println(".amr\",0,95");
}

//моргать поворотником в режиме прогрева или пидстопа
void Blinker() {
  unsigned long currentMillis3 = millis();   // текущее время в миллисекундах, выясняем не настал ли момент сменить состояние светодиода
  if ((Blinks10state10 == HIGH) && (currentMillis3 - previousMillis3 >= OnTime10)) // если светодиод включен и светится больше чем надо
  {
    Blinks10state10 = LOW;                   // выключаем
    previousMillis3 = currentMillis3;   // запоминаем момент времени
    digitalWrite(Blinks10, Blinks10state10);   // реализуем новое состояние
  }
  else if ((Blinks10state10 == LOW) && (currentMillis3 - previousMillis3 >= OffTime10) && !state10)    //здесь проверяем 3 пунктом это состояние
  {
    Blinks10state10 = HIGH;                   // включаем
    previousMillis3 = currentMillis3 ;   // запоминаем момент времени
    digitalWrite(Blinks10, Blinks10state10);    // реализуем новое состояние
  }
}

//--Выполняем моргание реле дальнего света и клаксона, при блокировке мотора-------
void Gygok() {
  unsigned long currentMillis4 = millis();   // текущее время в миллисекундах, выясняем не настал ли момент сменить состояние светодиода
  if ((Klaxonstate11 == HIGH) && (currentMillis4 - previousMillis4 >= OnTime11)) // если светодиод включен и светится больше чем надо
  {
    Klaxonstate11 = LOW;                   // выключаем
    previousMillis4 = currentMillis4;   // запоминаем момент времени
    digitalWrite(Klaxon, Klaxonstate11);   // реализуем новое состояние
  }
  else if ((Klaxonstate11 == LOW) && (currentMillis4 - previousMillis4 >= OffTime11) && !state11)    //здесь проверяем состояние
  {
    Klaxonstate11 = HIGH;                   // включаем
    previousMillis4 = currentMillis4 ;   // запоминаем момент времени
    digitalWrite(Klaxon, Klaxonstate11);    // реализуем новое состояние
  }
}

 

vic163-163
Offline
Зарегистрирован: 06.03.2018

frequency_meter

 

//frequency_meter.ino
//тахометр
#define Out_LED 4                      //Вывод счетчика 
#define Taho 3                         //Вход сигнал тахометра
#define ObrabotkaTaho  5               //Выход обработанного счетчика, задержка 0.5 сек

volatile unsigned int RPM_ON_LED = 200;          //Включать Led при достижении оборотов, об/мин
volatile unsigned long microcod = 0;             //Предыдущее значение таймера
volatile unsigned int rpm2 = 0;                  //Обороты коленвала, об/мин
volatile unsigned int rpm2OFF = 0;               //Обороты коленвала для отключения коротких каналов, об/мин
volatile byte sr = 0;                            //счетчик обнуления
volatile boolean st = false;                     //триггер

unsigned long previousMillis = 0;  // Зададим начальное значение для счетчика millis
unsigned long PsoTime5 = 0;        // для таймера в цикле отработки задержки сигнала счетчика
bool timer5 = 0;                   // флаг включен ли таймер, 0 - выключен, 1 - включен
uint16_t TimePush5 = 3000;          // Время срабатывания вывода для отработки задержки сигнала счетчика

void setup() {
  Serial.begin(9600);   // для контроля в Serial, считает или нет, можно закомментировать
  pinMode(Out_LED, OUTPUT);
  pinMode(Taho, INPUT);
  pinMode(ObrabotkaTaho, OUTPUT);

  //  При включении зажигания выключить LED
  digitalWrite(Out_LED, LOW);        //По умолчанию LED выключено
  //Устанавливаем вход тахометра
  digitalWrite(Taho, HIGH);         //Внутренняя подтяжка
  digitalWrite(ObrabotkaTaho, LOW);        //По умолчанию выключено

  detachInterrupt(0);            // отключаем обработку внешнего прерывания на Pin2
  attachInterrupt(1, RPM2, FALLING); //Устанавливаем считывание оборотов через прерывание, при смене значения на порту с HIGH на LOW

}
void loop() {
 
  //---- обработка задержки сигнала счетчика тахометра  -----------
  // при старте в авто в линии тахометра мусор, его отфильтровываем
  if (!timer5 && digitalRead(Out_LED) == HIGH) {
    timer5 = 1;  // если таймер выключен и ObrabotkaTaho == HIGH запускаем таймер
    PsoTime5 = millis();
  }
  if (digitalRead(Out_LED) == LOW) {
    timer5 = 0;  // если ObrabotkaTaho == LOW молчит выключаем таймер, сбрасываем флаг "звонок выполнен"
    digitalWrite(ObrabotkaTaho,  LOW);
  }
  if (timer5 && millis() - PsoTime5 > TimePush5)  // если таймер был включен и кончился,
  {
    timer5 = 0;                                   // выключаем таймер и
    digitalWrite(ObrabotkaTaho,  HIGH);              // если флаг выполнен в фальсе то
  }

  Serial.println(rpm2);   // для контроля в Serial, считает или нет, можно закомментировать
  if (sr != 0) {
    sr--;
  } else {
    rpm2 = 0;
  }
  rpm2OFF = rpm2 + 4000;  // время подсчета пропусков оборотов +1--+100, чем больше, тем точнеев подсчет

  //Если текущие обороты больше или равны заданным, с учетом времени реакции, то включаем LED.
  //В противном случае выключаем LED
  if (rpm2 >= RPM_ON_LED) {         //Включать Led при достижении оборотов, об/мин
    digitalWrite(Out_LED, HIGH);
  } else if (rpm2 < RPM_ON_LED) {   //Выключать Led при достижении оборотов, об/мин
    digitalWrite(Out_LED, LOW);
  }
  delay(50);
}
//Считывание оборотов
void RPM2() {
  if (!st) {
    microcod = millis();
  } else {
    rpm2 = (1000 / (millis() - microcod)) * 60 / 2; //об/мин. импульсы 1 раза на один оборот
  }                                             //(если 2 импульса за оборот * 60 / 2; смотреть в мониторе порта).
  st = !st;
  sr = 20;     // счетчик обнуления, чем больше, тем больше время сброса LED в LOW, 1000~~15сек
}

 

vic163-163
Offline
Зарегистрирован: 06.03.2018

Как здесь сохранить архив со всеми файлами, что бы не хранить на стороннем ресурсе, что то не найду как.

На яндексе файлы могут не долго пролежать, подчищаю иногда диск.

Спасибо.

 

b707
Offline
Зарегистрирован: 26.05.2017

vic163-163 пишет:

Как здесь сохранить архив со всеми файлами


никак
А оно надо? Уверены, что стоит выкладывать эту полурабочую поделку?
код с кучей делеев, с таймерами, которые заглючат от первого же переполнения ?

MaksVV
Offline
Зарегистрирован: 06.08.2015

и while(1) вообще гуд. На кпп механику такую поделку ставить нельзя. Уедет  

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

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

b707
Offline
Зарегистрирован: 26.05.2017

Почему-то всех новичков тянет на ардуину именно сигналку запилить...

v258
Offline
Зарегистрирован: 25.05.2020

b707 пишет:

Почему-то всех новичков тянет на ардуину именно сигналку запилить...

Неправда. Меня тянуло сделать кнопку старт/стоп. Слава богу вовремя остановился, решил обойтись часами )))