Блок GSM автозапуска для сигнализации SCHER-KHAN

  • Цена: $1.98
  • Коротенький обзор модуля gsm связи для ардуино и устройство блока автозапуска на его основе.

    При относительно низкой цене (всего 2$) данный модуль имеет большой функционал, достаточный для большинства бытовых самоделок.

    Модуль

    Функционал модуля довольно широк — взаимодействие с устройствами с помощью АТ — команд, подключение микрофона и колонок, совершение звонков, прием и отправка SMS и USSD-запросов, спящий режим модуля — погружение и пробуждение, распознавание DTMF, определение приблизительных координат, FM-радио, прием и отправка данных по GPRS и т. д.

    На плате расположены необходимые выводы

    Блок GSM автозапуска для сигнализации SCHER-KHAN

    Питание модуля рассчитано на литиевые аккумуляторы и лежит в пределах 3.4-4.5 В, рекомендованное 4 В. При питании от другого источника требуется обеспечить силу тока в 2А без просадок, иначе он просто не сможет зарегистрироваться в сети.

    Взаимодействие с модулем осуществляется по интерфейсу UART (Serial) при помощи специальных AT-команд. Линии данных рассчитаны на напряжение от 2,1 до 3,1В, при работе с ардуино входящую линию необходимо пропустить через делитель напряжения, чтобы привести к требуемому диапазону, исходящую с напряжением 2,8В ардуино воспринимает нормально и делитель не требуется.

    При первом включении светодиод на плате начинает часто, равномерно мигать, что означает что сеть еще не найдена. При успешной регистрации в сети, светодиод начинает мигать редко, примерно раз в секунду или две.

    Полный список АТ команд можно найти в мануале по командам

    Более подробную информацию по модулю можно получить из даташита

    Есть еще сайт с подробнейшим описанием модуля и примерами работы с ним, с которого я и взял всю информацию и код в основной своей массе взят оттуда.

    Блок

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

    Выхода 2:

    заводить по таймеру — не удобно, потому что выхожу в разное время.

    поменять сигнализацию на ту, которая имеет возможность GSM запуска — дорого.

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

    Посмотрел бегло инструкции других моделей охранных систем SCHER-KHAN — на всех что мне попались такая возможность есть.

    Потребуется модуль SIM800L, ардуино (в моем случае про мини с питанием 3,3В), и STEP_DOWN преобразователь для получения 4В из 12В. Собрал я это все давно, в начале прошлой зимы на макетной плате, показывать её не буду — там всё страшно)) Отработало всё практически год и за это время недостатков я не заметил, ни разу не зависло и других отказов не было. Теперь, перед наступающей зимой решил привести это всё в красивый вид.

    Вытравил плату

    файлы для DipTrace

    Дополнительная информация
    Блок GSM автозапуска для сигнализации SCHER-KHAN

    Собрал всё на плате

    Дополнительная информация
    Блок GSM автозапуска для сигнализации SCHER-KHAN

    Блок GSM автозапуска для сигнализации SCHER-KHAN

    Блок GSM автозапуска для сигнализации SCHER-KHAN

    Схема

    Все резисторы на 10 кОм, только R8 на 220 Ом.

    Дополнительная информация
    Блок GSM автозапуска для сигнализации SCHER-KHAN

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

    Код для Ардуины

    Сразу хочу предупредить — в основном все скопировано/вставлено из чужих примеров, я совсем не программист, для меня главное работает безотказно, а как там всё внутри не так важно.

    От себя попытался добавить спящий режим как для ардуины, так и для модема. Перезагрузку при зависании и раз в сутки для надежности. Несколько дополнительных команд.

    cкетч в облаке

    Дополнительная информация
    #include <SoftwareSerial.h>// Библиотека программной реализации обмена по UART-протоколу

    #include <avr/wdt.h>

    #include <avr/sleep.h>

    #include <avr/power.h>

    #include <avr/interrupt.h>

    SoftwareSerial SIM800(8, 9); // RX, TX

    #define RING 2 //пин входящего звонка

    #define RESET_GSM 12 //пин перезагрузки sim800l

    #define SLEEP_GSM 6 //пин спящего режима sim800l

    #define START_ENGINE 3 //пин сигнала автозапуска для сигнализации

    #define R1 20 // сопротивление резистора R1

    #define R2 5 // сопротивление резистора R2

    #define LED 13 // светодиод на плате ардуино

    unsigned long sleep_sim; //таймер сна модема

    boolean callback = false; //нужно ли перезвонить по последнему входящему номеру

    volatile int nbr_remaining; // volatile to be modified in interrupt function

    unsigned long timing = 0; //переменная для задержки

    unsigned long reset_if_gsm_hover = 30000;

    String LastNumber = ""; //переменная для хранения последнего входящего номера

    String _response = ""; // Переменная для хранения ответа модуля

    int resetCounter = 1; // количество циклов сна после последней перезагрузки, цикл сна = 8сек

    unsigned long led_standby = 0; // счетчик для мигания светодиодом

    void setup() {

    pinMode(RING, INPUT_PULLUP); // к пину RING

    pinMode(RESET_GSM, OUTPUT); // к пину RESET модема для его перезагрузки

    digitalWrite(RESET_GSM, HIGH); // режим LOW — перезагрузка

    pinMode(SLEEP_GSM, OUTPUT); // к DTR пину GSM модуля

    digitalWrite(SLEEP_GSM, LOW); // пробуждаем GSM модуль

    pinMode(START_ENGINE, OUTPUT); // к сигнализации

    digitalWrite(START_ENGINE, LOW); // режим HIGH — автозапуск

    pinMode(LED, OUTPUT); //светодиод на ардуино

    digitalWrite(LED, LOW); // HIGH — горит

    wdt_enable(WDTO_8S); //сторожевой таймер на 8 сек

    Serial.begin(9600); // Скорость обмена данными с компьютером

    SIM800.begin(9600); // Скорость обмена данными с модемом

    Serial.println(«Start!»);

    sendATCommand(«AT», true); // Отправили AT для настройки скорости обмена данными

    // Команды настройки модема при каждом запуске

    _response = sendATCommand(«AT+CLIP=1», true); // Включаем АОН

    //_response = sendATCommand(«AT+DDET=1», true); // Включаем DTMF

    _response = sendATCommand(«AT+CSCLK=1», true); // Включаем возможность перевода sim800l в спящий режим

    _response = sendATCommand(«AT+CMGF=1;&W», true); // Включаем текстовый режим SMS (Text mode) и сразу сохраняем значение (AT&W)!

    }

    String sendATCommand(String cmd, bool waiting) {

    String _resp = ""; // Переменная для хранения результата

    Serial.println(cmd); // Дублируем команду в монитор порта

    digitalWrite(SLEEP_GSM, LOW); // пробуждаем GSM модуль

    delay(300);

    SIM800.println(cmd); // Отправляем команду модулю

    if (waiting) { // Если необходимо дождаться ответа…

    _resp = waitResponse(); //… ждем, когда будет передан ответ

    // Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать

    if (_resp.startsWith(cmd)) { // Убираем из ответа дублирующуюся команду

    _resp = _resp.substring(_resp.indexOf("r", cmd.length()) + 2);

    }

    Serial.println(_resp); // Дублируем ответ в монитор порта

    }

    return _resp; // Возвращаем результат. Пусто, если проблема

    }

    String waitResponse() { // Функция ожидания ответа и возврата полученного результата

    String _resp = ""; // Переменная для хранения результата

    long _timeout = millis() + 10000; // Переменная для отслеживания таймаута (10 секунд)

    while (!SIM800.available() && millis() < _timeout) {

    wdt_reset();

    } // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то…

    if (SIM800.available()) { // Если есть, что считывать…

    _resp = SIM800.readString(); //… считываем и запоминаем

    }

    else { // Если пришел таймаут, то…

    Serial.println(«Timeout…»); //… оповещаем об этом и…

    }

    return _resp; //… возвращаем результат. Пусто, если проблема

    }

    void loop() {

    wdt_reset();

    if (millis() > led_standby) { //мигание светодиодом в дежурном режиме

    digitalWrite(LED, HIGH);

    led_standby = millis() + 3000;

    delay(10);

    //Serial.println(readVoltage(100));

    } else {

    digitalWrite(LED, LOW);

    }

    if ((millis() — sleep_sim) > 120000) { //через 2 мин бездействия модем отправляем спать

    digitalWrite(SLEEP_GSM, HIGH);

    callback = false;

    sleep_sim = millis();

    Serial.println(«sleep_gsm»);

    }

    if (millis() > 86000000) { //каждые сутки перезагрузка модема и ардуины

    Serial.println(«reset_timeout»);

    digitalWrite(12, LOW);

    delay(100);

    digitalWrite(12, HIGH);

    delay(20000);

    }

    if (millis() > reset_if_gsm_hover) { //если модем завис и не отвечает перезагружаем его и ардуино, проверка каждые полчаса

    Serial.println(«reset_timeout_gsm»);

    reset_if_gsm_hover = millis() + 1800000;

    _response = sendATCommand(«AT+SAPBR=0,1», true);

    if (_response.length() < 1) {

    Serial.println(«reset_gsm»);

    digitalWrite(12, LOW);

    delay(100);

    digitalWrite(12, HIGH);

    delay(20000);

    }

    }

    if (SIM800.available()) { // Если модем, что-то отправил…

    reset_if_gsm_hover = millis() + 600000;

    sleep_sim = millis();

    digitalWrite(SLEEP_GSM, LOW);

    _response = waitResponse(); // Получаем ответ от модема для анализа

    _response.trim(); // Убираем лишние пробелы в начале и конце

    Serial.println(_response); // Если нужно выводим в монитор порта

    String whiteListPhones = "+79500000000, +79990000000, +79530000000, +79220000000"; // Белый список телефонов

    if (_response.startsWith(«RING»)) { // Есть входящий вызов

    int phoneindex = _response.indexOf("+CLIP: "");// Есть ли информация об определении номера, если да, то phoneindex>-1

    String innerPhone = ""; // Переменная для хранения определенного номера

    if (phoneindex >= 0) { // Если информация была найдена

    phoneindex += 8; // Парсим строку и…

    innerPhone = _response.substring(phoneindex, _response.indexOf(""", phoneindex)); //… получаем номер

    LastNumber = innerPhone;

    Serial.println(«Number: » + innerPhone); // Выводим номер в монитор порта

    }

    // Проверяем, чтобы длина номера была больше 6 цифр, и номер должен быть в списке

    if (innerPhone.length() >= 7 && whiteListPhones.indexOf(innerPhone) >= 0) {

    digitalWrite(3, HIGH); // turn the LED on (HIGH is the voltage level)

    delay(100); // wait for a second

    digitalWrite(3, LOW); // turn the LED off by making the voltage LOW

    sendATCommand(«ATA», true); // Если да, то отвечаем на вызов

    sendATCommand(«AT+CREC=4,»C:\User\6.amr",0,99", true); //проигрываем аудиофайл

    sendATCommand(«ATH», true); //сбрасываем

    timing = millis(); //сбрасываем счетчик до засыпания модема

    callback = true; //разрешаем перезвонить через заданное время если завелась

    } else {

    sendATCommand(«ATH», true); // Если нет, то отклоняем вызов

    }

    }

    if (_response.startsWith("+CMTI:")) { // Пришло сообщение об отправке SMS

    int index = _response.lastIndexOf(","); // Находим последнюю запятую, перед индексом

    String result = _response.substring(index + 1, _response.length()); // Получаем индекс

    result.trim(); // Убираем пробельные символы в начале/конце

    _response = sendATCommand(«AT+CMGR=» + result, true); // Получить содержимое SMS

    parseSMS(_response); // Распарсить SMS на элементы

    }

    if (_response.indexOf("+CIPGSMLOC: 0,") > -1) { //поиск, формирование ответа и ответ с координатами

    String LAT;

    String LNG;

    String Answer;

    LAT = _response.substring(_response.indexOf("+CIPGSMLOC: 0,") + 24, _response.indexOf("+CIPGSMLOC: 0,") + 33);

    LNG = _response.substring(_response.indexOf("+CIPGSMLOC: 0,") + 14, _response.indexOf("+CIPGSMLOC: 0,") + 23);

    Answer = «yandex.ru/search/?text=E» + LNG + "%20N" + LAT + "n" + readVoltage(200) + «V»;

    Serial.println(«GSM»);

    sendSMS(LastNumber, Answer); //отправляем смс на последний номер

    sendATCommand(«AT», true);

    sendATCommand(«AT+CMGDA=»DEL ALL"", true); // Удалить все сообщения, чтобы не забивали память модуля

    sendATCommand(«AT+SAPBR=0,1», true); // отключаем интернет

    }

    }

    if (Serial.available()) { // Ожидаем команды по Serial…

    SIM800.write(Serial.read()); //… и отправляем полученную команду модему

    }

    //если прошла минута после звонка и напряжение больше 13,2 вольта и разрешено перезвонить звоним, значит завелась

    if (millis() — timing > 45000 && callback == true) {

    if (readVoltage(100) > 13.2){

    sendATCommand(«ATD» + LastNumber + ";", true); //

    delay(1000); //

    callback = false;

    }else{

    callback = false;

    }

    }

    }

    // узнаем напряжение бортовой сети

    float readVoltage(int samples) { // samples — сколько раз нужно прочитать сенсор

    unsigned long avg_sum = 0;

    float u1;

    for (int i = 0; i < samples; i++) {

    avg_sum += analogRead(A6);

    delay(1); // небольшая пауза между замерами

    }

    u1 = (avg_sum / samples * 3.3 / 1024. / R2 * (R1 + R2));

    Serial.println(u1);

    return u1;

    }

    void parseSMS(String msg) {

    String msgheader = "";

    String msgbody = "";

    String msgphone = "";

    msg = msg.substring(msg.indexOf("+CMGR: "));

    msgheader = msg.substring(0, msg.indexOf("r"));

    msgbody = msg.substring(msgheader.length() + 2);

    msgbody = msgbody.substring(0, msgbody.lastIndexOf(«OK»));

    msgbody.trim();

    int firstIndex = msgheader.indexOf("","") + 3;

    int secondIndex = msgheader.indexOf("","", firstIndex);

    msgphone = msgheader.substring(firstIndex, secondIndex);

    LastNumber = msgphone;

    Serial.println(«Phone: » + msgphone);

    Serial.println(«Message: » + msgbody);

    if (msgbody.startsWith(«GPS_SEND»)) {

    sendATCommand(«AT+SAPBR=3,1,»CONTYPE",«GPRS»", true);

    sendATCommand(«AT+SAPBR=3,1,»APN",«internet»", true);

    sendATCommand(«AT+SAPBR=1,1», true);

    sendATCommand(«AT+CIPGSMLOC=1,1», true);

    }

    if (msgbody.startsWith(«V_SEND»)) {

    String Answer;

    String LNG = «Voltage = »;

    Answer = "" + LNG + readVoltage(100) + «V»;

    sendSMS(LastNumber, Answer);

    }

    if (msgbody.startsWith(«E_START»)) {

    digitalWrite(3, HIGH); // turn the LED on (HIGH is the voltage level)

    delay(100); // wait for a second

    digitalWrite(3, LOW); // turn the LED off by making the voltage LOW

    timing = millis();

    callback = true;

    }

    if (msgbody.startsWith(«CALL_BACK»)) {

    sendATCommand(«ATD» + LastNumber + ";", true);

    }

    }

    void sendSMS(String phone, String message)

    {

    sendATCommand(«AT+CMGS=»" + phone + """, true); // Переходим в режим ввода текстового сообщения

    sendATCommand(message + "rn" + (String)((char)26), true); // После текста отправляем перенос строки и Ctrl+Z

    }

    Логика работы и смс команды

    Белый список номеров телефонов находится в самом скетче. При звонке с незнакомого номера вызов просто сбрасывается.

    Если номер известен осуществляется попытка запуска и вызов сбрасывается в течении 2 сек. Через 45 сек если напряжение борт сети равно или более 13,2В значит двигатель работает и модуль перезванивает на последний входящий номер, его можно сбросить, но раз в месяц можно и ответить на звонок, чтобы были какие-то списания с сим карты установленной в модеме и оператор сот связи был доволен))

    Смс команды.

    отправляются только с номеров со списка.

    GPS_SEND отправляет в ответ приблизительные координаты. Сделал на случай угона и если поставят в глухие дворы отстаиваться, так можно попытаться найти.

    V_SEND отправляет в ответ напряжение борт сети.

    E_START запуск через смс, тоже что и со звонком.

    CALL_BACKв ответ перезванивает и через подключенный микрофон можно слушать что происходит в салоне, тоже на случай угона.

    В итоге получилось надежное устройство автозапуска, с минимумом вложений. Сим карта без абонентской платы, но нужно периодически чтобы отправлялось смс или совершался звонок, так как операторы связи этого требуют.

    Для тех кто решится повторить, отвечу на вопросы с удовольствием.

    Upd. Забыл добавить, сначала была проблема, машина не заводилась, сигнализация пищала при попытке запуска. Как оказалось помехи от блока влияли на выносной датчик вибрации сигнализации, получалось в момент звонка сигнализация «думала» что машину трясут и не позволяла завести двигатель. Решилось всё перемещением датчика на 30 — 40 см от блока запуска.

Оцените статью