Данная статья является продолжением публикаций про созданную мною систему "Умный дом" на основе проводного интерфейса CAN. Также предлагаемый проект может быть использован для разработки каких то других пользовательских программ, так как оформлен в виде задачи (Task) в FreeRTOS. Программа написана на языке программирования C/C++ в среде программирования ESP-IDFv5.
1 Обоснование необходимости модуля
С экономической точки зрения, использование роутера в системе значительно увеличивает ее стоимость при малом числе контроллеров сети.
В связи с существующей ситуацией в стране, необходим дополнительный канал связи для передачи основных сообщений при отсутствии интернета, например с помощью sms. Существующие роутеры, обладающие такой функцией должны обладать внутренним модулем GSM со слотом для SIM карты и стоимость таких роутеров в 2-3 раза выше.
2 Выбор модуля
Из существующих модулей GSM наиболее бюджетным является класс модулей SIM800 работающие в сети 2G (GSM/GPRS), остальные типы модулей значительно дороже [1].
Данные модули представлены в трех разновидностях, буквы C, H, L.
Наиболее широко используются модули SIM800L, SIM800C. Отличаются они наличием Bluetooth 3.0 в последней модели, при этом разница в цене незначительна.
Поэтому предпочтительнее выбрать модуль SIM800C.
На Aliexpress есть несколько вариантов модулей SIM800C, но лучше выбрать вариант с разведенным на плате конвертером уровней TTL 5V < 3,3V и преобразователем напряжения с 5V до ~3,7 Вольт.
ВНИМАНИЕ! При использовании дешевого модуля SIM800C/L без конвертера уровней, даже при подключении его напрямую к ESP32 с уровнем логики 3,3 V вместо максимальных 3,1 V, указанных в datasheet, можно вывести SIM800 из строя.
3 Подключение модуля
Вывод «5V». Питание модуля от 3.4 В до 4.4 В, рекомендуется 4В и ток до 2А. На купленной в Aliexpress плате рекомендуется подключить к 5 В и за счет падения напряжения на диоде, расположенном на плате, напряжение упадет до допустимого. Также рекомендуют подключить конденсатор 1000 мкФ параллельно существующему по питанию.
Вывод «V_TTL». Вывод конвертера уровней, подключается к 3,3В для ESP32.
Вывод «GND». Общий вывод питания.
Вывод «TXD». Передача данных от модуля. Подключение к «IO15» вывод 23 ESP32-C6-WROOM-1.
Вывод «RXD». Прием данных модулем. Подключение к «IO19» вывод 17 ESP32-C6-WROOM-1.
Вывод «PWX». Импульсом отрицательной полярности длительностью >3c осуществляется сброс в начало работы. Рекомендуется формировать с помощью кнопки, например «INIT» или подключить постоянно к общему выводу питания (но тогда сброс модема будет осуществляться по сбросу питания).
Если все подключено правильно загорается постоянно светодиод питания «POWER» и мигает другой с частотой 1 Гц (готовность модема к работе). Если модем зарегистрировался в сотовой сети светодиод начинает мигать с интервалом 3 с.
4 Программная реализация в ESP-IDF
4.1 АТ — команды
Основные АТ- команды используемые модулем:
Команды изменения режима работы модуля
SIM800C имеет два режима энергосбережения: режим минимальной функциональности и спящий режим.
«AT+CSCLK=1»: команда для перевода SIM800C в спящий режим.
Для перевода SIM800C в режим минимальной функциональности можно использовать команду «AT+CFUN=<fun>». Когда SIM800C находится в спящем режиме и режиме минимальной функциональности, ток модуля минимален.
Существует три режима работы, которые можно установить с помощью AT-команды «AT+CFUN=<fun>». Команда предоставляет выбор уровней функциональности <fun>=0, 1, 4.
AT+CFUN=0: Минимальная функциональность. Потребление до 1мА.
AT+CFUN=1: Полная функциональность (по умолчанию). Потребление 350-450мА при передаче и 15-20мА в режиме ожидания приема.
AT+CFUN=4: Режим полета (отключение радиочастотной функции). Потребление 15-20мА.
Базовые команды тестирования
AT: Проверка связи с модулем. В ответ должно прийтиOK.ATE0/ATE1: Выключить или включить эхо (повтор вводимых команд в терминале).AT+GSV: Запросить версию прошивки и название модели.AT+IPR=?: Узнать поддерживаемые скорости передачи данных (baud rate).AT+CSQ: Проверка уровня сигнала. Возвращает значения от 0 до 31 (чем выше, тем лучше).ATI: эта команда позволяет получить имя модуля и его номер.
AT+CBC: эта команда возвращает процент заряда батареи (второе число в выходном окне) если она подключена к модулю.
Работа с сетью и SIM-картой
AT+CPIN?Проверка состояния SIM-карты (запрошен ли PIN-код).AT+CCID: эта команда проверяет номер sim карты, написанный на ее обратной стороне. После исполнения команды вы можете проверить этот номер вручную. Также эту команду можно использовать для проверки того подключена ли sim карта к модулю.
AT+CREG?: Проверка регистрации в сети (статус 1 или 5 означает успешную регистрацию). 1 будет означать что вы в домашней сети, а 5 – что вы в роуминге. Любое другое число будет свидетельствовать о том, что вы не зарегистрированы в сети.Обычно время регистрации в сети составляет 15-30 с.AT+COPS?: Узнать имя текущего оператора мобильной связи.
Голосовые вызовы
ATD+79XXXXXXXXX;: Совершить исходящий вызов (обязательно наличие точки с запятой в конце).ATA: Ответить на входящий вызов.ATH: Разорвать соединение (положить трубку).AT+CLIP=1: Включить определитель номера (АОН) для отображения номера звонящего.
Работа с SMS
AT+CMGF=1: Установить текстовый режим (Text mode) вместо PDU (по умолчанию)."AT+CSCS=\"GSM\"":Установить кодировку текста (здесь стандартная GSM)."AT+CNMI=2,2,0,0,0":Команда задает режим хранения входящих SMS. В данном случае: Автоматический вывод входящих SMS в UART.AT+CMGS="+79XXXXXXXXX": Начать отправку SMS. После ввода текста нужно отправить символCtrl+Z(код 0x1A) для завершения.AT+CMGL="ALL": Вывести список всех SMS из памяти модуля.AT+CMGR=1: Прочитать сообщение под определенным индексом.AT+CMGD=1: Удалить сообщение из памяти.
GPRS и Интернет
AT+SAPBR=3,1,"APN","internet": Установка точки доступа (настройки оператора).AT+SAPBR=1,1: Установить соединение (открыть контекст GPRS).AT+HTTPINIT: Инициализация HTTP-сервиса.AT+HTTPACTION=0: Выполнить GET-запрос (1 — POST, 2 — HEAD).
4.2 Прямая работа через UART (AT-команды)
Этот вариант подходит только для приема/передачи SMS. Он представлен в основном во всех источниках информации.
При работе через интерфейс последовательного ввода/вывода используется библиотека: driver/uart.h.
4.2.1 Инициализация UART1:
uart_config_t uart_config = {
.baud_rate = 115200, // Скорость по умолчанию для большинства модулей
.data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_param_config(UART_NUM_1, &uart_config);
uart_set_pin(UART_NUM_1, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_driver_install(UART_NUM_1, BUF_SIZE * 2, 0, 0, NULL, 0);
4.2.2 Для управления модулем используются AT-команды.
Используйте uart_write_bytes для инициализации (например, AT\r\n для проверки связи) и uart_read_bytes для чтения ответов от модуля.
4.2.3 Обработка данных:
Создать задачу (Task) в FreeRTOS для постоянного чтения UART, чтобы не пропустить входящие SMS или сигналы сети.
Далее приведен созданный мной код программы задачи в среде программирования ESP-IDF:
ПРИЕМ/ПЕРЕДАЧА SMS через GSM-модуль
//подключение пользовательских значений #include "app_const.h" //================ UART1 GSM modem ================================= #define TX_PIN (GPIO_NUM_19)//выход передатчика данных #define RX_PIN (GPIO_NUM_15)//вход приемника данных #define BUF_SIZE 160//размер буфера принимаемых данных #define TIME_SMS 5000//интервал задачи приема/передачи sms #define NUM_TEL "+79384799076"// номер телефона куда отправляются SMS #define WAIT_INIT_MODEM 2000//пауза на инициализацию модема,мс #define SMS_MODEM_PRIO 4//приоритет задачи sms modem //=============================================== //подключение общих программ #include <stdint.h> #include "stdio.h" #include "string.h" #include <stdlib.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" #include "esp_err.h" #include "esp_system.h" #include "driver/gpio.h" #include "driver/uart.h" //Функция посылки AT-команд void send_at_com(const char* cmd) { uart_write_bytes(UART_NUM_1, cmd, strlen(cmd)); uart_write_bytes(UART_NUM_1, "\r\n", 2); } //Функция чтения данных от модема через UART void read_from_modem(uint8_t *data) { int len = uart_read_bytes(UART_NUM_1,data,(BUF_SIZE - 1),10);//ожидание 10 тик if(len > 0) {//если что-то получено, то в конец строки 0 data[len] = '\0'; printf("Modem GSM: %s", data); } } //Функция отправки SMS void sim800_send_sms(const char* phone_number, const char* text) { char cmd[64]; // 1. Команда инициализации отправки SMS snprintf(cmd, sizeof(cmd), "AT+CMGS=\"%s\"\r\n", phone_number); uart_write_bytes(UART_NUM_1, cmd, strlen(cmd)); vTaskDelay(pdMS_TO_TICKS(100)); // Ожидание символа приглашения '>' // 2. Отправка самого текста сообщения uart_write_bytes(UART_NUM_1, text, strlen(text)); // 3. Отправка символа Ctrl+Z (ASCII код 26) для подтверждения отправки char ctrl_z = 26; uart_write_bytes(UART_NUM_1, &ctrl_z, 1); } //Программа выполнения задачи получения/отправки SMS через GSM-модем void sms_modem(void *arg) { //Инициализация UART1: uart_config_t uart_config = { .baud_rate = 115200, // Скорость по умолчанию для большинства модулей .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .source_clk = UART_SCLK_DEFAULT, }; uart_param_config(UART_NUM_1, &uart_config); uart_set_pin(UART_NUM_1, TX_PIN, RX_PIN, -1, -1); uart_driver_install(UART_NUM_1, BUF_SIZE * 2, 0, 0, NULL, 0); // Настройте временный буфер для входящих данных uint8_t *data = (uint8_t *) malloc(BUF_SIZE); //Признак регистрации модема в сотовой сети uint8_t f_reg = 0;// не зарегистрирован //ПОСЛЕДОВАТЕЛЬНОСТЬ АТ-команд по тестированию модуля GSM и //установке режима работы printf("Modem GSM, ready?\n"); uart_flush_input(UART_NUM_1); // Чистим старые данные send_at_com("AT");//готовность модуля? read_from_modem(data); send_at_com("AT+CSQ");//мощность сигнала, дцб read_from_modem(data); send_at_com("AT+CCID");//номер sim карты? read_from_modem(data); send_at_com("AT+COPS?");//имя подключенного оператора сети read_from_modem(data); send_at_com("AT+CMGF=1");//установка текстового режима SMS read_from_modem(data); send_at_com("AT+CSCS=\"GSM\""); // Кодировка текста стандартная GSM read_from_modem(data); send_at_com("AT+CNMI=2,2,0,0,0"); // Автоматический вывод входящих SMS в UART read_from_modem(data); //Основной цикл задачи while (1) { //Чтение входящих SMS if(f_reg==1) { //read_from_modem(data); int len = uart_read_bytes(UART_NUM_1,data,(BUF_SIZE - 1),10); if(len>0 && data[len-1]=='\n') { //если что-то получено, то в конец строки 0 data[len] = '\0'; printf("Modem GSM: %s", data); char text_uart[BUF_SIZE]; for(int n=0; n<=len; n++) { text_uart[n] = data[n]; } //В принятом сообщение указывается: номер телефона, время, //само сообщение.Типа: /* +CMT: "+79380000000","","26/07/05,17:43:55+12" ky-ky! */ //Считаем, что за цикл приходит не более 1 сообщения. //Выделяем номер телефона и текст SMS, разделив строку по символу //переноса и убрав пустые строки char phone[20] = {0}; char *text_sms; uint8_t ft = 0;//флаг признака строки с номером телефона text_sms = strtok(text_uart, "\n"); do { text_sms = strtok('\0', "\n"); if(text_sms && text_sms[0]!='\r' && ft==1) { //эта строка следующая после номера и времени - текст sms break; } if(text_sms && text_sms[0]!='\r' && ft==0) { // Извлекаем номер телефона, находящийся в первых кавычках // Регулярное выражение считывает до 12 символов sscanf(text_sms, "+CMT: \"%12s", phone); ft = 1; } } while(text_sms); printf("Phone: %s\n", phone); printf("Text SMS: %s\n", text_sms); //ДАЛЕЕ ОБРАБОТКА ПОСТУПИВШЕГО СООБЩЕНИЯ //здесь может быть ваш код. } } //Проверка регистрации в сотовой сети модема send_at_com("AT+CREG?");//регистрация в сети? //чтение данных через UART int len = uart_read_bytes(UART_NUM_1,data,(BUF_SIZE - 1),10); //если в данных после "," 1 - модем регистрирован в сотовой сети for(int i=0; i<len; i++) { if(data[i]==',') { if(data[i+1]=='1') { printf("This modem is registered!\n"); if(f_reg==0) { printf("Send a message about modem GSM connection\n"); sim800_send_sms(NUM_TEL, "Modem GSM connection!"); f_reg = 1; } } else { printf("Not registered!\n"); f_reg = 0; } break; } } vTaskDelay(pdMS_TO_TICKS(TIME_SMS)); } vTaskDelete(NULL); } //Данная функция вызывается для создания задачи для ОС void init_sms_modem() { TaskHandle_t TaskHandleSMSmodem = NULL; xTaskCreate(sms_modem,"SMSmodem",4096,NULL,SMS_MODEM_PRIO,&TaskHandleSMSmodem); // Проверим, создалась ли задача if(TaskHandleSMSmodem != NULL) { printf("TASK SMS MODEM create!\n"); } else printf("TASK SMS MODEM FAILED!\n"); }
4.3 Использование компонента esp_modem
Более сложный и интересный вариант с использованием esp_modem. Официальный компонент esp-protocols/esp_modem значительно упрощает работу, предоставляя абстракцию для выполнения звонков, отправки SMS и настройки интернет соединения (PPP). Использование компонента позволяет работать с модемом как с обычной сетевой картой через стандартный стек esp_netif.
Однако это тема отдельной разработки и отдельной статьи, которую я возможно напишу в ближайшем будущем.
Список используемой литературы
1 Статья «Подключение GSM модуля SIM800C к ESP8266/ESP32/Arduino»: https://www.bizkit.ru/2019/02/05/11989/?ysclid=mk8fgq58lw824349945
2 Статья «Подключение GSM модуля SIM800L к ESP32»: https://microkontroller.ru/esp32-projects/podklyuchenie-gsm-modulya-sim800l-k-esp32/?ysclid=mk842h2151575746327
