GPRS Shield + Leonardo

Тема в разделе "Arduino & Shields", создана пользователем axxxl, 7 янв 2019.

  1. axxxl

    axxxl Нуб

    Есть устройство для отслеживания температуры. Цифровой датчик температуры и влажности (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.
    КАК победить эту проблему?
     
    Последнее редактирование: 8 янв 2019
  2. NikitOS

    NikitOS Король шутов Администратор

  3. axxxl

    axxxl Нуб

    Я не спрашивал как вставить код. Меня интересует решение проблемы с зависанием GPRS Shield + Leonardo.
     
  4. вот сам его так и читай в поисках ошибок.
     
    Daniil нравится это.
  5. NikitOS

    NikitOS Король шутов Администратор

    Я сказал, как правильно.
    В таком виде его никто читать не будет
     
    Daniil нравится это.
  6. b707

    b707 Гуру

    нет там никаких "недокументированных фич". Скорее всего, модем просто засыпает, если на нем нет активности какое-то время.
    Попробуйте каждые 3-5 минут подавать на модем команду "АТ". Если возвращает "ОК" - значит все нормально, если ответа нет - перезагружайте модем.
     
  7. axxxl

    axxxl Нуб

    Я делал вот так
    Код (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, ничего не моргает.
     
  8. b707

    b707 Гуру

    Неправильно. Эти куски кода вместо решения проблем только усугубляют ее

    Давйте посмотрим в первом коде вот на эту конструкцию :
    Код (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();
      }
    обратите внимание на принципиально другой подход к работе с миллис
     
    Последнее редактирование: 8 янв 2019
  9. axxxl

    axxxl Нуб

    В 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();
    }
     
    После отправки СМС я выключаю модуль, и непосредственно перед отправкой следующего сообщения снова его включаю.
    Но в любом случае буду пробовать ваш вариант, как появится возможность добраться до поделки. Единственное я увеличу время задержки, т.к. если плата не будет успевать подключиться к сети за секунду, код будет дергать питание туда сюда.