#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 + "\r\n" + (String)((char)26), true); // После текста отправляем перенос строки и Ctrl+Z
}
А почему платы разные — вытравленная и распаянная? Разные ревизии?
Какую антенну использовали для SIM800? Куда прятали?
антена самая простая, которая в комплекте иногда идет, кусочек текстолита с проводом. Сам блок и антена спрятана за бардачком.
да, извиняюсь точно разные, первый раз травил забыл отзеркалить печать, а правильную уже не фотографировал без лужения.
По скетчу.
…
Если используется прямое обращение по номеру, зачем было в самом начале писать дефайны?..
Но — как сделано, так и сделано.
Если всё работает и автора устраивает — то и ладно.
Кто будет повторять — имейте в виду, при переделке схемы выверяйте все числа в скетче, дефайны не помогут…
да это кучу раз всё исправлял и наверно запутался. Но не мешает, исправлю.
Если честно, я сам задумываются о том, что для одной маленькой ардуины в машине найдётся работа. И именно на этапе зимнего удалённого запуска. Думаю заставить её в случае удалённого запуска с сигналки и если температура в салоне отрицательная, минуточек на пять включать обогрев кресел. Дольше не нало, вредно. А в подготовюленный салон и садиться приятнее…
А в автобусе люди, которые в брючках ПШ и пальто или пуховике поверх? *Зачем сейчас топят в автобусах, внутри 20+, приходится куртку снимать.
представьте что с вашими шалтай-балтаями происходит в в парилке, сауне или горячей ванной ))) это вредно только в плане выживаемости живых сперматазоидов, вред сразу же проходит после того как тепло исчазает.
А заглушить двигатель дистанционно сигнализация позволяет?
Думаю, случаи когда собирался выходить и планы поменялись не так уж редки. Не тарахтеть же ему до второго пришествия!)
Это у всех операторов в России такие рестрикции? А в KZ и BY с этим как?
В Украине для продления номера Киевстар достаточно раз в год принять входящий звонок, Vodafone — закинуть на счёт 5грн раз в год, lifecell — 10грн/год.
да, там если в течении 3 месяцев нет списаний со счета они включают «услугу сохранения номера» с абонентской платой, когда интересовался у всех операторов было примерно одно и тоже.
Можно взять тариф «Управление удалёнными объектами» и за 20 рублей в месяц иметь крохотный пакет трафика для управления через веб — moscow.megafon.ru/ai/document/9471/file/Tariff_1_moscow.pdf
Можно вставить sim карту Йоты и в «конструкторе» тарифа оставить только какой-нибудь мессенджер, чтобы абонплата составляла 10 руб. в месяц. Закинуть на счёт 120 рублей и забыть на год.
Но могут быть ограничения на минимальную сумму или комиссии за перевод. Раньше в QIWI-кошельке их не было, как сейчас — не интересовался.
У них минимальный тариф идет от 1ГБ и стоит 162.45 руб/мес.
В минутах можно выбрать «0», а в гигабайтах нет.
Тарифы меняют, отправив смс-ку. Личного кабинета нет, только через андроид-приложение…
Тут либо сделать принятие звонка и ввод кода ( через тональный набор ) либо оставить только смс.
ps: а вообще варианты с интернет меседжерами тоже интересные
как опасность я бы всё-таки рассматривал вариант заглушить во время движения конечно. такой сценарий лучше исключить. Причем проблема может быть не в недоброжелателях, а банально взял телефон и случайно ткнул последний набранный ещё раз набрать (неважно владелец взял или ребёнок/жена/тёща/шутник). Случайно набрать номер из последних — не такое уж редкое явление.
Но уже ниже прочитал что во время движения не заглохнет — это хорошо.
В идеале бы доработать сигнализацию идентификацией нахождения владельца авто за рулём, чтобы исключить реакцию на звонок даже из белого списка во время движения.
С дополнительными плюшками в виде GPS отслеживания и онлайн-мониторинга авто…
еще вспомнил блок потреблял меньше самой сигнализации (<30мА), поэтому я был спокоен.
Но внеплановый прогрев по звонку — тоже очень полезная штука. Жаль у меня так просто не подключить, внешний блок должен не "+" куда-то подать, а команду в CAN-шину…
«Белый список» не зашивать в код, а читать из SIM-карты не пробовали? Мне кажется — проще в SIM-карту номера заносить, чем менять в коде и перезаливать.
Это если у ОпСоСа подписаться на сервис определения координат по вышкам?
Вот этот лот — тот же самый модуль?
https://aliexpress.com/item/item/32283531730.html
Хотел сначала сделать ещё интересней, хранить в eeprom ардуино, а добавлять отправкой смс с каким то определенным кодом. Тогда бы вообще не пришлось бы его доставать. Но потом вспомнил когда последний раз менял номер телефона и решил что это не нужно, делал же только для себя, выкладывать не планировал.
вообще если время появится свободное, доработаю, сделаю номера в eeprom, тогда можно будет дистанционно добавлять и удалять номера.
это гораздо интереснее, чем sms канал
ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Stand-Alone-CAN-Controller-with-SPI-20001801J.pdf
оно во все стороны)
Да, красный тот же
Надо по питанию ставить конденсаторы и ножки sim-разъёма пропаивать, если кто столкнётся с проблемой «глючности» модуля
ну или както поставить компаратор по питанию. При запуске машины там идет просадка вольт до 8. ее хватит чтоб сбросить модуль.
З.Ы.
о, можно вообще не так)
компаратор на 10,5 вольт + MOSFET
• 20 nA @ 3 V Shutoff Mode
• 0.6 µA @ 3 V Stop Mode, including Power-on Reset, Brown-out Detector, RAM and CPU retention
• 0.9 µA @ 3 V Deep Sleep Mode, including RTC with 32.768 kHz oscillator, Power-on Reset, Brown-out Detector, RAM and CPU
retention
• 45 µA/MHz @ 3 V Sleep Mode
• 180 µA/MHz @ 3 V Run Mode, with code executed from flash
И в другой серии efm32gg12
Flexible Energy Management System
• 76 μA/MHz in Active Mode (EM0)
• 1.8 μA EM2 Deep Sleep current (16 kB RAM retention and
RTCC running from LFRCO)
www.st.com/content/ccc/resource/technical/document/application_note/e1/ba/54/65/07/1b/4c/ff/CD00219011.pdf/files/CD00219011.pdf/jcr:content/translations/en.CD00219011.pdf
уж какой STM8 вроде не жрущий… а параметры хуже 32-битного EFM
А для мк с близким обьемом рам и флеш и похожей периферией в одном техпроцессе параметры прям один в один
Вот (выделено жирным) для референсних ядер Cortex-M0+ (STM32G) и Cortex-M0 (STM32F) — данные для Cortex-M0 в скобках
Flexible Energy Management System
• 20 nA @ 3 V Shutoff Mode
• 0.6 µA @ 3 V Stop Mode, including Power-on Reset, Brown-out Detector, RAM and CPU retention 565nА
• 0.9 µA @ 3 V Deep Sleep Mode, including RTC with 32.768 kHz oscillator, Power-on Reset, Brown-out Detector, RAM and CPU retention 0.9 (1.4) µA/MHz
• 45 µA/MHz @ 3 V Sleep Mode 32 (50) µA/MHz
• 180 µA/MHz @ 3 V Run Mode, with code executed from flash 100 (250) µA/MHz 3.3V 25C, периферия отключена, при тактировании всей периферии не превышает 500 µA/MHz
— а вот для разных техпроцессов энергоэффективность уже отличается на порядок, а площадь на два порядка. Так для STM32F (Cortex-M0) параметры ниже.
Динамическое потребление, мкВт/МГц Площадь, мм²
180ULL (1,8 В; 25°C) 66 0,11
90LP (1,2 В; 25°C) 12,5 0,03
40LP (1,1 В; 25°C) 5,3 0,008
Так что на сегодня для практически похожих мк в активном режиме силикон лаб EFM32 в сравнении с STM32G жрет в 1.8 раза больше, что в некоторых случаях может быть существенно. Кроме этого (и может быть главное) они значительно дороже и все под заказ.
www.st.com/resource/en/datasheet/stm32g071c8.pdf
стр 61
а вот у STM32F103 например все намного хужее…
недавно поставили мелкое LDO на этот проц… пришлось плату переразводить…
З.Ы. а так ну конечно все зависит от схемотехники периферии и надо оно вообще или нет… както делали на EFM32 железку с батарейным питанием… работает пол года на одной батарейке…
основной функцией «сигналок» — удобство эксплуатации, защитные функции устоят разве что перед неопытным
угонщиком.
самая ленивая схема защиты как минимум КАСКО, выбивание денег конечно та же затея, но по крайней мере это некая защита чтобы не остаться без денег совсем.
по способу защиты хорошо себя чувствуют секретки в идеале сделанные самим владельцем или по крайней мере надежным знакомым электриком, но ни как не на сервисе. найти секретку очень сложно, проще отсканировать код или влезть в цепи сигнализации, в связи с этим любая сигналка с автозапуском «ломается» гораздо быстрее, чем без этой опции, всякие там приблуды типа ЖСМ для дистанционного запуска не сильно «дырявят» уязвимые места, достаточно что автозапуск есть. в связи с этим по способу защиты я бы распределил так (на первом месте самая слабая защита):
1. дополнительная сигнализация с автозапуском
2. родная или сигнализация без автозапуска (для предпускового подогрева двигателя есть отдельные системы, да, они дороги, но намного эффективнее в плане расхода топлива и более щадящие для ресурса двигателя)
3. дополнительная метка
4. дополнительная механическая скрытая защита руля или коробки передач.
5. секретка встроенная в цЕпи блокировки двигателя
6. спутниковые охранные системы (весьма дороги, но не дороже автомобиля :))
7. КАСКО
8. штатная сигнализация при условии выбора автомобиля не находящегося в списке риска угонов
9. персональная круглосуточная охрана
8 пункт здесь самый дешевый вариант, за все остальное придется раскошелится в зависимости от достатка.
ЗЫ: места распределены мной исключительно на собственных знаниях и основаны на личном мнении, ваше мнение безусловно может отличаться соответственно.
я не работаю автоэлектриком, но очень много всего сделал и поставил в своей машине, в том числе простую сигнализацию. секреток не ставил, т.к. у меня 8 пункт :)
Да, там как раз появляется "-" как и надо для вашей сигнализации.
сейчас не могу посмотреть с телефона эти файлы, но скорее всего да, там 2 разъема, если u4 это питание с аккумулятора, то u5 соответственно микрофон.
sendATCommand(«AT+CREC=4,\»C:\\User\\6.amr\",0,99", true); //проигрываем аудиофайл
https://github.com/martinhol221/SIM800L_DTMF_control/wiki/%D0%97%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B0-%D0%B0%D1%83%D0%B4%D0%B8%D0%BE%D1%84%D0%B0%D0%B9%D0%BB%D0%BE%D0%B2-%D0%B2-SIM800L,-AT-CREC
Чтобы при звонке модуль не просто бросал трубку, а говорил что то
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.