Алгоритм настройки модуля SIM800L

Здравствуйте.
Было времечко на работе, решила написать код настройки модема.
Перезагрузка пока-что программная, потом будет сброс питания.
SoftwareSerial исчезнет, отладочные сообщения уберутся.
Решила совместить проверку наличия сети с проверкой ответа модуля на команды (таймаут)

Спойлер
#include <avr/wdt.h>
#include <SoftwareSerial.h>
SoftwareSerial SIM800(9, 2);

#define MAX_BUF 50 //Размер буфера
#define INT_NET_FOUND 5000 //Интервал проверки сети если сеть найдена
#define INT_NET_NOT_FOUND 3000//Интервал проверки сети если сеть не найдена
#define TIMEOUT_TIME 3000 //Время наступления таймаута
#define MAX_NUM_TIMEOUT_ERR 2 //Максимальное количество ошибок таймаута
#define MAX_NUM_NET_ERR  5 //Максимальное количество ошибок поиска сети
#define MODEM_CONF_COMMAND_INT 1000 //Интервал отправки команд настройки модема

#define MODEM_NOT_CONF 0 //Модем не настроен
#define MODEM_CONF_ROGRESS 1 //Идёт настройка модема
#define MODEM_CONF 2 //Модем настроен

uint8_t amount_command; // Количество команд первоначальной настройки модема

//Команды для первоначальной настройки модема
char *conf_commands[]  = {
  "ATE1",//0---Включить эхо.
  "ATV1",//1---Полные заголовки и текстовые овтеты.
  "AT+CLIP=1",//2--- // Включить АОН.
  "AT+CMGF=1",//3---Включить TextMode для SMS.
  "AT+CPBS=\"SM\"",//4---Память SIM-карты.
};
//Команды для первоначальной настройки модема


void setup() {
  wdt_disable();
  Serial.begin(9600);
  SIM800.begin(9600);
  Serial.println(F("Start!"));
  SIM800.println(F("AT"));
  amount_command = sizeof(conf_commands) / sizeof(conf_commands[0]);
  wdt_enable (WDTO_4S);
}


void loop() {
  wdt_reset();

  static uint8_t pos_buf;//Позиция в буфере
  static char buffers[MAX_BUF];//Буфер

  static uint32_t modem_setup_tmr;//Таймер настройки модема
  static uint16_t modem_setup_int = INT_NET_NOT_FOUND;//Интервал настройки модема
  static uint8_t modem_setup_step;//Этап настройки модема
  static uint8_t timeout_err_count;//Счётчик ошибок таймаута
  static uint8_t net_err_count;//Счётчик ошибок поиска сети
  static uint8_t initial_modem_setup; //Начальная настройка модема
  static uint8_t command_number; //Номер команды настройка модема
  static bool response_number;



  switch (modem_setup_step) {

    case 0://Проверяю наличие сети
      if (millis() - modem_setup_tmr >= modem_setup_int) {
        modem_setup_tmr = millis();
        modem_setup_step = 1;
        SIM800.println(F("AT+CCALR?"));

        Serial.print(F("Net_check. Time: "));
        Serial.print(millis());
        Serial.print(F(" Interval: "));
        Serial.print(modem_setup_int);
        Serial.println("");
      }
      break;

    case 1://Если нет ответа в течении TIMEOUT_TIME, значит ошибка таймаут
      if (millis() - modem_setup_tmr >= TIMEOUT_TIME) {
        modem_setup_tmr = millis();
        modem_setup_step = 0;
        modem_setup_int = INT_NET_NOT_FOUND;
        timeout_err_count++;

        if (initial_modem_setup == MODEM_CONF_ROGRESS) {
          initial_modem_setup = MODEM_NOT_CONF;
          command_number = 0;
        }

        Serial.print(F("Timeout. Time: "));
        Serial.print(millis());
        Serial.print(F(" Error: "));
        Serial.print(timeout_err_count);
        Serial.println("");
      }
      break;


    case 2://Сеть найдена
      modem_setup_step = 4;
      net_err_count = 0;
      modem_setup_int = INT_NET_FOUND;
      Serial.println(F("Network_found:"));

      //Если сеть найдена и модем не настроен
      if (initial_modem_setup == MODEM_NOT_CONF) {
        initial_modem_setup = MODEM_CONF_ROGRESS;
        modem_setup_tmr = millis();
        modem_setup_step = 5;
        Serial.println(F("Initial_modem_setup:"));
      }


      break;

    case 3://Сеть не найдена
      modem_setup_step = 4;
      net_err_count++;
      modem_setup_int = INT_NET_NOT_FOUND;

      Serial.print(F("Network_non_found. Error"));
      Serial.print(net_err_count);
      Serial.println("");
      break;

    case 4://Если ответ пришёл раньше чем TIMEOUT_TIME
      modem_setup_tmr = millis();
      modem_setup_step = 0;
      timeout_err_count = 0;
      break;



    case 5://Настройка модема
      if (millis() - modem_setup_tmr >= MODEM_CONF_COMMAND_INT) {
        modem_setup_tmr = millis();
        modem_setup_step = 1;
        response_number = false;
        SIM800.println(conf_commands[command_number]);

        Serial.print(conf_commands[command_number]);
        Serial.print(F(" Timer: "));
        Serial.print(millis());
        Serial.println("");
      }
      break;

    case 6://Если команда настройки модема выполнена
      Serial.print(conf_commands[command_number]);
      Serial.print(F(" --- OK"));
      Serial.println("");
      command_number++;

      if (command_number > amount_command - 1) {
        Serial.println(F("Modem_setup_OK"));
        modem_setup_tmr = millis();
        modem_setup_step = 0;
        initial_modem_setup = MODEM_CONF;
      } else {
        modem_setup_tmr = millis();
        modem_setup_step = 5;
      }
      break;



  }//switch(check_step)


  //Если предел ошибок таймаута или сети, перезагрузка модема
  if (timeout_err_count > MAX_NUM_TIMEOUT_ERR || net_err_count > MAX_NUM_NET_ERR) {
    SIM800.println(F("AT+CFUN=1,1"));
    timeout_err_count = 0;
    net_err_count = 0;
    modem_setup_step = 0;
    initial_modem_setup = MODEM_NOT_CONF;
    modem_setup_tmr = millis();
    command_number = 0;
    Serial.println(F("Modem_reset:"));
  }



  if (Serial.available())SIM800.write(Serial.read());

  if (SIM800.available()) {
    uint8_t temp = SIM800.read();

    if (temp) {
      buffers[pos_buf] = temp;
      pos_buf++;
      if (pos_buf >= MAX_BUF) {
        memset(buffers, 0, MAX_BUF);
        pos_buf = 0;
      } else {
        if (temp == '\n' && pos_buf > 1 && buffers[pos_buf - 2] == '\r') {

          if (modem_setup_step == 1) {

            if (strstr (buffers, "+CCALR: 1") != NULL)modem_setup_step = 2;
            if (strstr (buffers, "+CCALR: 0") != NULL)modem_setup_step = 3;

            if (!response_number && strstr (buffers, conf_commands[command_number]) != NULL)response_number = true;
            if (response_number && strstr (buffers, "OK") != NULL) modem_setup_step = 6;

          }



          //Serial.println(buffers);

          memset(buffers, 0, MAX_BUF);
          pos_buf = 0;

        }//if(temp
      }//if(pos_buf >= MAX_BUF) {
    }//if(temp) {
  }//if(SIM800.available()){



}//loop

Пинайте :grinning:

Зачем?
Работает? Нехай себе работает дальше.

1 лайк

Работает.
Ну как зачем, вот ту ты могла - бы сделать так. потому что целесообразнее… ну и что - то такое)))

Ну… 13-15 можно описать через enum.

Функция loop - 178 строк!

Никак нельзя логические блоки отдельными функциями выстроить?

2 лайка

Я ещё и по разным файлам распихиваю…

Спасибо. Обновляюсь)
Ни разу не пробовала раскидывать функции по файлам, получаю ошибку:

Спойлер

Файл SIM800L.ino

#include <avr/wdt.h>
#include <SoftwareSerial.h>
SoftwareSerial SIM800(9, 2);

void setup() {
  wdt_disable();
  Serial.begin(9600);
  SIM800.begin(9600);
  Serial.println(F("Start!"));
  SIM800.println(F("AT"));
  wdt_enable (WDTO_4S);
}


void loop() {
  wdt_reset();

  if (Serial.available())SIM800.write(Serial.read());

  //if (SIM800.available()) modem_reading(SIM800.read());


  modem_setup();



}//loop

Файл modem_setup.ino

void modem_setup(uint8_t parametr = 0) {



}

Если void modem_setup(uint8_t parametr = 0) Получаю ошибку
если void modem_setup() Ошибки нет

F:\Users\Iren\Documents\Arduino\SIM800L\SIM800L.ino: In function 'void loop()':
SIM800L:23:3: error: 'modem_setup' was not declared in this scope
   modem_setup();
   ^~~~~~~~~~~
F:\Users\Iren\Documents\Arduino\SIM800L\SIM800L.ino:23:3: note: suggested alternative: 'memset'
   modem_setup();
   ^~~~~~~~~~~
   memset
exit status 1
'modem_setup' was not declared in this scope

Я не понял - как именно Ардуино ИДЕ связывает ино-файлы. Поэтому я создаю файлы с расширением .h в той же папке и подключаю в основном ино-файле. (Закрой ИДЕ, создай файлы .h и открой ино-файл. Файлы .h «подтянутся» автоматом).

Может быть так делать и «не правильно», но я делаю и никаких проблем у меня с этим нет. По крайней мере я точно знаю где что подключено.

Основной скетч

Спойлер
#include <avr/wdt.h>
#include <SoftwareSerial.h>
SoftwareSerial SIM800(9, 2);

#define MAX_BUF 50
#define INT_NET_NOT_FOUND 3000
#define INT_NET_FOUND 5000
#define TIMEOUT_TIME 3000
#define MAX_NUM_TIMEOUT_ERR 2 //Максимальное количество ошибок таймаута
#define MAX_NUM_NET_ERR  5 //Максимальное количество ошибок поиска сети
#define MODEM_CONF_COMMAND_INT 1000

bool response_status;
uint8_t command_number;
uint8_t step_setup;
uint8_t amount_command;

enum {
  NOT_CONFIGURED,
  PROGRESS,
  CONFIGURED,
} modem_setup_status;

char *conf_commands[]  = {
  "ATE1",//0---Включить эхо.
  "ATV1",//1---Полные заголовки и текстовые овтеты.
  "AT+CLIP=1",//2--- // Включить АОН.
  "AT+CMGF=1",//3---Включить TextMode для SMS.
  "AT+CPBS=\"SM\"",//4---Память SIM-карты.
};

void setup() {
  wdt_disable();
  Serial.begin(9600);
  SIM800.begin(9600);
  Serial.println(F("Start!"));
  SIM800.println(F("AT"));
  amount_command = sizeof(conf_commands) / sizeof(conf_commands[0]);
  wdt_enable (WDTO_4S);
}

#include "modem_setup.h"
#include "modem_reading.h"


void loop() {
  wdt_reset();

  if (Serial.available())SIM800.write(Serial.read());

  if (SIM800.available()) modem_reading(SIM800.read());
  modem_setup();



}

modem_setup.h

Спойлер
void modem_setup(uint8_t parametr = 0) {

  static uint32_t check_tmr;
  static uint16_t check_int = INT_NET_NOT_FOUND;
  static uint8_t timeout_err_count;
  static uint8_t net_err_count;

  if (parametr > 0)step_setup = parametr;

  switch (step_setup) {

    case 0:
      if (millis() - check_tmr >= check_int) {
        check_tmr = millis();
        step_setup = 1;
        SIM800.println(F("AT+CCALR?"));

        Serial.print(F("Net_check. Time: "));
        Serial.print(millis());
        Serial.print(F(" Interval: "));
        Serial.print(check_int);
        Serial.println("");
      }
      break;

    case 1:
      if (millis() - check_tmr >= TIMEOUT_TIME) {
        check_tmr = millis();
        step_setup = 0;
        timeout_err_count++;
        check_int = INT_NET_NOT_FOUND;

        if (modem_setup_status == PROGRESS) {
          modem_setup_status = NOT_CONFIGURED;
          command_number = 0;
        }

        Serial.print(F("Timeout. Time: "));
        Serial.print(millis());
        Serial.print(F(" Error: "));
        Serial.print(timeout_err_count);
        Serial.println("");
      }
      break;

    case 2:
      step_setup = 4;
      net_err_count = 0;
      check_int = INT_NET_FOUND;
      Serial.println(F("Network_found:"));

      if (modem_setup_status == NOT_CONFIGURED) {
        modem_setup_status = PROGRESS;
        Serial.println(F("Modem_setup_start"));
        step_setup = 5;
        check_tmr = millis();
      }
      break;

    case 3:
      step_setup = 4;
      net_err_count++;
      check_int = INT_NET_NOT_FOUND;
      Serial.print(F("Network_non_found. Error"));
      Serial.print(net_err_count);
      Serial.println("");
      break;

    case 4:
      check_tmr = millis();
      step_setup = 0;
      timeout_err_count = 0;
      break;

    case 5:
      if (millis() - check_tmr >= MODEM_CONF_COMMAND_INT) {
        check_tmr = millis();
        step_setup = 1;
        response_status = false;
        SIM800.println(conf_commands[command_number]);

        Serial.print(conf_commands[command_number]);
        Serial.print(F(" Timer: "));
        Serial.print(millis());
        Serial.println("");
      }
      break;

    case 6:
      Serial.print(conf_commands[command_number]);
      Serial.print(F(" --- OK"));
      Serial.println("");

      command_number++;

      if (command_number > amount_command - 1) {
        Serial.println(F("Modem_setup_OK"));
        check_tmr = millis();
        step_setup = 0;
        command_number = 0;
        modem_setup_status = CONFIGURED;
      } else {
        check_tmr = millis();
        step_setup = 5;
      }
      break;


  } //switch (step_setup) {


  if (timeout_err_count >= MAX_NUM_TIMEOUT_ERR || net_err_count >= MAX_NUM_NET_ERR) {
    //SIM800.println(F("AT+CFUN=1,1"));
    timeout_err_count = 0;
    net_err_count = 0;
    step_setup = 0;
    command_number = 0;
    modem_setup_status = NOT_CONFIGURED;
    check_tmr = millis();
    Serial.println(F("Modem_reset:"));
  }


}//void modem_setup

modem_reading.h

Спойлер
void modem_reading(uint8_t temp) {

  static uint8_t pos_buf;
  static char buffers[MAX_BUF];

  if (temp) {
    buffers[pos_buf] = temp;
    pos_buf++;
    if (pos_buf >= MAX_BUF) {
      memset(buffers, 0, MAX_BUF);
      pos_buf = 0;
    } else {
      if (temp == '\n' && pos_buf > 1 && buffers[pos_buf - 2] == '\r') {


        if (step_setup == 1) {

          if (strstr (buffers, "+CCALR: 1") != NULL)modem_setup(2);
          if (strstr (buffers, "+CCALR: 0") != NULL)modem_setup(3);

          if (modem_setup_status == PROGRESS) {
            if (!response_status && strstr (buffers, conf_commands[command_number]) != NULL)response_status = true;
            if (response_status && strstr (buffers, "OK") != NULL) modem_setup(6);
          }

        }// if (step_setup == 1) {



        //Serial.println(buffers);

        memset(buffers, 0, MAX_BUF);
        pos_buf = 0;

      }//if(temp
    }//if(pos_buf >= MAX_BUF) {
  }//if(temp) {

}

Пришлось несколько переменных сделать глобальными, enum удобно.

как раз наоборот, посмотри к примеру K3NG контроллер поворотки

А то! ))

я бы обертку испрользовал, коли планируете дальше перевести на хардовый сериал, тогда всего одну строчку чуток поправить всё остальное не трогая

#include <SomeSerial.h>
//SomeSerial SIM800(9, 2);
//SomeSerial SIM800(&Serial);
SomeSerial SIM800(&Serial1);
//SomeSerial SIM800(&Serial3);

Основная проблема, это логика обработки данных от модема, вы ждёте \rn последовательность, после чего обрабатываете данные. В общем путь правильный, но например представьте что OKrn пришло в последние байты буфера, а он у вас переполнился, O пришло, а остальное нет.
Или буфер кольцевым делать или размером килобайт или больше.

Нет, вопрос не в том, как это должно выглядеть в конце, а в том, как этого добиться наиболее рациональным образом.
Последовательность “закрыть IDE, насоздавать .h/.cpp файлов, открыть IDE” действительно выглядит немного странно.

смысл? это можно делать прямо в IDE

SIM800

С этим я не разобралась.

Ну да.
Сейчас посмотрел: кнопка список вкладок → новая вкладка…
А так - делал так же, как и BOOM: “закрыть-создать-открыть”.

ты меня очень сильно удивил )))

Кто бы говорил ))))
Когда я впервые так попробовал - у меня ino файл создался. Я тогда не стал сильно «морочиться» и стал делать как выше описал.

ну так расширение надо задавать,по умолчанию будет ino…