Поиск нужной строки при работе с Com портом

Pavel_1282
Offline
Зарегистрирован: 19.12.2012

Всем привет, работаю с GSM модулем SIM800L немного хочу доработать управляющую программу, чтобы была внешняя индикация его готовности (к примеру светодиодом) к работе.

Известно что запускается модуль командами в моем случае:

C++Выделить код
1
2
3
4
5
6
7
8
    SIM800.begin(9600);  // Скорость обмена данными с модемом
    SIM800.println("AT");
    SIM800.println("AT+CLIP=1");  //включаем АОН
    delay(100);
    SIM800.println("AT+CMGF=1");  //режим кодировки СМС - обычный (для англ.)
    delay(100);
    SIM800.println("AT+CSCS="GSM"");  //режим кодировки текста
    delay(100);

Если, после загрузки программы в МК смотреть в com порт то выдает он примерно вот такие значения:



AT

ОК

AT+CLIP=1

ОК

AT+CMGF=1

ОК



Это означает что модуль готов и можно работать с ним.

Я хочу дописать программу так что если в выведенных значениях есть "ОК" то идет нужное мне действие... 

Есть какой оператор который ищет в выведенных значениях в порт нужные данные ?

b707
Онлайн
Зарегистрирован: 26.05.2017

Pavel_1282 пишет:

Есть какой оператор который ищет в выведенных значениях в порт нужные данные ?

нет.

Надо сначала собрать из порта строчку символ за символом, а уже потом в этой строке искать, например функциями strstr() strtok() ( вариантов поиска много)

Upper
Offline
Зарегистрирован: 23.06.2020

Pavel_1282 пишет:

Есть какой оператор который ищет в выведенных значениях в порт нужные данные ?

Такая "встроенная" возможность есть, но не всегда ее удобно использовать, т.к. если ничего не найдет, будет ждать время заданное в setTimeout() и блокировать выполнение остальной программы. А если данные идут постоянно, но не содержат искомого, то будет блокировать пока идут данные т.к. Timeout сбрасывается при чтении каждого очередного символа. И оно только ищет и отбрасывает просмотренные данные.

Serial.find(target, length)

https://www.arduino.cc/reference/en/language/functions/communication/serial/find/

b707
Онлайн
Зарегистрирован: 26.05.2017

Upper пишет:

Такая "встроенная" возможность есть, но не всегда ее удобно использовать

Serial.find(target, length)

это не "возможность", а сплошная профанация, не надо такое новичкам советовать

Pyotr
Offline
Зарегистрирован: 12.03.2014

Вот такой функцией пользуюсь. Аналог find() , но не блокирует скетч. 

byte  isMarker (const char * marker){ // "OK\r\n" len=4
  static byte index = 0;
  byte len = 0;

  len = strlen(marker);
  while(esp8266.available()){
    byte c = esp8266.read ();
    if(index < len){
      if(c == marker[index]) index++; //
      else{ //не маркер
        index = 0;
        if(c == marker[index]) index++; //возможно снова начало маркера
      }
    }
    if(index == len){
      index = 0;
      return 1;
    }
  }
  return 0;
}

Вызывается так же

if(isMarker("OK")){ 
  //что-то делаем
}

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

b707 пишет:

Pavel_1282 пишет:

Есть какой оператор который ищет в выведенных значениях в порт нужные данные ?

нет.

Надо сначала собрать из порта строчку символ за символом, а уже потом в этой строке искать, например функциями strstr() strtok() ( вариантов поиска много)

По хорошему надо не накапливать в строке, тем более, если заранее неизвестно, какой длины может быть строка, а разбирать сразу - по приходу очередного символа.

Pavel_1282
Offline
Зарегистрирован: 19.12.2012

Upper пишет:

Pavel_1282 пишет:

Есть какой оператор который ищет в выведенных значениях в порт нужные данные ?

Такая "встроенная" возможность есть, но не всегда ее удобно использовать, т.к. если ничего не найдет, будет ждать время заданное в setTimeout() и блокировать выполнение остальной программы. А если данные идут постоянно, но не содержат искомого, то будет блокировать пока идут данные т.к. Timeout сбрасывается при чтении каждого очередного символа. И оно только ищет и отбрасывает просмотренные данные.

Serial.find(target, length)

https://www.arduino.cc/reference/en/language/functions/communication/serial/find/

Понял, но эта часть должна выполняться void setup() так что по идеи блокировать выполнение основной программы не должно

Pavel_1282
Offline
Зарегистрирован: 19.12.2012

Pyotr пишет:

Вот такой функцией пользуюсь. Аналог find() , но не блокирует скетч. 

Спасибо буду пробовать

Pavel_1282
Offline
Зарегистрирован: 19.12.2012

Пробовал через Serial.find(target, length) она ищет нужное значение или строку, но когда вручную вводишь его через терминал, если же вывод значений в послед порт указан в коде, то не может найти нужного .

Если через if(isMarker(""так вообще такого оператора нет, может дополнительные библиотеки нужно подключать. 

 

b707
Онлайн
Зарегистрирован: 26.05.2017

Pavel_1282 пишет:

Если через if(isMarker(""так вообще такого оператора нет, может дополнительные библиотеки нужно подключать. 

 

пипец.... Вы язык Си знаете вообще? Вам исходный код "этого оператора" в сообщении #4 зачем дали, как вы думаете?

Pyotr
Offline
Зарегистрирован: 12.03.2014

Pavel_1282 пишет:

Если через if(isMarker(""так вообще такого оператора нет, может дополнительные библиотеки нужно подключать. 

 

Понимаю... Даже скетч не буду просить показать. Могу дать пример работы с АТ командами с ESP8266 запрос-ответ без блокировки скетча и с таймаутом. Надо?

Pavel_1282
Offline
Зарегистрирован: 19.12.2012

[/quote]

Понимаю... Даже скетч не буду просить показать. Могу дать пример работы с АТ командами с ESP8266 запрос-ответ без блокировки скетча и с таймаутом. Надо?

[/quote]

Хорошо, давайте

Pyotr
Offline
Зарегистрирован: 12.03.2014

SIM800 у меня нет под рукой, а ESP8266 подключена к меге. Для нее и будет пример.
При включении ESP ждет 5 сек и подключается к точке доступа на смартфоне. Если ESP не отвечает на команды, то происходит аппаратная перезагрузка модуля. Если точка доступа отключена, ESP пытается подключиться каждые 15 сек. После подключения к точке доступа, больше ничего не происходит- это просто пример. Все это происходит в фоновом режиме. Подредактируйте под свои задачи.

#define DEBUG 1  //закомментировать эту строку, если не нужна отладка
#ifdef DEBUG
#define DEBUG_BEGIN(x)     Serial.begin(x)
#define DEBUG_PRINT(x)     Serial.print(x)
#define DEBUG_PRINTLN(x)   Serial.println(x)
#else
#define DEBUG_BEGIN(x) 
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif 
#define PIN_HARDRESET_ESP 7
uint32_t currMillis, startTimeOut, timeDelayEspMs, timeOutMs;

enum {RESET_START, RESET_END, POWER_ON,//команда, ответ
      AT_TEST, AT_TEST_REPLY,  // AT, OK
      AT_CWMODE, AT_CWMODE_REPLY, //AT+CWMODE=1, OK
      CONNECT_TO_WIFI, CONNECT_TO_WIFI_REPLY,//"AT+CWJAP=\"Redmi Note 9\",\"123456789\" , OK
      STOP_ESP
     };
byte automataStatesEsp = POWER_ON;

void setup() {
 Serial1.begin(115200);
  DEBUG_BEGIN(115200);
  digitalWrite(PIN_HARDRESET_ESP, HIGH);
}

void loop() {
  currMillis = millis();
  runAutomataEsp();  
}
//////////////////////////////////////////////////////////
void runAutomataEsp() {
  switch (automataStatesEsp) {
    case RESET_START: //
      digitalWrite(PIN_HARDRESET_ESP, LOW);
      pinMode(PIN_HARDRESET_ESP, OUTPUT);
      setTimeOutForNextStep(200, RESET_END);
      DEBUG_PRINTLN(F("RESET_START"));
      break;
    case RESET_END:
      if (isTimeOutElapsed()) {
        pinMode(PIN_HARDRESET_ESP, INPUT);
        digitalWrite(PIN_HARDRESET_ESP, HIGH);
        automataStatesEsp = POWER_ON;
        DEBUG_PRINTLN(F("RESET_END"));
      }
      break; 
         
    case POWER_ON: //после подачи питания ждем 5 сек и отправляем команду "АТ"
      setTimeOutForNextStep(5000, AT_TEST);
      DEBUG_PRINTLN(F("POWER_ON"));
      break;
      
    case AT_TEST:
      if(isTimeOutElapsed()) {
        clearInputBuff();
        Serial1.println(F("AT"));
        //После команды "АТ" устанавливаем таймаут=1 сек и переходим на след.шаг
        setTimeOutForNextStep(1000, AT_TEST_REPLY);
        DEBUG_PRINTLN(F("AT_TEST"));
      }
      break;
    case AT_TEST_REPLY:
      if(isTimeOutElapsed()){//если ESP не отвечает, то перезагружаем
        automataStatesEsp = RESET_START; //без задержки на следующий шаг
      }
      else if (Serial1.available() > 0 && isMarker("OK")){
        setTimeOutForNextStep(200, AT_CWMODE);
        DEBUG_PRINTLN(F("AT_TEST_REPLY"));
      }      
      break;
      
    case AT_CWMODE:
      if (isTimeOutElapsed()) {
        clearInputBuff();
        Serial1.println(F("AT+CWMODE=1"));
        setTimeOutForNextStep(500, AT_CWMODE_REPLY);
        DEBUG_PRINTLN(F("AT_CWMODE=1"));
      }
      break;
    case AT_CWMODE_REPLY:
      if(isTimeOutElapsed())  setTimeOutForNextStep(200, AT_TEST); 
      else  if(Serial1.available() > 0 && isMarker("OK")) {
        setTimeOutForNextStep(300, CONNECT_TO_WIFI);
        DEBUG_PRINTLN(F("AT_CWMODE_REPLY_OK"));
      }
      break;
            
    case CONNECT_TO_WIFI:
      if (isTimeOutElapsed()) {
        clearInputBuff();
        Serial1.println(F("AT+CWJAP=\"Redmi Note 9\",\"don198753\""));
        setTimeOutForNextStep(15000, CONNECT_TO_WIFI_REPLY);
        DEBUG_PRINTLN(F("AT+CWJAP=\"Redmi Note 9\",\"don198753\""));
      }
      break;
    case CONNECT_TO_WIFI_REPLY:
      if(isTimeOutElapsed())  setTimeOutForNextStep(100, AT_TEST); 
      else  if (Serial1.available() > 0 && isMarker("OK")) { 
        automataStatesEsp = STOP_ESP;
        DEBUG_PRINTLN(F("CONNECT_TO_WIFI_OK"));
        
      }    
      break;

    default:
      automataStatesEsp = STOP_ESP;
  }
}
// Очищаем приемный буфер. (для данного примера буфер можно не чистить)
void clearInputBuff(){
  while (Serial.available() > 0) { Serial.read(); }
}
//==================
byte  isMarker (const char * marker){ 
  static byte index = 0;
  byte len = 0;

  len = strlen(marker);
  while(Serial1.available()){
    byte c = Serial1.read ();
    if(index < len){
      if(c == marker[index]) index++; 
      else{ //не маркер
        index = 0;
        if(c == marker[index]) index++; //возможно снова начало маркера
      }
    }
    if(index == len){
      index = 0;
      return 1;
    }
  }
  return 0;
}
//===========================
void setTimeOutForNextStep(word ms, byte nextStep){
  setTimeOut(ms);
  automataStatesEsp = nextStep;
}
//====================== 
inline void setTimeOut(uint32_t ms) {
  startTimeOut = millis();
  timeOutMs = ms;
}
//==================
inline void stopTimeOut() {
  timeOutMs = 0xFFFFFFFF; 
}
//==================  таймер для таимаута
bool isTimeOutElapsed() {
  if (currMillis - startTimeOut > timeOutMs) {
    stopTimeOut();
    return 1;
  }
  return 0;
}

 

Pavel_1282
Offline
Зарегистрирован: 19.12.2012

Спасибо!