Есть устройство для отслеживания температуры. Цифровой датчик температуры и влажности (Troyka-модуль) он же DHT11 + GPRS Shield + Leonardo. За основу взяли GPRS-логгер для теплицы без ненужных датчиков. Задача устройства - 1 раз в час опрашивать температуру, если она выходит за пределы допустимых значений отправить СМС. И один раз в сутки отправлять СМС с температурой, вне зависимости от показаний (контролируем что устройство работает). Питание устройства блок питания 7.5В 1.5А. Код (C++): #include <GPRS_Shield_Arduino.h> #include <GPRS_Shield_Arduino.h> #include <SoftwareSerial.h> #include <dht11.h> #include <stdlib.h> #include <avr/wdt.h> #define DHT11_PIN 11 //имя для пина к которому подключен датчик DHT11 #define INTERVAL 3600000 // интервал между отправками данных в миллисекундах (60 минут) #define PHONE_NUMBER "+ТУТ НОМЕР ТЕЛЕФОНА" #define LOW_TEMP 4 #define HIGH_TEMP 24 unsigned long previousMillis = 0; // переменная для хранения времени работы программы int temp = 0; // переменная температуры воздуха int humi = 0; // переменная влажности воздуха int count = 23; //количество-1 проверок на цикл с заданным интервалом char txtMsg[80]; //здесь храним текст СМСки dht11 DHT;// создаём объект класса dht11 GPRS gprs(Serial1); // создаём объект класса GPRS и передаём в него объект Serial1 // по умолчанию: PK = 2, ST = 3 // GPRS gprs(Serial1, 2, 3); void setup() { wdt_enable(WDTO_8S); //инициализация wathcdog перезагрузка через 8секунд gprs.powerOn(); Serial1.begin(9600); // открываем Serial-соединение с GPRS Shield wdt_reset(); //сбрасываем счетчик не реже чем 1 раз за 8 секунд, иначе перезагрузка } void loop() { while (true) { wdt_reset(); readSensors(); // вызываем функцию считывания всех показателей с датчиков wdt_reset(); if (count < 23) { //если температура вне заданного интервала отправить СМС (23 нужно оформить в переменную) count++; if (temp <= LOW_TEMP) { sendSMS(); } if (temp >= HIGH_TEMP) { sendSMS(); } } else { //один раз за цикл отправляем показания count = 0; sendSMS(); } while (millis() - previousMillis < INTERVAL) { //ждём заданный интервал wdt_reset(); delay(4000); wdt_reset(); delay(4000); wdt_reset(); delay(4000); wdt_reset(); delay(4000); wdt_reset(); delay(4000); wdt_reset(); } previousMillis = millis(); //если прошел, то сохраняем текущее время } } // функция считывания показателей с датчиков void readSensors() { wdt_reset(); DHT.read(DHT11_PIN); // считывание данных с датчика DHT11 // сохраняем считанные значения temp = DHT.temperature; humi = DHT.humidity; //Создаем текст СМС с получнными данными sprintf(txtMsg, "Temperature %d *C; Humidity %02d %", (int)temp, (int)humi); wdt_reset(); } void sendSMS() { while (!gprs.init()) { wdt_reset(); delay(2000); } gprs.sendSMS(PHONE_NUMBER, txtMsg); wdt_reset(); delay(4000); wdt_reset(); delay(4000); wdt_reset(); } При включении СМС приходит как и должна. GPRS платка коротко моргает диодом 1 раз в 6 секунд (что соответствует "сеть найдена, соединение установлено"). НО по прошествии суток повторного СМС не приходит. На GPRS плате горит красным диод TX, ничего не моргает. Проверял следующее: 1. Уменьшал период опроса температуры до 10минут и изменял пороговые значения -промежуточные СМСки с докладом исправно приходят. Добавлял вывод данных по Serial - работает несколько часов, потом вывода на терминал нет и на GPRS плате горит красным диод TX, ничего не моргает. 2. вставил while (!gprs.init()) в цикл ожидания интервала while (millis() - previousMillis < INTERVAL) - с тем же результатом. 3. Добавил gprs.init() перед отправкой СМС - с тем же результатом. 4. Добавил включение gprs.powerOn() в функцию отправки СМС, после СМС выключал GPRS модуль - с тем же результатом. 5. Добавил Serial1.begin(9600) в функцию отправки СМС, после отправки СМС Serial1.end(); - результат тот же. 6. Включил watchdog - и это ничего не изменило. Приведенный скетч последняя версия, все лишнее кроме watchdog убрано. Больше идей нет. Как я понимаю это недокументированная фича GPRS Shield + Leonardo. КАК победить эту проблему?
Я не спрашивал как вставить код. Меня интересует решение проблемы с зависанием GPRS Shield + Leonardo.
нет там никаких "недокументированных фич". Скорее всего, модем просто засыпает, если на нем нет активности какое-то время. Попробуйте каждые 3-5 минут подавать на модем команду "АТ". Если возвращает "ОК" - значит все нормально, если ответа нет - перезагружайте модем.
Я делал вот так Код (C++): while (millis() - previousMillis < INTERVAL) { // ждём 60 минут while (!gprs.init()) { delay(10000); } delay(10000); } //если прошел, то сохраняем текущее время previousMillis = millis(); } раз в 20 секунд проверял подключение к сети и вот так Код (C++): void sendSMS() { gprs.powerOn(); delay(5000); while (!gprs.init()) { delay(1000); } gprs.sendSMS(PHONE_NUMBER, txtMsg); delay(30000); gprs.powerOff(); } перед отправкой СМС включал GPRS shild,подключался к сети, отправлял СМС и после выключал GPRS shild и еще так Код (C++): void sendSMS() { Serial1.begin(9600); gprs.powerOn(); delay(5000); while (!gprs.init()) { delay(1000); } gprs.sendSMS(PHONE_NUMBER, txtMsg); delay(30000); gprs.powerOff(); Serial1.end(); } как прошлый вариант, но добавил включение выключение Serial 1й СМС приходит, через какое-то время На GPRS плате горит красным диод TX, ничего не моргает.
Неправильно. Эти куски кода вместо решения проблем только усугубляют ее Давйте посмотрим в первом коде вот на эту конструкцию : Код (C++): while (!gprs.init()) { delay(10000); } А теперь подумайте - в случае, если модем завис - метод gprs.init() будет постоянно возвращать false, правильно? - а значит программа НИКОГДА не выйдет из цикла while. Вместо того, чтоб решить проблему, этот цикл сам вешает программу. Кроме того, хотя это и не относится к делу - кто вас учил так использовать миллис? -миллис тут бесполезен, этот код полностью аналогичен delay() Во втором и третьем куске кода видим ровно этот же кусок с while (!gprs.init()) , который так же приводит к зависанию Идея контроля работы модема должна быть другой - регулярно проверяем, отвечает ли модем и если нет - перезапускаем его. Код может быть например такой - Код (C++): if (millis() - previousMillis > INTERVAL) { // запускаем раз в 5 минут if (!gprs.init()) { // если модем не отвечает - перезагружаем gprs.poweOff(); delay(1000); gprs.poweOn(); delay(1000); } //если прошел, то сохраняем текущее время previousMillis = millis(); } обратите внимание на принципиально другой подход к работе с миллис
В millis остались задержки от моих экзерсис с инициализацией. В заголовочном файле описание следующее Код (C++): /** initialize GPRS module including SIM card check & signal strength * @return true if connected, false otherwise */ bool init(void); Способ применения я взял из примера библиотеки Код (C++): gprs.powerOn(); // проверяем, есть ли связь с GPRS-устройством while (!gprs.init()) { // если связи нет, ждём 1 секунду // и выводим сообщение об ошибке; // процесс повторяется в цикле, // пока не появится ответ от GPRS-устройства delay(1000); Serial.print("GPRS Init error\r\n"); } Я не совсем понимаю разницу между предложенным вами вариантом и моим вторым Код (C++): void sendSMS() { gprs.powerOn(); delay(5000); while (!gprs.init()) { delay(1000); } gprs.sendSMS(PHONE_NUMBER, txtMsg); delay(30000); gprs.powerOff(); } После отправки СМС я выключаю модуль, и непосредственно перед отправкой следующего сообщения снова его включаю. Но в любом случае буду пробовать ваш вариант, как появится возможность добраться до поделки. Единственное я увеличу время задержки, т.к. если плата не будет успевать подключиться к сети за секунду, код будет дергать питание туда сюда.