ARDUINO Arduino Nano + SIM900 зависает

Gosu

✩✩✩✩✩✩✩
27 Июн 2024
8
0
Собрал Arduino Nano + SIM900 соединены rx tx и земля. Запрограммировал чтобы посылать команды Serial => Nano => Sim900 => Nano => Serial и считывать ответы на сервере. Как только подключаю к серверу (на Linux) то оно работает от часа до суток и зависает. Сначала подумал что наводки с проводов, тогда припаял к пинам здоровенные медные провода, но проблема никуда не делась, потом на сервере стал отслеживать зависания и просто перезапускать Serialport, какое-то время это работает, но в итоге через от дня до 4-х зависает наглухо и даже перезапуск Srialport не помогает. Запитано sim900 своим блоком питания, а Nano от usb порта.
Что это может быть? Наводки или програмный сбой?

main.cpp:
#include <Arduino.h>
#include <SoftwareSerial.h>

#define OS_BENCH    // дефайн до подключения либы
#include <GyverOS.h>
#include <GParser.h>
#include <../lib/Matcher.h>

GyverOS<2> OS;

SoftwareSerial gsm(2, 3); // RX-3; TX-2;

void taskGSM();
void taskSerial();

uint8_t simRequest;

uint32_t savedtime = 0;
bool lockSend = false;
bool startup = true;
bool needSend = false;

char gsmString[128];
char phoneNumber[13];
char msgToSend[64];

char at_cmgs[24] = "AT+CMGS=\"000000000000\"\r";
char call_atd[21] = "ATD + 000000000000;\r";
uint16_t i = 0;
int ms;


void setup() {
  gsm.begin(9600);
  Serial.begin(115200);
  Serial.setTimeout(250);

  Serial.println( "start" );

  OS.attach(0, taskSerial, 50);
  OS.attach(1, taskGSM, 50);

  lockSend = true;
  startup = true;
  simRequest = 0;
  gsm.println( "AT + CREG? \r" );
  delay(500);
}


void taskGSM() {
  if (gsm.available()) {
    Matcher mymatch( "+CMT:" );
    memset(gsmString, 0, (int)(sizeof gsmString));
    i = 0;
    while (gsm.available()) {
      char incoming = (char)gsm.read();
      delay(2);

      if ( i < 10 ) {
        mymatch.isnew( incoming );
      }

      if ( !mymatch.getMatched() ) {
        gsmString[i] = incoming;
      } else {
        Serial.print( incoming );
      }
      //Serial.print( incoming );
      i++;
    }
    //Serial.print( gsmString );
    if (mymatch.getMatched()) {
      Serial.print( "|;" );
      return;
    } else if ( simRequest == 2 && strstr(gsmString, ">") != NULL ) {
      gsm.println( msgToSend );
      delay(50);
      gsm.write(26);
      simRequest = 3;
      return;
    } else if ( strstr(gsmString, "OK") != NULL ) {
      switch (simRequest) {
        case 0:
          char str[4];
          strncpy(str, gsmString + 2 + strcspn(gsmString, ":"), 3);
          str[3] = 0;
          if ( strcmp(str, "0,1") == 0 || strcmp(str, "1,1") == 0 ) {
            if (needSend) {
              simRequest = 2;
              gsm.println( at_cmgs );
            } else if (startup) {
              simRequest = 1;
              startup = false;
              gsm.println( "AT + CMGF=1 \r" );
            }
          } else {
            simRequest = 0;
            gsm.println( "AT + CREG? \r" );
            delay(1000);
          }
        break;
        case 1:
          simRequest = 4;
          //lockSend = false;
          gsm.println( "AT + CNMI = 2,2,0,0,0 \r" );
        break;
        case 3:
          lockSend = false;
          needSend = false;
          simRequest = 5;
          Serial.println( "sended" );
        break;
        case 4:
          simRequest = 5;
          lockSend = false;
          Serial.println( "ready" );
        break;
        case 5:
          lockSend = false;
          Serial.print( "sr5||" );
          Serial.println( gsmString );
        break;
        default:
          lockSend = false;
        break;
      }
      //Serial.println( (String) "true" );

    } else if ( strstr(gsmString, "NO CARRIER") != NULL ) {
      Serial.print( "called" );
      lockSend = false;
      return;
    } else if ( strstr(gsmString, "ERROR") != NULL ) {
      // Ошибка
      if (needSend) {
        simRequest = 0;
        gsm.println( "AT + CREG? \r" );
      } else {
        Serial.print( "err||" );
        Serial.println( gsmString );
        lockSend = false;
      }
    }
  }
}


void taskSerial() {
  if (Serial.available()) {
    char serialString[64];
    int16_t amount = Serial.readBytes(serialString, 64);
    serialString[amount] = NULL;
    GParser data(serialString, '|');
    int8_t am = data.split();

    //Serial.println(data[0]);
    //Serial.println(data[1]);

    if (millis() - ms > 3000) {
      //Serial.println( "unlock" );
      lockSend = false;
    }

    if (lockSend ) {
      Serial.println( "locked" );
    } else if ( data.equals(0, "send") ) {
      needSend = true;
      lockSend = true;
      ms = millis();
      memset(phoneNumber, 0, (int)(sizeof phoneNumber));
      strcpy(phoneNumber, data[1]);

      memset(msgToSend, 0, (int)(sizeof msgToSend));
      strcpy(msgToSend, data[2]);

      strncpy( at_cmgs + 9, phoneNumber, 12 );

      simRequest = 2;
      gsm.println( at_cmgs );

    } else if ( data.equals(0, "at") ) {       
      simRequest = 5;
      lockSend = true;
      ms = millis();
      gsm.println( data[1] );

    } else if ( data.equals(0, "call") ) {
      lockSend = true;
      ms = millis();

      memset(phoneNumber, 0, (int)(sizeof phoneNumber));
      strcpy(phoneNumber, data[1]);

      strncpy( call_atd + 6, phoneNumber, 12 );
      
      gsm.println( call_atd );
    }
    //*/
  }
}

void loop() {
  OS.tick();
}
Matcher.h:
#include <Arduino.h>
class Matcher {
    private:
      const char * _match;
      uint16_t _i;
      uint16_t _max;
      bool _matched;
    public:
    Matcher(const char * match ) {
      _match = match;
      _matched = false;
      _max = strlen(_match);
      _i = 0;
    }
    char getChar(uint16_t n) {
      return _match[n];
    }
    bool isnew ( char c ) {
      if (c == _match[ _i ]) {
        _i++;
        if ( _i == _max) {
          _matched = true;
        }
      } else {
        _i = 0;
      }
      return getMatched();
    }
    bool getMatched() {
      return _matched;
    }
};
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
492
142
@Gosu,
Начать с очевидного.
> даже перезапуск Srialport не помогает.
Наверно у вас настроено так, что перезапуск Serialport должен формировать RESET для NANO силами USB-UART преобразователя.
Поэтому если он перестает помогать то
  • Или NANO зависла так, что ей не помогает RESET. Маловероятно, но проверить легко нажав RESET на NANO
  • Или м.с USB-UART зависла и не формирует сигнал RESET для NANO. Проверить можно отправив с ПК строку и посмотреть - моргает ли светодиод (Rx или TX на NANO они иногда по разному подписаны)
По результатам думать дальше.

Из замечаний по коду. Они могут и не быть причиной ошибки, если все это учтено.
  • Добавить в loop моргающий светодиод - для визуального контроля зависания NANO
  • serialString[amount] = NULL; может писать за границу массива, если amount = 64
  • gsm.begin(9600); Serial.begin(115200); В этом случае Serial может терять входные данные, если одновременно работает SoftSerial
 

Gosu

✩✩✩✩✩✩✩
27 Июн 2024
8
0
@Bruzzer, я легко отслеживаю зависания, тем что раз в 10 минут происходит опрос устройства с сервера на предмет подключения модуля SIM900 к GSM сети, и как только ответ не получен, значит зависло и мне сразу приходит сообщение в телегу и происходит перезагрузка порта. И если модуль завис не наглухо, то после перезагрузки он просто продолжает корректно работать и получать ответы, если же наглухо, то ответы не приходят и он начинает перезагружаться раз в 10 минут, а телега начинает заспамляться сообщениями об ошибке.

По коду попробую, просто проверка занимает часы и даже дни.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
492
142
Если ответ не получен, то может зависла не NANO а порт или программа на сервере или USB-UART на нано . На этапе поиска причин - моргающий встроенный диод, это просто и наглядно.