Зависает arduino после 2-х дней работы

Добрый день, кратко опишу ситуацию.
На Arduino UNO собран небольшой прибор который, снимает показания с датчика. Датчик работает по modbus, и подключен к arduino через конвертер интерфейсов. Питание подается с преобразователя напряжения 5А. Поверх Arduino установлен SIM900 shield.

В цикле программы, опрашивается датчик примерно раз в 19 секунд (с учетом всех задержек в коде), формируется http get запрос, и отправляется на веб сервер через sim900.

Отлаживаю эту систему двумя способами, UNO мониторю через COM порт IDE, мониторинг SIM 900 через COM порт PUTTY.

Проблема в следующем:

  1. В определенный момент программа зависает и UNO перестает выводить информацию в serial.
  2. SIM900 сначала шлет 200 коды ответа от сервера (хотя запросы не отправляются), потом выводит уровень сигнала (+29 OK), и после этого строку вида “+CREG: 1”.
  3. после реинициализации com порта UNO ардуино начинает свой цикл с setup (видимо ребутится)

SIM900 питается от внешнего питания, переключатель включен, с программными портами косяк, надо менять UNO (это я понимаю), но пока что это все что имеется. В коде много комментариев, сразу прошу прощения.

#include <SoftwareSerial.h>
#include <iarduino_Modbus.h>

SoftwareSerial GSMport(7, 8);   // RX, TX для GSM модуля
SoftwareSerial rs485(2, 5);     // RX, TX для RS485 интерфейса
ModbusClient modbus(rs485, 3);  // объект Modbus, использующий rs485 и управляющий вывод DE конвертера
int TTS = 5000;                 // Время задержки между отправками данных
float Temp;                     // Переменная для хранения температуры
float Vel;                      // Переменная для хранения виброскорости
float Disp;                     // Переменная для хранения виброперемещения
String lvl_gsm;                 // Переменная для хранения уровня сигнала
int count = 0;                  // Счетчик отправок данных

void setup() {
  Serial.begin(9600);  // Скорость порта
  Serial.println("Start Setup");
  Serial.println("Check Enable SIM900Shield");
  GSMport.begin(9600);
  GSMport.setTimeout(1500);
  rs485.begin(4800);       // Инициализация RS485 интерфейса
  modbus.begin();          // Инициализация Modbus
  modbus.setTimeout(100);  // Установка таймаута для Modbus

  if (!check_Init_GSM_Shield()) {
    powerUpOrDownGsm();  // включаем GSM надо добавить проверку на инициализацию сети в SIM900
  }

  /*if (!check_Init_GSM_connect()) {  // write two func
    init_connect_to_GSM();
  }*/
  init_connect_to_GSM();
  Serial.setTimeout(100);
  Serial.println("Finish Setup loop");
}

void loop() {
  Serial.println("Start loop");
  ReadReg();
  getSignalStrength();
  list_param(Temp, Vel, Disp, lvl_gsm);
  delay(TTS);
  send_http_req(Temp, Vel, Disp, lvl_gsm);
}

void powerUpOrDownGsm() {  // Функция вкл/выкл
  Serial.println("Start powerUpOrDownGsm func");
  GSMport.listen();
  pinMode(9, OUTPUT);
  digitalWrite(9, LOW);
  delay(1000);
  digitalWrite(9, HIGH);
  delay(2000);
  digitalWrite(9, LOW);
  delay(10000);
  Serial.println("Finish powerUpOrDownGsm func");
}

bool check_Init_GSM_Shield() {
  Serial.println("Start checkInitGSM");
  GSMport.listen();
  String at_com = "AT";
  Serial.println(at_com);
  GSMport.println(at_com);
  delay(5000);
  String response = ReadGSM();
  Serial.println("I get answer: " + response);
  if (response.indexOf("OK") != -1) {  // проверяем есть ли OK в ответе если нету возвращаем FALSE
    Serial.println("Shield already init. check_Init_GSM_Shield return TRUE");
    return true;
  }
  Serial.println("Shield not init. check_Init_GSM_Shield return FALSE");
  return false;
}

bool check_Init_GSM_connect() {  // найти AT команды для проверки соединения сотовой
  Serial.println("Start checkInitGSM_connect");
  GSMport.listen();
  String req = "AT+CREG?";
  Serial.println("Arduino send command: " + req);
  GSMport.println(req);
  delay(5000);
  String response = ReadGSM();
  Serial.println("Arduino get answer from SIM900: " + response);
  if (response.indexOf("+CREG: 1,1") != -1) {  // проверяем есть ли OK в ответе если нету возвращаем FALSE
    Serial.println("Shield already connect to GSM. check_Init_GSM_connect return TRUE");
    return true;
  }
  return false;
}

void send_http_req(float data1, float data2, float data3, String& data4) {
  GSMport.listen();
  String req = "AT+HTTPPARA=\"URL\",\"http://185.146.156.135/vibro_data-add/add.php/?temp=";
  req += data1;
  req += "&vel=";
  req += data2;
  req += "&disp=";
  req += data3;
  req += "&signalStr=";
  req += data4;
  req += "\"";
  SendATCommand("AT+HTTPINIT");
  delay(4000);
  //SendATCommand("AT+HTTPPARA=\"CID\",1");
  Serial.println(req);
  SendATCommand(req);
  SendATCommand("AT+HTTPACTION=0");
  delay(5000);
  SendATCommand("AT+HTTPTERM");
  Serial.println(count++);
  rs485.begin(4800);
}

void init_connect_to_GSM() {
  GSMport.listen();
  SendATCommand("AT+CIPSHUT");
  delay(1000);
  SendATCommand("AT+HTTPTERM");
  delay(1000);
  SendATCommand("AT+SAPBR=0,1");
  delay(1000);
  SendATCommand("AT+SAPBR=1,1");
  delay(6000);
  SendATCommand("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
  SendATCommand("AT+SAPBR=3,1,\"APN\",\"internet.tele2.ru\"");
  SendATCommand("AT+SAPBR=3,1,\"USER\",\"tele2\"");
  SendATCommand("AT+SAPBR=3,1,\"PWD\",\"tele2\"");
  //SendATCommand( "AT+SAPBR=1,1");
  //SendATCommand("AT+HTTPINIT");
  delay(4000);
  SendATCommand("AT+HTTPPARA=\"CID\",1");
}

void ReadReg() {
  rs485.listen();  // Инициализация RS485 интерфейса
  int attempts = 3;
  while (attempts > 0) {
    int32_t regAI0 = modbus.inputRegisterRead(1, 0);
    int32_t regAI1 = modbus.inputRegisterRead(1, 1);
    int32_t regAI2 = modbus.inputRegisterRead(1, 2);

    if (regAI0 != -1 && regAI1 != -1 && regAI2 != -1) {
      Temp = float((float)(regAI0) / 10);
      Vel = float((float)(regAI1) / 10);
      Disp = float((float)(regAI2) / 10);
      GSMport.begin(9600);
      return;
    } else {
      Serial.println("Ошибка датчика");
      delay(100);
      attempts--;
    }
  }
  Serial.println("Не удалось прочитать данные с датчика после нескольких попыток");
}

void getSignalStrength() {
  GSMport.listen();
  Serial.println("Start func getSignalStrength");
  GSMport.println("AT+CSQ");
  delay(2000);
  String response = ReadGSM();
  int index = response.indexOf("+CSQ: ");
  Serial.println("got answer: " + response);
  if (index != -1) {
    int commaIndex = response.indexOf(",", index);
    if (commaIndex != -1) {
      lvl_gsm = response.substring(index + 6, commaIndex);
      Serial.println("getSignalStrength return " + lvl_gsm);
      rs485.begin(4800);
    }
  } else {
    Serial.println("getSignalStrength return error ");
  }
  // Ошибка при получении уровня сигнала
}

bool list_param(float data1, float data2, float data3, String& data4) {
  Serial.println("Start list param ");
  //Serial.println("Temp: " + data1);
  //Serial.println("Vel: " + data2);
  //Serial.println("Disp: " + data3);
  Serial.println("lvl_gsm: " + data4);
  return true;
}

String ReadGSM() {
  //Serial.println("Start ReadGSM func");
  GSMport.listen();
  int incomingByte;
  String response;
  while (GSMport.available()) {
    incomingByte = GSMport.read();
    response += char(incomingByte);
    //Serial.println("Response: " + response);
    delay(10);
  }
  //Serial.println("Finish ReadGSM loop");
  return response;
}

void SendATCommand(String comma) {
  GSMport.listen();
  GSMport.println(comma);
  delay(2000);
  Serial.println(ReadGSM());
}

Лог с UNO на чём обрывается ?

String, два SoftwareSerial - это прыжок в неизвестность.

2 лайка

HTTPINIT

OK

и больше ничего не выводится.

image

со String что не так?
Из-за фрагментации памяти?

Так сразу не скажешь. Пробуйте добавить более осмысленные отладочные сообщения и со счетчиками или выводом текущего миллис …
Надо понять на каком проходе/моменте это происходит и потом уже разбираться …

Ну, представьте, что модем полтора кило ответа выдал вот тут: String response = ReadGSM();

К тому же подобный код - это, чаще всего, выстрел в ногу, когда используешь SoftwareSerial:

GSMport.println(at_com);
delay(5000);
String response = ReadGSM();

UDP Нашел проблему в неправильно работающем MAX485. и заменил его. Остался вопрос по SIM900, сыпет 601 ошибками, как пофиксить не могу придумать.

601 ошибка. Проблему в самом модуле искать, или на стороне оператора? Если в самом модуле, что продиагностировать, наличие регистрации в сети?

а сервер не ваш?
мне не нравится последовательность отправляемых модему команд, я вот так использую:

Спойлер
  unitInetHTTP.unitAddCommand(cmdSendStrWaitRespNextCmd, (char *)"AT+SAPBR=2,1\r", 20000UL, (char *)"OK\r\n", 1, cmdGoNext);                                                                                                                     // get stat
  unitInetHTTP.unitAddCommand(cmdSendStrWaitTwoResp, (char *)"AT+HTTPINIT\r", 3000UL, (char *)"OK\r\n", 2, cmdGoNext, 0, (char *)"+CME ERROR:", cmdGoID, 10);                                                                                    // init
  unitInetHTTP.unitAddCommand(cmdSendStrWaitRespNextCmd, (char *)"AT+HTTPPARA=\"CID\",1\r", 3000UL, (char *)"OK\r\n", 3, cmdGoNext);                                                                                                             // cid
  unitInetHTTP.unitAddCommand(cmdSendStrWaitRespNextCmd, (char *)"AT+HTTPPARA=\"URL\",\"https://xxx.xx/test.php?n=AB021&p=asd123&t=30.23&b=89&lt=22.0211112&lg=33.977334&o=MegaFon&s=18\"\r", 3000UL, (char *)"OK\r\n", 4, cmdGoNext);  // url
  unitInetHTTP.unitAddCommand(cmdSendStrWaitRespNextCmd, (char *)"AT+HTTPSSL=1\r", 3000UL, (char *)"OK\r\n", 5, cmdGoNext);                                                                                                                      // ssl
  unitInetHTTP.unitAddCommand(cmdSendStrWaitRespNextCmd, (char *)"AT+HTTPPARA=\"CONTENT\",application/x-www-form-urlencoded\r", 3000UL, (char *)"OK\r\n", 6, cmdGoNext);                                                                         // content
  unitInetHTTP.unitAddCommand(cmdSendStrWaitRespNextCmd, (char *)"AT+HTTPACTION=0\r", 3000UL, (char *)"OK\r\n", 7, cmdGoNext);                                                                                                                   // action
  unitInetHTTP.unitAddCommand(cmdSendStrWaitRespNextCmd, (char *)"AT+HTTPREAD\r", 3000UL, (char *)"OK\r\n", 8, cmdGoNext);                                                                                                                       // read
  unitInetHTTP.unitAddCommand(cmdTypeJustResponse, NULL, 15000UL, (char *)"+HTTPACTION: 0,200,0\r\n", 9, cmdGoNext);                                                                                                                             // wait 200
  unitInetHTTP.unitAddCommand(cmdSendStrWaitRespNextCmd, (char *)"AT+HTTPTERM\r", 10000UL, (char *)"OK\r\n", 10, cmdGoNext);                                                                                                                     // term

Сервер наш) На нем штатно все отрабатывает. Заметил что команда SAPBR 1,1 переодически ERROR шлет, после ребута, и меняется на ОК только после перепрошивки.

Изучу ваш код, спасибо

В общем не получала симка IP адрес. Прикрутил проверки, пока полет нормальный. Всем спасибо!

Её паника одолевала или что?