Не меняется переменная - не найду причину

Тема в разделе "Arduino & Shields", создана пользователем Justasf, 10 июл 2023.

Метки:
  1. Justasf

    Justasf Нуб

    День добрый.

    Мучаю модем SIM800. Есть задача получать данные по температуре с датчика DS18B20 и через связь GSM отправлять на narodmon. Между отправками модем выключен, arduino спит. Все более менее работает (зависит от качества связи, не в этом вопрос). Понадобилось для анализа прикрутить передачу количества периодов сна. Прикрутил глобальную переменную, в loop увеличиваю при каждом периоде сна на 1, а она не меняется. Много чего перепробовал, сбрасывается на 0 на новом витке loop. Опыта у меня совсем мало, разбираю и соединяю куски кода с разных примеров и форумов. 100% проблема ничтожная, но я без опыта ее не вижу. Уже руки опускаются, помогите советом..

    Код (C++):
    #define battery_min 3600     // минимальный уровень заряда батареи
    #define sim800_Vcc 2           // пин питания, куда подключен sim800
    #define ONE_WIRE_BUS 13 // и настраиваем  пин 13 как шину подключения датчиков DS18B20

    #include <SoftwareSerial.h>
    SoftwareSerial SIM800(5, 6); // RX, TX
    #include <DallasTemperature.h> // подключаем библиотеку чтения датчиков температуры
    #include <Wire.h>              // вспомогательная библиотека датчика
    OneWire oneWire(ONE_WIRE_BUS);
    DallasTemperature sensors(&oneWire);//
    #include <LowPower.h>          // библиотека сна

    float tempds0; // переменная для температуры
    float my_vcc_const = 1.104;   // константа вольтметра
    unsigned long Time1 = 0;
    unsigned long Time2 = 0;
    byte modem = 0;            // переменная состояние модема
    int16_t _sig = -99;
    int16_t varS;

    void setup() {
      String at = "";
      Serial.begin(9600);  //скорость порта
      SIM800.begin(9600);  //скорость связи с модемом
      pinMode(sim800_Vcc, OUTPUT);
      pinMode(A5, OUTPUT);
      pinMode(A4, OUTPUT);
      digitalWrite(sim800_Vcc, 1);      // подать питание на SIM800
      delay(5000);
      do {
        at = sendATCommand("ATE0", true);  //
        at.trim();                       // Убираем пробельные символы в начале и конце
      } while (at != "OK");
      at = "";
      digitalWrite(A4, 1); // подать питание на датчик
      digitalWrite(A5, 0); //
      sensors.begin();
      sensors.setWaitForConversion(false);
      sensors.requestTemperatures();   // читаем температуру с датчика
      tempds0 = sensors.getTempCByIndex(0); // опросить датчик DS18B20
    }

    void loop() {
      String at = "";
      int k = 0;
      if (SIM800.available()) { // если что-то пришло от SIM800 в направлении Ардуино
        while (SIM800.available()) k = SIM800.read(), at += char(k), delay(1); //пришедшую команду набиваем в переменную at

        if (at.indexOf("SHUT OK") > -1 && modem == 2) {
          Serial.println("1.***Start***"), Serial.println(varS), Serial.println("*************"),
          Serial.println("S H U T OK"), SIM800.println("AT+CMEE=1"), delay(100), modem = 3;

        } else if (at.indexOf("OK") > -1 && modem == 3) {
          Serial.println("AT+CMEE=1 OK"), SIM800.println("AT+CGATT=1"), delay(100), modem = 4;

        } else if (at.indexOf("OK") > -1 && modem == 4) {
          Serial.println("AT+CGATT=1 OK"), SIM800.println("AT+CSTT=\"internet.ru\""), modem = 5;

        } else if (at.indexOf("OK") > -1 && modem == 5) {
          Serial.println("internet.ru OK"), SIM800.println("AT+CIICR"), modem = 6;

        } else if (at.indexOf("OK") > -1 && modem == 6) {
          Serial.println("AT+CIICR OK"), SIM800.println("AT+CIFSR"), modem = 7;

        } else if (at.indexOf(".") > -1 && modem == 7) {
          Serial.println(at), SIM800.println("AT+CIPSTART=\"TCP\",\"narodmon.ru\",\"8283\""), modem = 8;

        } else if (at.indexOf("CONNECT OK") > -1 && modem == 8 ) {
          SIM800.println("AT+CIPSEND"), Serial.println("C O N N E C T OK"), modem = 9;

        } else if (at.indexOf(">") > -1 && modem == 9) {  // пакет c данными и шлем на сервер
          Serial.println("#00-00-00-00-00-00#ABCDEFG"); // индивидуальный номер для народмона
          Serial.print("\n#Temp1#"), Serial.println(tempds0);
          Serial.print("\n#Vbat#"),  Serial.println(readVcc());
          if  (_sig > -114 && _sig < -46) Serial.print("\n#dBm#"), Serial.println(_sig);
          Serial.print("\n#Period#"),  Serial.println(millis() - Time2);
          Serial.print("\n#Count#"),  Serial.println(varS);
          Serial.println("\n##"), delay (50); // обязательный параметр окончания пакета данных
          SIM800.print("#00-00-00-00-00-00#ABCDEFG"); //
          if  (85 > tempds0 && tempds0 > -50) SIM800.print("\n#Temp1#"), SIM800.print(tempds0);
          SIM800.print("\n#Vbat#"),  SIM800.print(readVcc());
          if  (_sig > -114 && _sig < -46) SIM800.print("\n#dBm#"),  SIM800.print(_sig);
          SIM800.print("\n#Period#"),  SIM800.print(millis() - Time2);
          SIM800.print("\n#Count#"),  SIM800.print(varS);
          SIM800.print("\n##");      // обязательный параметр окончания пакета данных
          SIM800.print((char)26), delay (100);
          modem = 10;

        } else if (at.indexOf("OK") > -1 && modem == 10) {
          delay(50);
          Serial.println("SEND OK");
          modem = 0, delay (100), SIM800.print("AT+CIPSHUT"); // закрываем пакет
          digitalWrite(A4, 0), digitalWrite(A5, 0), delay(50); // отключить питание на датчик
          digitalWrite(sim800_Vcc, 0), delay(50);     // отключить питание на SIM800
          _sleep(), delay(50);
          Time2 = millis();
          delay(50);
          Serial.println("2.***END***");
          Serial.println(varS);
          Serial.println("***********");
          delay(50);
          digitalWrite(sim800_Vcc, 1), delay(5000);      // включить питание на SIM800
          digitalWrite(A4, 1), digitalWrite(A5, 0), delay(50); // включить питание на датчик
          SIM800.print("AT+CIPSHUT");

        } else Serial.println(at);    // если пришло что-то другое выводим в серийный порт
        at = "";  // очищаем переменную
      }

      if (millis() > (Time1 + 10000)) detection(), Time1 = millis(); // выполняем функцию detection () через интервал (interval)

      if (readVcc() < battery_min) digitalWrite(sim800_Vcc, 0), digitalWrite(A4, 0), digitalWrite(A5, 0), LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // отключить питание на датчик

    }

    void detection() { // условия проверяемые каждые  сек
      static byte interval;
      sensors.requestTemperatures();   // читаем температуру с датчика
      tempds0 = sensors.getTempCByIndex(0); // опросить датчик DS18B20
      if (interval == 255) _sig = Signal();
      Serial.print(" || Signal : "), Serial.print(_sig);
      Serial.print(" || Modem : "), Serial.print(modem);
      Serial.print(" || voltage : "), Serial.print(readVcc());
      Serial.print(" || Interval : "), Serial.print(interval);
      Serial.print(" || Temp : "), Serial.println(tempds0);
      interval--;
      if (interval == 253 ) interval = 0, modem = 1; //
      if (modem == 1) SIM800.println("AT+CIPSHUT"), modem = 2;
    }

    void _sleep() { // ЦИКЛ ДЛЯ СНА 15 МИНУТ // 110 * 8 ~ 15 минут
      varS = varS + 1, delay(50);
      //  Timer delays about few minutes between readings
      for (int i = 0; i < 108; i++) {
        LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
      }
      //LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
      //LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
      //LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
    }

    int Signal() { // замеряем dBa
      String _signal;
      do {
        _signal = sendATCommand("AT+CSQ", true);    // Запрашиваем информацию о качестве сигнала
      } while (_signal.indexOf("CSQ:") < 0);
      _signal = _signal.substring(8, 10);
      int8_t _signall = _signal.toInt();
      return (_signall + _signall - 114);
    }

    String sendATCommand(String cmd, bool waiting) {
      String _resp = "";                            // Переменная для хранения результата
      //Serial.println(cmd);                          // Дублируем команду в монитор порта
      SIM800.println(cmd);                          // Отправляем команду модулю
      if (waiting) {                                // Если необходимо дождаться ответа...
        _resp = waitResponse();                     // ... ждем, когда будет передан ответ
        Serial.println(_resp);                      // Дублируем ответ в монитор порта
      }
      return _resp;                                 // Возвращаем результат. Пусто, если проблема
    }

    String waitResponse() {                         // Функция ожидания ответа и возврата полученного результата
      String _resp = "";                            // Переменная для хранения результата
      long _timeout = millis() + 10000;             // Переменная для отслеживания таймаута (10 секунд)
      while (!SIM800.available() && millis() < _timeout)  {}; // Ждем ответа 10 секунд, если не пришел ответ или наступил таймаут, то...
      if (SIM800.available()) {                     // Если есть, что считывать...
        _resp = SIM800.readString();                // ... считываем и запоминаем
      }
      else {                                        // Если пришел таймаут, то...
        digitalWrite(sim800_Vcc, 0);      // - питание на SIM800
        delay(1000);
        digitalWrite(sim800_Vcc, 1);      //  + питание на SIM800
        delay(5500);
        modem = 2;
        SIM800.println("AT+CIPSHUT");
        digitalWrite(A4, 1); // подать питание на датчик
        digitalWrite(A5, 0); //
        _resp = "REBOOT";
      }
      return _resp;                                 // ... возвращаем результат. Пусто, если проблема
    }

    long readVcc() { //функция чтения внутреннего опорного напряжения, универсальная (для всех ардуин) vbyen
    #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
      ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
      ADMUX = _BV(MUX5) | _BV(MUX0);
    #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
      ADMUX = _BV(MUX3) | _BV(MUX2);
    #else
      ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #endif
      delay(2); // Wait for Vref to settle
      ADCSRA |= _BV(ADSC); // Start conversion
      while (bit_is_set(ADCSRA, ADSC)); // measuring
      uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
      uint8_t high = ADCH; // unlocks both
      long result = (high << 8) | low;

      result = my_vcc_const * 1023 * 1000 / result; // расчёт реального VCC
      return result; // возвращает VCC
    }
     
  2. DetSimen

    DetSimen Гуру

    Да тут и с опытом в этом говнокоде сложно чонить увидеть.
     
    parovoZZ нравится это.
  3. Justasf

    Justasf Нуб

    int16_t varS - вот это. Обозначил переменную в самом начале кода. Правильно понимаю, что тут не надо ей присваивать значение и оно будет по умолчанию "0" и эта переменная будет видна во всех частях программы (спрошу только чтобы перепроверить себя...)?
    по условию elseif(at.indexOf("OK")>-1&& modem ==10) должна выполняется функция void _sleep() - там увеличение значения varS = varS +1, и в серийный порт видно что она увеличивается, но после всех IF на новом витке loop опять 0. Что не так?
     
  4. Justasf

    Justasf Нуб

    учится учится и еще раз учится... какой код есть про тот и спрашиваю...
     
  5. DetSimen

    DetSimen Гуру

    Пока не сделаешь декомпозицию, спрашивать можешь доооолго.
     
  6. Justasf

    Justasf Нуб

    понял. буду резать и искать в блоках . спасиб..
     
  7. liahim55

    liahim55 Нерд

    Разбираться с кодом терпения не хватило.
    Попробуйте объявить переменную как volatile или храните в EEPROM
     
  8. User248

    User248 Гик

    Потому что здесь что-то непонятное. Попробуйте запятую заменить на точку с запятой.

    Код (C++):
    varS = varS + 1, delay(50);
     
    DetSimen и parovoZZ нравится это.
  9. parovoZZ

    parovoZZ Гуру

    да, компилятор Си глобальные переменные обнулит самостоятельно. Локальные - нет.

    да, но с оговоркой - только в текущем файле. Если переменная объявлена в другом файле, то для её видимости этот файл необходимо подключить.
     
  10. Justasf

    Justasf Нуб

    учусь на примерах. Вот по моему вероятная ошибка.
    " if (at.indexOf("SHUT OK") > -1 && modem == 2) {Serial.println("S H U T OK"), SIM800.println("AT+CMEE=1"), modem = 3; { " (часть кода)
    здесь команды идут через запятую (и компилятор не ругается), но много источников пишут, что после каждой команды надо ставить " ; ". Где правда?
     
  11. parovoZZ

    parovoZZ Гуру

    правда в книге Кернигана и Ричи. На примерах хорошо учиться практике, но никак не теории. А практика только после теории.
     
    DetSimen нравится это.
  12. User248

    User248 Гик

    Действительно не ругается, но выглядит это не корректно. Запятые привычно видеть только в функциях и цикле for, где можно инициализировать сразу несколько переменных через запятую. Но если в том же цикле for точку с запятой заменить на запятую, то начнёт ругаться.
     
    Последнее редактирование: 11 июл 2023
  13. User248

    User248 Гик

    Значит, по какой-то причине сбрасывается микроконтроллер.
     
  14. parovoZZ

    parovoZZ Гуру

    может для начала написать код в соответствии со стандартами языка, а не полагаться на поведение компилятоа в условиях, когда все предупреждения от него выключены?
    Честно, я даже не понимаю, как компилятор воспринимает здесь запятые. Потому как через запятые можно перечислять переменные или аргументы в функции. Но команды... Команды разделяются исключительно через точку с запятой.
     
  15. Ariadna-on-Line

    Ariadna-on-Line Гуру

    1. Что угодно прокомментировано, но не главный фигурант вопроса. Приходится гадать о какой переменной речь. Спасибо хоть во втором сообщении догадались назвать.
    2. Вот нахрена вам название подпрограммы с нижней черточки : _sleep() ? В синтаксисе языков это может означать продолжение предыдущей строки, а не отдельное слово. И ввести в заблуждение компилятор. Используется для удобочитаемости на узких мониторах.
    3. Про точки с запятой тут уже сказали. Чаще всего ошибки возникают вот из-за такого выпендривания с синтаксисом.
    4. Большое количество точек ветвления if, else if - может приводить к переполнению стека памяти. Но это уже конкретно мои фантазии. Прошу тапками не кидаться.
     
    Последнее редактирование: 11 июл 2023
  16. liahim55

    liahim55 Нерд

    Все таки рекомендую строку
    int16_t varS;
    заменить на
    volatile int16_t varS;
    и думаю все заработает.
     
  17. DetSimen

    DetSimen Гуру

    Гугли "Язык Си, операция запятая"
     
  18. DetSimen

    DetSimen Гуру

    Неть
     
  19. DetSimen

    DetSimen Гуру

    Нет. Но очень хорошо приводит к запутыванию логики программы. Вложенные if-else зло, если ты не знаешь, что делаешь а ТС не прочитал ни одной книги по языку, он точно не знает, что делает.
     
    parovoZZ нравится это.
  20. Justasf

    Justasf Нуб

    Насколько я помню, один из подходов к изучению, начинай делать что-либо полезное для себя (pet project) и читай/ищи/спрашивай нужную информацию. А если только читать, то интерес быстро угаснет. Я не читал книг по программированию, это так.
    Здесь if elseif пошаговая отправка команд одна за одной для модема. (пока предыдущая не исполнится следующая не отправляется). Другие конструкции у меня не привели к результату (на эмуляторе работало, с "живой" железкой SIM800 - нет).