Подключение модуля gsm/gprs a6 (расширенная версия) к Arduino UNO R3

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Homo Faber пишет:

где я опять накосячил?

практически везде.

write и read команды оперируют одним байтом, зачем в init 52 и 55 строка вообще не понятно

зачем ставить скорость 115200 а потом 9600, что  за извращение

какими командами и как инициализироват модем А6 уже писалось

светодиод загорается но не видно где он должен гаснуть

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

http://codius.ru/articles/GSM_%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C_SIM800L_%D1%87%D0%B0%D1%81%D1%82%D1%8C_1

 

Homo Faber
Offline
Зарегистрирован: 25.05.2019

Прочёл, проникся, исправил. Вот новый код и ответ на него.

#include <SoftwareSerial.h>

// 8 - RX Arduino (TX GSM_A6), 9 - TX Arduino (RX GSM_A6)
SoftwareSerial GSM_A6(8, 9);// 8 - RX Arduino (TX GSM_A6), 9 - TX Arduino (RX GSM_A6)

unsigned long current_millis=millis();
int ch = 0;
int LedG = 4;                                 // Пин для зелёного светодиода
int LedR = 7;                                 // Пин для красного светодиода
String val = "";
byte Flag=false;

void setup()
{
  pinMode(LedG, OUTPUT);
  digitalWrite(LedG, LOW);                    // Зелёный светодиод ВЫКЛ
  pinMode(LedR, OUTPUT);
  digitalWrite(LedR, LOW);                    // Красный светодиод ВЫКЛ
  Serial.begin(9600);                         // Скорость обмена данными с компьютером
  Serial.println("Start!");
  GSM_A6.println("AT+IPR=9600");
  GSM_A6.begin(9600);                         // Скорость обмена данными с модемом 9600
  initModem();
}

void loop() {
  if (GSM_A6.available())                     // Ожидаем прихода данных (ответа) от модема...
     {
      Serial.write(GSM_A6.read());            // ...и выводим их в Serial
     }
  if (Serial.available())                     // Ожидаем команды по Serial...
     {
      GSM_A6.write(Serial.read());          // ...и отправляем полученную команду модему
     }
}

void initModem()
{
  while ((millis() - current_millis) <= 5000UL)
        {
         GSM_A6.println("AT");                // Посылаем команду АТ
         delay(1000);
// Контроль ответа ОК
         val="";
         while (GSM_A6.available())
               {
                ch = GSM_A6.read();
                val += char(ch);              // Сохраняем входную строку в переменную val
                delay(10);
                if (val.indexOf("OK"))
                   {
                    Serial.println("LedG");
                    digitalWrite(LedG, HIGH); // Зелёный светодиод ВКЛ
                    Flag=true;
                    break;
                   }
               }
         if (Flag) break;      
        }
  GSM_A6.println("AT+IPR?");                  // Посылаем запрос о скорости соединения
// Контроль скорости 9600
  val="";
  while (GSM_A6.available())
        {
         ch = GSM_A6.read();
         val += char(ch);                     // Сохраняем входную строку в переменную val
         delay(10);
         if (val.indexOf("9600"))
            {
             Serial.println("LedR");
             digitalWrite(LedR, HIGH);        // Красный светодиод ВКЛ
             break;
            }
        }
  delay(1000);
  GSM_A6.println("ATI");                      // Посылаем запрос о версии модуля
}

А вот ответ.

Start!
LedG
LedR
 
 
OK
AT+IPR?
 
+IPR: 9600
 
OK
ATI
 
Ai Thinker Co.LTD
A6 
V03.03.20161229019H03
 
OK
 
Чего я не могу понять, так это почему мои сообщения "LedG" и "LedR" (и соответсвенно включаются светодиоды) выводятся раньше ответа модема? И почему на мой запрос "АТ" всё также приходит ответ в виде набора чисел? Ведь эту часть я срисовал с http://codius.ru/articles/GSM_модуль_SIM800L_часть_1.
До SMS надеюсь когда-нибудь таки дойду...
Homo Faber
Offline
Зарегистрирован: 25.05.2019

Честно говоря я что-то не понял. После очередного запуска модем стал отвечать эхом, то есть что я посылаю, то и получаю в ответ. Но только на команды введённые через монитор порта.

Примерно так.

Start!
LedG
LedR
 
 
OK
AT+IPR?
 
+IPR: 9600
 
OK
ATI
 
Ai Thinker Co.LTD
A6 
V03.03.20161229019H03
 
OK
AT
AT+IPR?
ATI
 
Дал команды сответственно "AT", "AT+IPR?" и "ATI" и получил из же в ответ. На Arduino явственно перемигиваются светодиоды TX и RX в момент передачи команды иполучения ответа. Что бы это значило?
Мой чайник скоро закипит, но не от удачной работы, а от непонимания...
andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Про автоответ это банально - есть команда модема которая отключает автоответ - нагуглите легко.
По поводу остального - у вас логика программы страдает, вы выводите сообщения до того как вывод ответа, да и вообще все криво.
У вас как вообще с программированием?
Т е вам надо взять в толк что работает все последовательно, необходимо в loop разделять режимы работы программы и в зависимости от это этого выводить сообщения. Куча примеров на форуме....

Homo Faber
Offline
Зарегистрирован: 25.05.2019

"АТЕ0" пробовал - не помогло, просто никакого ответа. Программированием занимаюсь профессионально, около 30 лет. На логику никто не жаловался. С языком СОСИ++ связался впервые. Настолько идиотские конструкции, что поневоле принимаешь за правду то, что он был придуман как пример языка с невозможными конструкциями, в качестве первоапрельской шутки студентами МТИ. Почему-то очень понравился профессору. С этого момента и началось шествие С по умам программистов.
По поводу последовательности команд. Если я подав команду "АТ" дожидаюсь ответа модема "ОК" и ТОЛЬКО ПОСЛЕ ЭТОГО вывожу "LedG" и включаю зелёный светодиод, затем подаю команду "AT+IPR?", дожидаюсь ответа "+IPR: 9600" и ТОЛЬКО ПОСЛЕ ЭТОГО вывожу "LedR" и включаю красный светодиод. В чём отсутствие логики?
Кину ещё один камень в огород С. Хреново работать со строками. Нет элементарных функций наподобие LEFT(), RIGHT() для выделения определённого количества символов из строки. Пытался подключить "STRING.H", "CSTRING.H", меняне поняли ;). Получилответ,что библиотеки не подходят. Можете что-либо посоветовать?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Homo Faber пишет:

................................ Программированием занимаюсь профессионально, около 30 лет. На логику никто не жаловался. .......................................................
Кину ещё один камень в огород С. ..........................................

че то не вяжеться, тут частенько приходят супер программисты, а примитивного сделать не могут :(

ЗЫ. Извините, но я уйду с этой темы. Еслиб у Вас было желание разобраться - давно бы уже кучу примеров разобрали.

P.P.S. Не хвалюсь - просто констатация факта, ни капли не программист, работаю поверхностностно с: Ассемблер,C,Pascal,PHP,C++ ну ни разу не было желания поругаться на язык, это всего лишь инструмент, который надо учить.

Homo Faber
Offline
Зарегистрирован: 25.05.2019

И всё-таки я его добил. И он подчинился...

Вот скетч, там много всяких, возможно ненужных наворотов, но, по-моему, важен принцип - работает устойчиво.

#include <SoftwareSerial.h>                                         // Библиотека програмной реализации обмена по UART-протоколу
SoftwareSerial GSM_A6(8, 9);                                        // 8 - RX, 9 - TX

int Pins[4] = {2, 4, 7, 12};                                        // Пины с подключенными светодиодами
int Zvuk=3;                                                         // Пин зуммера
bool CorrFlg;                                                       // Флаг корректного завершения
bool CorrTlf;                                                       // Признака вхождения номера телефона в БЕЛЫЙ СПИСОК
String Mdm_Rsp = "";                                                // Переменная для хранения ответа модуля
long Upd_Lst = millis();                                            // Время последнего обновления
long Upd_Prd = 60000;                                               // Проверять каждую минуту
int Cnt=0;                                                          // Счётчик на все случаи жизни
int LED_Ctrl=0;                                                     // Контроль включения светодиодов

// БЕЛЫЙ СПИСОК телефонов в виде массива строк, с ОБЯЗАТЕЛЬНЫМ(!) "End" в конце списка
char* Ph_Nums[] = {"+7922*******", "+7919*******", "+7919*******", "+7982*******", "End"};

void setup()
{
  delay(10000);                                                     // Задержка 10 секунд перед запуском программы
  for (Cnt = 0; Cnt < 4; Cnt++)
      {
       pinMode(Pins[Cnt], OUTPUT);                                  // Настраиваем пины в OUTPUT
      }
  GSM_A6.begin(9600);                                               // Скорость обмена данными с модемом
  Send_AT_Cmd("AT", true);                                          // Отправка AT для настройки скорости обмена данными
  Send_AT_Cmd("AT+CMGD=1,4", true);                                 // Удаляем все сообщения, чтобы не забивали SIM-карту
  Send_AT_Cmd("AT+CLIP=1", true);                                   // Включаем АОН
  Send_AT_Cmd("ATE0;&W", true);                                     // Выключаем эхо-режим и сразу сохраняем значение (AT&W)!
  Send_AT_Cmd("AT+CMGF=1;&W", true);                                // Включаем текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
  String M_R=Send_AT_Cmd("AT+IPR?", true);                          // Запрос скорости обмена с модемом
  if (M_R.indexOf("9600"))                                          // Контроль скорости обмена с модемом
     {
      digitalWrite(12, HIGH);                                       // Индикация нормальной связи с модемом
     }
  Send_AT_Cmd("AT+CPMS=\"SM\",\"SM\",\"SM\"", true);                // Команда распределения памяти (хранить SMS сообщения в памяти SIM-карты)
  Upd_Lst = millis();                                               // Обнуляем таймер
}

// Основная программа
void loop()
{
  if (GSM_A6.available())                                           // Если у модема есть что сказать
     {
      Mdm_Rsp = Wait_Rsp();                                         // Получаем ответ от модема для анализа
      Mdm_Rsp.trim();                                               // Убираем лишние пробелы в начале и конце
      if (Mdm_Rsp.startsWith("+CIEV:"))                             // Пришло сообщение о получении SMS
         {
          RazborSMS(Mdm_Rsp);                                       // Разобрать SMS на элементы
         }
     }
}

// Подпрограмма разбора полученной SMS с определением номера телефона и команды
void RazborSMS(String SMS_Msg)
{
  String SMS_Msgheader  = "";                                       // Объявление строковой переменной заголовка
  String SMS_Cmd    = "";                                           // Объявление строковой переменной команды
  int index = SMS_Msg.indexOf("+7");                                // Находим первое вхождение "+7", получаем индекс
  String Ph_Num = SMS_Msg.substring(index, index+12);               // Получаем номер телефона
  String SMS_MsgToSend = "";                                        // Объявление строковой переменной SMS
  Ph_Num.trim();                                                    // Убираем пробелы в начале/конце

// Проверка номера телефона на вхождение в БЕЛЫЙ СПИСОК
  CorrTlf=false;                                                    // Сброс признака вхождения номера телефона в БЕЛЫЙ СПИСОК
  Cnt=0;                                                            // Обнуление счётчика
  while (Ph_Nums[Cnt]!="End")                                       // Перебор номеров телефонов с целью определения вхождения в БЕЛЫЙ СПИСОК
        {
         if (Ph_Num.compareTo(Ph_Nums[Cnt])==0)                     // Номер телефона совпал с имеющимся в БЕЛОМ СПИСКЕ
            {
              CorrTlf=true;                                         // Установка признака вхождения номера телефона в БЕЛЫЙ СПИСОК
              break;                                                // Выход из цикла при нахождении номера
            }
         Cnt++;                                                     // Приращение счётчика
        }
  if (CorrTlf)
     {
// Номер телефона входит в БЕЛЫЙ СПИСОК
      SMS_Msg = SMS_Msg.substring(SMS_Msg.indexOf("+CMT: "));       // Определяем начало строки заголовка
      SMS_Msgheader = SMS_Msg.substring(0, SMS_Msg.indexOf("\r"));  // Получаем заголовок

      SMS_Cmd = SMS_Msg.substring(SMS_Msgheader.length() + 2);      // Выделяем строку сообщения, включая "ОК"
      SMS_Cmd.toUpperCase();                                        // Переводим сообщение в верхний регистр
      SMS_Cmd = SMS_Cmd.substring(0, SMS_Cmd.lastIndexOf("OK"));    // Выделяем собственно команду
      SMS_Cmd.trim();                                               // Убираем лишние пробелы в начале и конце

      if (SMS_Cmd.length() == 2)                                    // Длина команды = 2 символам (корректно)
         {
          int LED_Ind = ((String)SMS_Cmd[0]).toInt();               // Получаем первую цифру команды - адрес устройства (1-3)
          int LED_St = ((String)SMS_Cmd[1]).toInt();                // Получаем вторую цифру команды - состояние (0 - выкл, 1 - вкл)
          if (LED_Ind >= 1 && LED_Ind <= 3 && (LED_St == 0 or LED_St == 1))
// Если адрес и состояние входят в допустимые границы
             {
              if (digitalRead(Pins[LED_Ind - 1])!=LED_St)           // Состояние светодиода должно изменится
                 {
// Если все нормально, исполняем команду
                  digitalWrite(Pins[LED_Ind - 1], LED_St);          // Исполнение команды
                  tone(Zvuk, 500*LED_Ind, 500);
                  if (digitalRead(Pins[LED_Ind - 1])==LED_St)       // Контроль корректности исполнения команды
                     {
// Формирование сообщения об ИСПОЛНЕНИИ(!) команды
                      SMS_MsgToSend = "LED:" + (String)LED_Ind + " set to " + (LED_St == 0 ? "OFF" : "ON")+". Uspeshno :-)";
                     }
                  else
                     {
// Формирование сообщения о НЕИСПОЛНЕНИИ(!) команды
                      SMS_MsgToSend = "LED:" + (String)LED_Ind + ". set to " + (LED_St == 0 ? "OFF" : "ON")+". Ne vypolneno :-(";
                     }
                 }
              else                                                  // Состояние светодиода НЕ должно изменится
                 {
// Формирование сообщения о НЕИЗМЕНЕНИИ состояния светодиода
                  SMS_MsgToSend = "LED:" + (String)LED_Ind + ". Sostoyanie ne izmenilos :-|";
                 }
             }
          else
             {
// Формирование сообщения о НЕВОЗМОЖНОСТИ выполнить команду
              SMS_MsgToSend = "Mission: Impossible :-(";
             }
         }
      else
         {
// Формирование сообщения о НЕКОРРЕКТНОСТИ команды
          SMS_MsgToSend = "Nekorrektnaya komanda :-(";
         }
     }
  else
// Номер телефона не входит в БЕЛЫЙ СПИСОК
     {
// Формирование сообщения о невхождении телефона в БЕЛЫЙ СПИСОК
      SMS_MsgToSend = "Izvinite, telefon ne opoznan! :-("; 
     }
  Send_SMS(Ph_Num, SMS_MsgToSend);                                  // SMS об РЕЗУЛЬТАТЕ команды
  Send_AT_Cmd("AT+CMGD=1,4", true);                                 // Удаляем все сообщения, чтобы не забивали SIM-карту
}

// Подпрограмма отправки SMS
void Send_SMS(String SMS_Num, String Ansver)
{
  Send_AT_Cmd("AT+CMGS=\"" + SMS_Num + "\"", true);                 // Передаём модему номер телефона и...
  Send_AT_Cmd(Ansver + "\r\n" + (String)((char)26), true);          // ...текст сообщения, после текста отправляем перенос строки и Ctrl+Z
}

// Подпрограмма отправки команд АТ модулю
String Send_AT_Cmd(String Cmd, bool Waiting)
{
  String M_Rsp = "";                                                // Переменная для хранения результата
  GSM_A6.println(Cmd);                                              // Отправляем команду модулю
  if (Waiting)                                                      // Если флаг ожидания TRUE
     {
      M_Rsp = Wait_Rsp();                                           // При необходимости ждем ответ
     }
  return M_Rsp;                                                     // Возвращаем данные, если таковые имеются
}

// Функция ожидания ответа и возврата полученного результата
String Wait_Rsp()
{
  String M_Rsp = "";                                                // Переменная для хранения результата
  long TimeOut = millis() + 10000;                                  // Переменная для отслеживания таймаута (10 секунд)
  while (!GSM_A6.available() && millis() < TimeOut)  {};            // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
  if (GSM_A6.available())                                           // Если у модема есть что сказать
     {
      M_Rsp = GSM_A6.readString();                                  // Считываем и запоминаем данные модема
     }
  return M_Rsp;                                                     // Возвращаем данные, если таковые имеются
}

Номера телефонов скрыл, SIM карта в модеме от MOTIV. Для нормального запуска модема на 9600 НЕ ТРЕБУЕТСЯ многократной передачи AT+IPR=9600, один раз указал скорость обмена и он понял. Были некоторые сложности в начале пути, но в итоге всё заработало нормально. Скетч разработан ТОЛЬКО для проверки возможностей модема по приёму-передаче SMS.
Вот схема подключения. Расчита на работу под управлением скетча, но каждый волен переделать её и скетч под свои нужды. Плата модема показана условно, только выводы, из них,как видите, используется только 4.

Если у кого-то возникнут вопросы - милости прошу, отвечу по мере сил и умения.
Спасибо всем принявшим участие.

PS. А Си, действительно, трёхнутый на всю голову язык.
PPS. Гораздо лучший справочник по языку Си для Arduino находится тут: https://doc.arduino.ua/ru/prog/

sadman41
Offline
Зарегистрирован: 19.10.2016

Долбаните то же самое на ассемблере. После этого будете храмы ставить Cи на каждом перекрестке.

Homo Faber
Offline
Зарегистрирован: 25.05.2019

На заре своей трудовой деятельности, в году этак 1986-87, обслуживал СМ-4 и СМ-1420. После месячных курсов влёт писал тестовые программки для блоков... Сейчас уже, конечно, всё забылось.
А Си всё равно ипанутый язык, даже Fortran-77. смотрится логичнее...

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну и что, эти ваши СМ-ки с модемами работали, Вы в асинхронном режиме перифирию программировали с лёту? 
(просто интересно)

 

Homo Faber
Offline
Зарегистрирован: 25.05.2019

Нет, они использовались локально, но сложность СМ-ки и Arduin-ки, сравнивать невозможно, ибо это слишком разные устройства. Программировал, естественно, не с лёту, нопрограммы в 150-200 строк писалисьза пару дней, так как за простой натягивали крепко. Зато в результате определась неисправная плата, а то и элемент на ней. Учился в Киеве, при заводе выпускавшем эти машины, учили добротно, коллектив преподователей (они же работники завода) знал своё дело туго. В то время, на каждую плату имелись принципиальные схемы, с контрольными точками, с эпюрами (осциллограммами), то есть искать неисправности приходилось не по наитию, а по приборам. А программы на Макроассемблере помогали быстрее найти неисправность и заменить мёртвый элемент. Если, конечно, это был не процессор. Тогда Цэшку и осциллограф в зубы и вперёд, на мины... Такое правда было всего один раз, тогда обошлось малой кровью, нашли непропай заводской... А вот с периферией таки да, раз в 2-3 месяца что-нибудь да помирало. Был курьёзный случай: утром включили машину, чере пару секунд из одного шкафа раздался грохот. Быстро выключили, открыли шкаф и охренели: из блока вентиляиторов сорвались лопасти, упали вовнутрь и частично перерубили плоский кабель межблочной связи (интерфейс). Заменили вентилятор и кабель за 20 минут и всё заработало.
Вы уж извините, ударился в воспоминания...

ojakov
Offline
Зарегистрирован: 26.11.2015

Спасибо помогло, только еще пришлось питание дополнительное подать от повер банка. Я что то так и подумал, что вы с 80-х годов. Я позже начал в 1990-м.

Homo Faber
Offline
Зарегистрирован: 25.05.2019

И снова приветствую гуру Arduino и модуля gsm/gprs А6.

Нарисовал программку под свои нужды, дошло дело до подключения и внедрения А6,  и тут "такое началось" ;)

В общем ситуация такая: воззвал к старой (которую накатал с вашей помощью) программке получения и отправки SMS, кое что изменил, добавил-убрал, в общем, получил результат, который меня полностью удовлетворяет.

Вот текстовка:

#include <Wire.h>                                                 // Бибилиотека для I2C (SDA - A4, SCL - A5)
#include <Time.h>                                                 // Библиотека времени
#include <DS1307RTC.h>                                            // Библиотека для модуля часов
#include <I2C_LCD_RUS_NoCyrB.h>                                   // Библиотека для lcd без кириллицы (только БОЛЬШИЕ буквы)
#include <EEPROM.h>                                               // Библиотека для работы с памятью EEPROM
#include <SoftwareSerial.h>                                       // Библиотека програмной реализации обмена по UART-протоколу

I2C_LCD_RUS_NoCyrB lcd(0x27, 16, 2);                              // Подключаем lcd (адрес, 16 столбцов, 2 строки)
SoftwareSerial GSM_A6(8, 9);                                      // 8 - RX, 9 - TX

String Mdm_Rsp = "";                                              // Строковая переменная для хранения ответа модуля
String S_Tlf="+7904*******";                                      // Свой телефон TELE2
// БЕЛЫЙ СПИСОК телефонов в виде массива строк, с ОБЯЗАТЕЛЬНЫМ(!) "End" в конце списка
char* Ph_Nums[]= {"+7922*******", "+7919*******", "+7982*******", "End"};

void setup()
{
  Serial.begin(9600);                                             // Скорость обмена данными с компьютером
  GSM_A6.begin(9600);                                             // Скорость обмена данными с модемом
  lcd.begin();                                                    // Инициализация ЖК дисплея
  lcd.clear();
  lcd.print("GSM MOДУЛЬ");
  lcd.setCursor(0,1);
  lcd.print("ПOДГOTOBKA ");
  Serial.println("Start!");

  Send_AT_Cmd("AT", true);                                        // Отправка AT для настройки скорости обмена данными
  lcd.print(4);
delay(500);
  Send_AT_Cmd("ATE0", true);                                      // Отправка AT для настройки скорости обмена данными
  lcd.print(3);
delay(500);
  Send_AT_Cmd("AT+CMGD=1,4", true);                               // Удаляем все сообщения, чтобы не забивали SIM-карту
  lcd.print(2);
delay(500);
// Команды настройки модема при каждом запуске
  Mdm_Rsp = Send_AT_Cmd("AT+CLIP=1", true);                       // Включаем АОН
  lcd.print(1);
delay(500);
  Mdm_Rsp = Send_AT_Cmd("AT+CMGF=1;&W", true);                    // Включаем текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
  lcd.print(0);
delay(500);
  Mdm_Rsp = Send_AT_Cmd("AT+IPR?", true);                         // Запрос скорости соединения
  lcd.setCursor(0,1);
  lcd.print("ГOTOB ES = "+Mdm_Rsp.substring(7, 12));              //*Сообщение о завершении инициалиции GSM модуля
}

void loop()
{
  if (GSM_A6.available())                                         // Если у модема есть что сказать
     {
      Mdm_Rsp =GSM_A6.readString();                               // Получаем ответ от модема для анализа
      Mdm_Rsp.trim();                                             // Убираем лишние пробелы в начале и конце
Serial.println(Mdm_Rsp+"\n");
      if (Mdm_Rsp.startsWith("+CIEV:"))                           // Пришло сообщение о получении SMS
         {
          RazborSMS(Mdm_Rsp);                                     // Разобрать SMS на элементы
          Send_AT_Cmd("AT+CMGD=1,4", true);                       // Удаляем все сообщения, чтобы не забивали SIM-карту
         }
     }
  }
}

// Подпрограмма отправки команд АТ модулю
String Send_AT_Cmd(String Cmd, bool Waiting)
{
  String M_Rsp = "";                                                // Переменная для хранения результата
  GSM_A6.println(Cmd);                                              // Отправляем команду модулю
  if (Waiting)                                                      // Если флаг ожидания TRUE
     {
      M_Rsp = Wait_Rsp();                                           // При необходимости ждем ответ
     }
  return M_Rsp;                                                     // Возвращаем данные, если таковые имеются
}

// Функция ожидания ответа и возврата полученного результата
String Wait_Rsp()
{
  String M_Rsp = "";                                                // Переменная для хранения результата
  long TimeOut = millis() + 10000;                                  // Переменная для отслеживания таймаута (10 секунд)
  while (!GSM_A6.available() and millis() < TimeOut)  {};            // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
  if (GSM_A6.available())                                           // Если у модема есть что сказать
     {
      M_Rsp = GSM_A6.readString();                                  // Считываем и запоминаем данные модуля
     }
  return M_Rsp;                                                     // Возвращаем данные, если таковые имеются
}

// Подпрограмма разбора полученной SMS с определением номера телефона и команды
void RazborSMS(String SMS_Msg)
{
Serial.println("Разбор SMS \n");
// Локальные переменные
  byte Cnt=0;                                                       // Обнуление счётчика
  String SMS_Msgheader = "";                                        // Объявление строковой переменной заголовка
  String SMS_Cmd = "";                                              // Объявление строковой переменной команды
  int index = SMS_Msg.indexOf("+7");                                // Находим первое вхождение "+7", получаем индекс
  String Ph_Num = SMS_Msg.substring(index, index+12);               // Получаем номер телефона
  String S_Date = SMS_Msg.substring(index+16, index+26);
  String S_Time = SMS_Msg.substring(index+27, index+35);
  String S_Sdvg = SMS_Msg.substring(index+35, index+38);
Serial.println(SMS_Msg);
Serial.println(Ph_Num);
Serial.println(S_Date);
Serial.println(S_Time);
Serial.println(S_Sdvg);
  String SMS_MsgToSend = "";                                        // Объявление строковой переменной SMS
  bool CorrTlf=false;                                               // Сброс признака вхождения номера телефона в БЕЛЫЙ СПИСОК

  Ph_Num.trim();                                                    // Убираем пробелы в начале/конце
// Проверка номера телефона на вхождение в БЕЛЫЙ СПИСОК
  while (Ph_Nums[Cnt]!="End")                                       // Перебор номеров телефонов с целью определения вхождения в БЕЛЫЙ СПИСОК
        {
         if (Ph_Num.compareTo(Ph_Nums[Cnt])==0)                     // Номер телефона совпал с имеющимся в БЕЛОМ СПИСКЕ
            {
              CorrTlf=true;                                         // Установка признака вхождения номера телефона в БЕЛЫЙ СПИСОК
              break;                                                // Выход из цикла при нахождении номера
            }
         Cnt++;                                                     // Приращение счётчика
        }
  if (CorrTlf)
     {
      lcd.clear();                                                  // Очистка дисплея и установка курсора на 1-ю позицию 1-й строки
      lcd.print("SMS "+Ph_Num);                                     // Вывод сообщения о номере телефона
      lcd.setCursor(0, 1);                                          // Установка курсора на 1-ю позицию 2-й строки
// Номер телефона входит в БЕЛЫЙ СПИСОК
      SMS_Msg = SMS_Msg.substring(SMS_Msg.indexOf("+CMT: "));       // Определяем начало строки заголовка
      SMS_Msgheader = SMS_Msg.substring(0, SMS_Msg.indexOf("\r"));  // Получаем заголовок

      SMS_Cmd = SMS_Msg.substring(SMS_Msgheader.length() + 2);      // Выделяем строку сообщения, включая "ОК"
      SMS_Cmd.toUpperCase();                                        // Переводим сообщение в верхний регистр
      SMS_Cmd = SMS_Cmd.substring(0, SMS_Cmd.lastIndexOf("OK"));    // Выделяем собственно команду
      SMS_Cmd.trim();                                               // Убираем лишние пробелы в начале и конце

      if (SMS_Cmd.length() >= 2 && SMS_Cmd.length() <= 8)           // Длина команды не менее 2 и не более 8 символов
         {
          lcd.print("KOMAHДA "+SMS_Cmd);                            // Вывод сообщения о команде
// Формирование сообщения о получении команды
          SMS_MsgToSend = "Komanda "+SMS_Cmd+" prinyata k ispolneniyu";
         }
      else
         {
          SMS_MsgToSend = "Nekorrektnaya komanda :-(";              // Формирование сообщения о НЕКОРРЕКТНОСТИ команды
         }
     }
  else
// Номер телефона не входит в БЕЛЫЙ СПИСОК
     {
      lcd.clear();
      lcd.print("ЧУЖOЙ HOMEP");                                    // Вывод сообщения о чужом номере
// Формирование SMS сообщения о невхождении телефона в БЕЛЫЙ СПИСОК
      SMS_MsgToSend = "Izvinite, telefon ne opoznan! :-("; 
     }
  Send_SMS(Ph_Num, SMS_MsgToSend);                                  // SMS об РЕЗУЛЬТАТЕ команды
  Send_AT_Cmd("AT+CMGD=1,4", true);                                 // Удаляем все сообщения, чтобы не забивали SIM-карту
}

// Подпрограмма отправки SMS
void Send_SMS(String SMS_Num, String Ansver)
{
  Send_AT_Cmd("AT+CMGS=\"" + SMS_Num + "\"", true);                 // Передаём модему номер телефона и...
  Send_AT_Cmd(Ansver + "\r\n" + (String)((char)26), true);          // ...текст сообщения, после текста отправляем перенос строки и Ctrl+Z
}

И получаю SMS:

+CIEV: "MESSAGE",1
 
+CMT: "+7922*******",,"2020/04/27,18:12:48+05"
Qwerty
 
После того, как я попытался интегрировать этот код в свою программу (привожу не весь код, а только ту часть, что имеет значение):
#include <Wire.h>                                                 // Бибилиотека для I2C (SDA - A4, SCL - A5)
#include <Time.h>                                                 // Библиотека времени
#include <DS1307RTC.h>                                            // Библиотека для модуля часов
#include <I2C_LCD_RUS_NoCyrB.h>                                   // Библиотека для lcd без кириллицы (только БОЛЬШИЕ буквы)
#include <EEPROM.h>                                               // Библиотека для работы с памятью EEPROM
#include <SoftwareSerial.h>                                       // Библиотека програмной реализации обмена по UART-протоколу

I2C_LCD_RUS_NoCyrB lcd(0x27, 16, 2);                              // Подключаем lcd (адрес, 16 столбцов, 2 строки)
SoftwareSerial GSM_A6(8, 9);                                      // 8 - ТX (U_TXD), 9 - RX (U_RXD), в скобках обозначения на модуле А6

//...

String Mdm_Rsp="";                                                   // Строковая переменная для хранения ответа модуля
String S_Tlf="+7904*******";                                      // Свой телефон TELE2
// БЕЛЫЙ СПИСОК телефонов в виде массива строк, с ОБЯЗАТЕЛЬНЫМ(!) "End" в конце списка
char* Ph_Nums[]= {"+7922*******", "+7919*******", "+7982*******", "End"};

void setup()
{
Serial.begin(9600);
  lcd.begin();

//...

// Работаем с GSM модулем А6
  GSM_A6.begin(9600);                                             // Скорость обмена данными с модемом
  lcd.begin();                                                    // Инициализация ЖК дисплея
  lcd.clear();                                                    // Очистка ЖК дисплея
  lcd.print("GSM MOДУЛЬ");                                        // Выводим 1-ю строку служебного сообщения об инициализации GSM модуля
  lcd.setCursor(0,1);                                             // Ставим курсор в 1-ю позицию 2-й строки
  lcd.print("ПOДГOTOBKA ");                                       // Выводим 2-ю строку служебного сообщения об инициализации GSM модуля

  while (millis()<Old_Mil) {};                                    // Задержка до 15 сек до начала инициализации GSM модуля

// Начинаем инициализацию GSM модуля путём посылки АТ команд
  Send_AT_Cmd("AT", true);                                        // Отправка AT для настройки скорости обмена данными
  lcd.print(4);                                                   // Выводим текущий этап инициализации (в обратном порядке)
  delay(500);                                                     // Задержка 0,5 сек
  Send_AT_Cmd("ATE0", true);                                      // Отключить ЭХО-режим
  lcd.print(3);                                                   // Выводим текущий этап инициализации (в обратном порядке)
  delay(500);                                                     // Задержка 0,5 сек
  Send_AT_Cmd("AT+CMGD=1,4", true);                               // Удалить все сообщения, чтобы не забивали SIM-карту
  lcd.print(2);                                                   // Выводим текущий этап инициализации (в обратном порядке)
  delay(500);                                                     // Задержка 0,5 сек
  Mdm_Rsp = Send_AT_Cmd("AT+CLIP=1", true);                       // Включить АОН
  lcd.print(1);                                                   // Выводим текущий этап инициализации (в обратном порядке)
  delay(500);                                                     // Задержка 0,5 сек
  Mdm_Rsp = Send_AT_Cmd("AT+CMGF=1;&W", true);                    // Включить текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
  lcd.print(0);                                                   // Выводим текущий этап инициализации (в обратном порядке)
  delay(500);                                                     // Задержка 0,5 сек
  Mdm_Rsp = Send_AT_Cmd("AT+IPR?", true);                         // Запрос скорости соединения
  lcd.setCursor(0,1);                                             // Ставим курсор в 1-ю позицию 2-й строки
  lcd.print("ГOTOB ES = "+Mdm_Rsp.substring(7, 12));              //*Сообщение о завершении инициалиции GSM модуля
  delay(3000);
}

void loop()
{

//...

          if (GSM_A6.available())                                         // Если у модема есть что сказать
             {
              Mdm_Rsp =GSM_A6.readString();                               // Получаем ответ от модема для анализа
              Mdm_Rsp.trim();                                             // Убираем лишние пробелы в начале и конце
Serial.println(Mdm_Rsp+"\n");
              if (Mdm_Rsp.startsWith("+CIEV:"))                           // Пришло сообщение о получении SMS
                 {
                  RazborSMS(Mdm_Rsp);                                     // Разобрать SMS на элементы
                  Send_AT_Cmd("AT+CMGD=1,4", true);                       // Удаляем все сообщения, чтобы не забивали SIM-карту
                  D_T=true;                                               // Взводим флаг вывода информации на дисплей (для обновления даты и времени, на всякий случай)
                 }
             }

//...
}

//==========================================================================================
// Подпрограмма отправки команд АТ модулю
//==========================================================================================
String Send_AT_Cmd(String Cmd, bool Waiting)
{
  String M_Rsp = "";                                              // Переменная для хранения результата
  GSM_A6.println(Cmd);                                            // Отправляем команду модулю
  if (Waiting)                                                    // Если флаг ожидания TRUE
     {
      M_Rsp = Wait_Rsp();                                         // При необходимости ждем ответ
     }
  return M_Rsp;                                                   // Возвращаем данные, если таковые имеются
}

//==========================================================================================
// Функция ожидания ответа и возврата полученного результата
//==========================================================================================
String Wait_Rsp()
{
// Локальные переменные
  String M_Rsp;                                              // Переменная для хранения результата
  long TimeOut = millis() + 10000;                                // Переменная для отслеживания таймаута (10 секунд)
  while (!GSM_A6.available() and millis() < TimeOut) {};          // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
  if (GSM_A6.available())                                         // Если у модема есть что сказать
     {
      M_Rsp = GSM_A6.readString();                                // Считываем и запоминаем данные модуля
     }
  return M_Rsp;                                                   // Возвращаем данные, если таковые имеются
}

//==========================================================================================
// Подпрограмма разбора полученной SMS с определением номера телефона и команды
//==========================================================================================
void RazborSMS(String SMS_Msg)
{
Serial.println("Разбор SMS \n");
// Локальные переменные
  byte Cnt=0;                                                     // Обнуление счётчика
  String SMS_Msgheader = "";                                      // Объявление строковой переменной заголовка
  String SMS_Cmd = "";                                            // Объявление строковой переменной команды
  byte Index = SMS_Msg.indexOf("+7");                             // Находим первое вхождение "+7", получаем индекс
  String Ph_Num = SMS_Msg.substring(Index, Index+12);             // Получаем номер телефона
  String S_Date = SMS_Msg.substring(Index+16, Index+26);
  String S_Time = SMS_Msg.substring(Index+27, Index+35);
  String S_Sdvg = SMS_Msg.substring(Index+35, Index+38);
//Serial.println(SMS_Msg);
//Serial.println(Index);
//Serial.println(Ph_Num);
//Serial.println(S_Date);
//Serial.println(S_Time);
//Serial.println(S_Sdvg);
  String SMS_MsgToSend = "";                                      // Объявление строковой переменной SMS
  bool CorrTlf=false;                                             // Сброс признака вхождения номера телефона в БЕЛЫЙ СПИСОК

  Ph_Num.trim();                                                  // Убираем пробелы в начале/конце
// Проверка номера телефона на вхождение в БЕЛЫЙ СПИСОК
  while (Ph_Nums[Cnt]!="End")                                     // Перебор номеров телефонов с целью определения вхождения в БЕЛЫЙ СПИСОК
        {
         if (Ph_Num.compareTo(Ph_Nums[Cnt])==0)                   // Номер телефона совпал с имеющимся в БЕЛОМ СПИСКЕ
            {
              CorrTlf=true;                                       // Установка признака вхождения номера телефона в БЕЛЫЙ СПИСОК
              break;                                              // Выход из цикла при нахождении номера
            }
         Cnt++;                                                   // Приращение счётчика
        }
  if (CorrTlf)
     {
// Номер телефона входит в БЕЛЫЙ СПИСОК
      lcd.clear();                                                // Очистка дисплея и установка курсора на 1-ю позицию 1-й строки
      lcd.print("SMS "+Ph_Num);                                   // Вывод сообщения о номере телефона
      lcd.setCursor(0, 1);                                        // Установка курсора на 1-ю позицию 2-й строки
      SMS_Msg = SMS_Msg.substring(SMS_Msg.indexOf("+CMT: "));     // Определяем начало строки заголовка
Serial.println("1 "+SMS_Msg);
// Получаем заголовок
      SMS_Msgheader = SMS_Msg.substring(0, SMS_Msg.indexOf("\r"));
Serial.println("2 "+SMS_Msgheader);
      SMS_Cmd = SMS_Msg.substring(SMS_Msgheader.length() + 2);    // Выделяем строку сообщения, включая "ОК"
Serial.println("3 "+SMS_Cmd);
      SMS_Cmd.toUpperCase();                                      // Переводим сообщение в верхний регистр
      SMS_Cmd = SMS_Cmd.substring(0, SMS_Cmd.lastIndexOf("OK"));  // Выделяем собственно команду
Serial.println("4 "+SMS_Cmd);
      SMS_Cmd.trim();                                             // Убираем лишние пробелы в начале и конце

      if (SMS_Cmd.length() >= 2 && SMS_Cmd.length() <= 8)         // Длина команды не менее 2 и не более 8 символов
         {
          lcd.print("KOMAHДА "+SMS_Cmd);                          //*Вывод сообщения о команде
// Формирование сообщения о получении команды
          SMS_MsgToSend = "Komanda "+SMS_Cmd+" prinyata k ispolneniyu";
         }
      else
         {
          SMS_MsgToSend = "Nekorrektnaya komanda :-(";            // Формирование сообщения о НЕКОРРЕКТНОСТИ команды
         }
     }
  else
// Номер телефона не входит в БЕЛЫЙ СПИСОК
     {
      lcd.clear();
      lcd.print("ЧУЖOЙ HOMEP");                                   // Вывод сообщения о чужом номере
// Формирование SMS сообщения о невхождении телефона в БЕЛЫЙ СПИСОК
      SMS_MsgToSend = "Izvinite, telefon ne opoznan! :-("; 
     }
  Send_SMS(Ph_Num, SMS_MsgToSend);                                // SMS об РЕЗУЛЬТАТЕ команды
  Send_AT_Cmd("AT+CMGD=1,4", true);                               // Удаляем все сообщения, чтобы не забивали SIM-карту
}

//==========================================================================================
// Подпрограмма отправки SMS
//==========================================================================================
void Send_SMS(String SMS_Num, String Ansver)
{
  Send_AT_Cmd("AT+CMGS=\"" + SMS_Num + "\"", true);               // Передаём модему номер телефона и...
  Send_AT_Cmd(Ansver + "\r\n" + (String)((char)26), true);        // ...текст сообщения, после текста отправляем перенос строки и Ctrl+Z
}

Получаю уже вот такую SMS:

+CIEV: "MESSAGE",1
 
+CMT: "+7922*******",,"2020/04/27,18:24
 
Вот для наглядности, какую SMS получил в первом варианте:
+CIEV: "MESSAGE",1
 
+CMT: "+7922*******",,"2020/04/27,18:12:48+05"
Qwerty
 
То есть обрезается самая, для меня,важная часть SMS.
Так вот, у с=меня возникает вопрос, каким образом обрезается SMS?
Мож я опять чего накосячил???

 

Homo Faber
Offline
Зарегистрирован: 25.05.2019

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

Опрашиваю модем на каждом цикле void Loop(), записываю SMS-ку в переменную, а уже обрабатываю её примерно через секунду, после опроса датчиков (если ни одного сработавшего), иначе только после обработки срабатывания.

Если кому интересно - пишите, постараюсь ответить.

b707
Offline
Зарегистрирован: 26.05.2017

Homo Faber пишет:

Опрашиваю модем на каждом цикле void Loop(), записываю SMS-ку в переменную

судя по коду - именно в этом у вас и проблема.  Вы считываете СМС в переменную. не проверяя - а пришло ли сообщение целиком?  -вместо этого вы просто ждете 10 секунд :

// Функция ожидания ответа и возврата полученного результата
String Wait_Rsp()
{
  String M_Rsp = "";                                                // Переменная для хранения результата
  long TimeOut = millis() + 10000;                                  // Переменная для отслеживания таймаута (10 секунд)
  while (!GSM_A6.available() and millis() < TimeOut)  {};            // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
  if (GSM_A6.available())                                           // Если у модема есть что сказать
     {
      M_Rsp = GSM_A6.readString();                                  // Считываем и запоминаем данные модуля
     }
  return M_Rsp;                                                     // Возвращаем данные, если таковые имеются
}

Код - просто сборище разных ляпов и глупостей. Тайм аут (строка 5) отмеряете неправильно. Блокирующий цикл ожидания (строка 6) - это просто жесть, все это время программа висит, датчики не проверяет, на сигналы не реагирует.

Ну и самый апофеоз - несмотря на тупое ожидание 10 секунд - все это не дает никакой гарантии, что вы правильно обработаете СМС. Представьте, например, что за эти 10 секунд придет еще одно сообщение или служебная инфа от оператора связи? - и все. вся ваша конструкция заткнется...

Homo Faber
Offline
Зарегистрирован: 25.05.2019

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

Вряд ли мне удастся отправить 2 SMS за 10 секунд, а служебная инфа отсекается ещё на этапе проверки SMS (в доработанной версии) путём проверки наличия "CMT". А вот подсказать про таймер не судьба???

b707
Offline
Зарегистрирован: 26.05.2017

Homo Faber пишет:

А вот подсказать про таймер не судьба???

какой таймер? зачем он тут?

Homo Faber
Offline
Зарегистрирован: 25.05.2019

Тайм аут имел в виду...

Homo Faber
Offline
Зарегистрирован: 25.05.2019

И снова я,со своими наивными вопросами.

Когда я попытался отправить по запросу отчёт, примерно из 80 символов, то получил пустую SMS. Никто не сталкивался с каким либо ограничением на количество символов передаваемых в SMS. Примерно до 70 символов передаётся и получается нормально, а потом - просто пустота... Хотя, по идее, можно посылать до 160 символов...
Все символы в отчёте - латиница и цифры, кириллицы нет.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Есть два ограничения :
1 стандарт GSM
2 кривизна скетча / библиотеки

Homo Faber
Offline
Зарегистрирован: 25.05.2019

Похоже я доэкспериментировался с А6. На выходе U_TXD теперь напряжение в 1.6 v (вместо 3,39 v), слегка подсвечивает синий светодиод, соединённый с этим выходом, обмен с Arduino на нуле. надежды, как я понимаю практически никакой. Некоторую надежду внушают пины H_TXD и H_TXD это HST_TXD и HST_RXD, если верить верить ;) руководству от Ai ThinkerTechnology. Пока не нашёл расшифровки, что это такое, HST, но надежды не теряю. Может кто сталкивался? 

Вот кусочек таблицы из руководства:

30 UART_TXD UART_TXD,Pin level 2.8V

31 UART_RXD UART_RXD,Pin level 2.8V

32 HST_RXD   Download serial port RXD Pin,pin level 2.8V

33 HST_TXD   Download serial port TXD pin,pin level 2.8V

Внушает надежду, что у них указано одинаковое напряжение: 2.8V.

Если интересны подробности, то был момент, когда я по ошибке посадил на U_RXD землю, а U_TXD соединил с выходным пином Arduino. Возможно, что это повлияло на работоспособность...

PS. Заказал новый модуль А6, буду насиловать дальше, когда придёт от китаяйцев.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Homo Faber , мне конечно все равно, а почему не Sim800L модем? у него и прошивки постабильнее и документации больше и работают практически всегда....

Homo Faber
Offline
Зарегистрирован: 25.05.2019

Когда на Ali выбирал, мне этот больше понравился, если честно чисто внешне. А когда выяснил, что делитель по входу не нужен, было оч-чень приятно. Да и то, что на моих глазах, можно сказать, 2 800-х накрылись медным тазиком, один просто в процессе работы на же рабочем проекте, тоже сыграло свою роль...

Homo Faber
Offline
Зарегистрирован: 25.05.2019

Наконец-то восстановил схему, допилил программу, всё вроде работает.

Смущает только одно: от оператора (Tele2) постоянно идут служебные сообщения, я их игнорирую, но немного напрягает эта ситуация. Если SIM карту ставишь в телефон, то такого не наблюдается.

Вот примеры сообщений, для удобства я отделил посылки пустыми строками.

10:41:08.608 -> SMS > +CIEV: service,  0
10:41:08.643 -> +CIEV: roam, 0
10:41:08.677 -> 
10:41:08.677 -> +CREG: 2
 
10:41:14.560 -> SMS > +CIEV: service,  1
10:41:14.594 -> +CIEV: roam, 0
10:41:14.628 -> 
10:41:14.628 -> +CREG: 1
 
10:43:35.525 -> SMS > +CIEV: service,  0
10:43:35.525 -> +CIEV: roam, 0
10:43:35.558 -> 
10:43:35.558 -> +CREG: 2
 
10:43:59.529 -> SMS > +CIEV: service,  0
10:43:59.565 -> +CIEV: roam, 0
10:43:59.599 -> 
10:43:59.599 -> +CREG: 3
 
10:45:40.356 -> SMS > +CIEV: service,  0
10:45:40.356 -> +CIEV: roam, 0
10:45:40.394 -> 
10:45:40.394 -> +CREG: 2
 
10:45:45.720 -> SMS > +CIEV: service,  1
10:45:45.760 -> +CIEV: roam, 0
10:45:45.803 -> 
10:45:45.803 -> +CREG: 1
 
10:51:14.371 -> SMS > +CIEV: service,  0
10:51:14.405 -> +CIEV: roam, 0
10:51:14.405 -> 
10:51:14.405 -> +CREG: 2
 
10:51:38.994 -> SMS > +CIEV: service,  0
10:51:39.031 -> +CIEV: roam, 0
10:51:39.067 -> 
10:51:39.067 -> +CREG: 3
 
10:53:19.700 -> SMS > +CIEV: service,  0
10:53:19.734 -> +CIEV: roam, 0
10:53:19.734 -> 
10:53:19.734 -> +CREG: 2
 
10:53:25.195 -> SMS > +CIEV: service,  1
10:53:25.229 -> +CIEV: roam, 0
10:53:25.229 -> 
10:53:25.229 -> +CREG: 1
 
Как видно за 12 минут 10 сообщений. "SMS >" - это моё.
Что можете посоветовать, уважаемые знатоки? Или плюнуть и забить?
b707
Offline
Зарегистрирован: 26.05.2017

Homo Faber пишет:

Смущает только одно: от оператора (Tele2) постоянно идут служебные сообщения, я их игнорирую, но немного напрягает эта ситуация. Если SIM карту ставишь в телефон, то такого не наблюдается.

я не спец в сотовой связи. но насколько знаю. эти сообщения и в телефоне идут, просто юзеру не показываются.

Почитайте вот тут https://www.developershome.com/sms/cpmsCommand.asp- получение и хранениее cлужебных сообщений настраивается параметрами BM ("broadcast messages") и SR ("status report") команды AT+CPMS. Правда тут в тексте оговорка, что к сожалению, далеко не все модемы поддерживают управление служебными сообщениями