Введение
Для телеметрии в труднодоступных местах Wi-Fi зачастую оказывается непригодным из-за ограниченного радиуса действия. В этой статье детально разберем интеграцию бюджетного GSM-модуля SIM800C с платой STM32F103C8T6, реализовав надежный канал передачи данных через сотовую сеть.

Необходимые детали
| № | Компонент | Количество | Купить |
|---|---|---|---|
| 1 | Отладочная плата STM32F411 | 1 шт | Авито | AliExpress | RobotChip |
| 2 | Блок питания AC-DC, 5В, 3А | 1 шт | Авито | AliExpress | RobotChip |
| 3 | Модуль SIM800C | 1 шт | Авито | AliExpress | RobotChip |
| 4 | Провод DuPont | 16 шт | Авито | AliExpress | RobotChip |
| 4 | Макетная плата 800 контактов | 1 шт | Авито | AliExpress | RobotChip |
| 6 | Модуль DHT11 | 1 шт | Авито | AliExpress | RobotChip |
| 7 | Конвертер CH340G | 1 шт | Авито | AliExpress | RobotChip |
Описание
В этой статье мы будем работать в среде Arduino IDE. Поддержку плат STM32 легко добавить через встроенный Boards Manager (подробную инструкцию я давал в прошлой публикации).
Зачем это нужно? Представьте задачу: организовать автономный мониторинг температуры и влажности на фермерском поле, лесной делянке или пасеке, где полностью отсутствует Wi-Fi. В таких условиях самым надёжным каналом передачи данных остаётся сотовая связь. Именно поэтому сердцем нашей системы станет микроконтроллер STM32, который будет собирать показания датчиков и отправлять их через GSM/GPRS-модуль. Благодаря повсеместному покрытию сетей устройство сможет стабильно выходить на связь даже в удалённой местности.
Подключение
Подключение компонентов не представляет сложности, так как модуль SIM800C обменивается данными по интерфейсу UART: контакт TX модуля подключаем к выводу PB6 микроконтроллера STM32F411CE, а контакт RX — к выводу PB7, затем контакт VDD логики соединяем с выводом 3.3 В (так как все выходы STM32F411 составляют 3.3 В), для включения модуля на пин PWX необходимо установить перемычку на GND, питание самого модуля осуществляется от источника питания 5В, для этого контакт соединяем с выходом VCC модуля, а GND — со входом GND, далее подключаем датчик DHT11 к контроллеру: выводы VCC и GND датчика соединяем с линиями 3.3 В и GND микроконтроллера, сигнальный вывод DATA — с портом PB5.

В данной статье я использую плату Black Pill на базе микроконтроллера STM32F411CEU6. После установки поддержки платы в Arduino IDE необходимо настроить параметры проекта во вкладке «Инструменты» следующим образом.

Также перед прошивкой необходимо нажать кнопку BOOT и, не отпуская её, нажать кнопку RST. Затем отпустите сначала RST, а после — BOOT. Микроконтроллер перейдёт в режим программирования.
Установка библиотек
Для работы, будем использовать библиотеку «DHT-sensor-library от Adafruit» скачать можно используя интегрированную среду разработки Arduino IDE», для этого откройте «Скетч → Подключение библиотеки → Менеджер библиотек…», так же выложу библиотеки в конце статьи.

Для работы библиотеки необходимо установить зависимые библиотеки, нажимаем «Установить все»

Программа
Ниже приведён исходный код для работы с модулем SIM800C. Перед загрузкой скетча задайте свой номер телефона в международном формате — на него будут приходить ответные сообщения
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
#include <SoftwareSerial.h> // Подключаем библиотеку SoftwareSerial #include <DHT.h> // Подключаем библиотеку DHT // Настройка SoftwareSerial: RX (прием) на PB6, TX (передача) на PB7. #define RX_PIN PB6 #define TX_PIN PB7 SoftwareSerial mySerial(RX_PIN, TX_PIN); // Настройка датчика DHT11: сигнал подключен к PB5, тип сенсора — DHT11 #define DHTPIN PB5 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(115200); // Инициализация монитор порта ПК (для отладки): скорость 115200 бод mySerial.begin(9600); // Инициализируем связь с модемом на скорости 9600 бод dht.begin(); // Инициализация датчика DHT11 while (!Serial) { ; } // Ожидание готовности монитора порта (актуально для некоторых плат вроде Leonardo/Micro) Serial.println("Starting up..."); // Отправка данных в мониторинг порта // Инициализация модуля с таймаутом (не более 10 секунд). Проверяем готовность модема командой AT до 10 раз bool modemReady = false; for (int i = 0; i < 10; i++) { sendCommand("AT"); if (waitForResponse(1000).indexOf("OK") != -1) { // Если в ответе есть "ОК" за 1 секунду modemReady = true; break; } delay(500); // Пауза перед следующей попыткой } if (!modemReady) { Serial.println("Modem not found!"); while (1); // Останавливаемся (бесконечный цикл), если модем не ответил } Serial.println("Module OK. Configuring..."); // Текстовый режим SMS: устанавливаем формат сообщений как текст вместо PDU sendCommand("AT+CMGF=1"); waitForResponse(1000); // Настройка уведомлений о новых SMS: вывод текста сообщения напрямую при получении (+CNMI=1,2...) sendCommand("AT+CNMI=1,2,0,0,0"); waitForResponse(1000); Serial.println("System Ready. Send 'DATA' to get sensor info."); } void loop() { // Если пришли данные от модема (новое SMS или служебный ответ) if (mySerial.available()) { String msg = waitForResponse(2000); // Собираем весь входящий буфер за 2 секунды Serial.println("Received: " + msg); // Убираем пробелы по краям и приводим к верхнему регистру для удобства поиска команды msg.toUpperCase(); msg.trim(); // Проверяем текст сообщения: ищем ключевое слово DATA if (msg.indexOf("DATA") > -1) { float h = dht.readHumidity(); // Считываем влажность (%) float t = dht.readTemperature(); // Считываем температуру (Цельсий) sms(String("Temp: " + String(t) + "C Hum: " + String(h) + "%"), String("+79179608420")); // Отправляем SMS с данными на указанный номер } } } // Функция отправки AT-команды в модем void sendCommand(const String& cmd) { mySerial.println(cmd); // Печатаем команду в программный порт Serial.print(">> "); Serial.println(cmd); // Дублируем отправку в монитор порта для отладки } // Функция ожидания ответа от модема (собирает строку целиком до истечения timeout) String waitForResponse(unsigned long timeout) { unsigned long startTime = millis(); String response = ""; while (millis() - startTime < timeout) { if (mySerial.available()) { char c = mySerial.read(); // Читаем байты из буфера один за другим response += c; } } return response; } // Процедура Отправки SMS через AT-команды void sms(String text, String phone) { Serial.println("\nSending SMS..."); // Переход в режим ввода текста SMS, указываем целевой номер в международном формате sendCommand("AT+CMGS=\"" + phone + "\""); // Ждем символ приглашения '>' от модема (он означает, что можно вводить тело сообщения) if (waitForResponse(5000).indexOf('>') > -1) { mySerial.print(text); // Передаем само сообщение mySerial.write(26); // Ctrl+Z (ASCII код 26) — команда завершения и отправки SMS delay(3000); // Даем время модему установить соединение с сетью и отправить пакет Serial.println("SMS Sent command executed."); } else { Serial.println("Failed to enter SMS prompt."); // Ошибка: приглашение '>' не получено |
Если все правильно сделали при открытия мониторинга порта увидим отправка и получения команд.

В телефоне при отправке SMS будет приходить сообщение об температуры и влажности.

Описание программы.
Сначала подключаются необходимые библиотеки для работы с датчиком DHT11 и программным UART, затем указываются порты и создаётся объект для работы с библиотеками.
1 2 3 4 5 6 7 8 9 10 |
#include <SoftwareSerial.h> #include <DHT.h> #define RX_PIN PB6 #define TX_PIN PB7 SoftwareSerial mySerial(RX_PIN, TX_PIN); #define DHTPIN PB5 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); |
В функции Setup инициализируем последовательные порты: на скорости 115200 бод — для отладки, и 9600 бод — для работы с модулем SIM800. Затем активируем датчик DHT11
1 2 3 |
Serial.begin(115200); mySerial.begin(9600); dht.begin(); |
Далее проверяем доступность модуля SIM800C. Для этого в течение 10 секунд отправляем команду AT. Если связь установлена — выводим соответствующее сообщение об успехе, если нет — сообщение об ошибке.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Serial.println("Starting up..."); bool modemReady = false; for (int i = 0; i < 10; i++) { sendCommand("AT"); if (waitForResponse(1000).indexOf("OK") != -1) { modemReady = true; break; } delay(500); } Serial.println("Module OK. Configuring..."); if (!modemReady) { Serial.println("Modem not found!"); while (1); } |
Следующими командами конфигурируем модуль: сначала отправляем команду для перевода в текстовый режим отправки SMS ( AT+CMGF=1), а затем настраиваем уведомления так, чтобы при получении нового сообщения модем сразу пересылал его текст в программный порт контроллера ( AT+CNMI=1,2,0,0,0)
1 2 3 4 5 6 7 |
sendCommand("AT+CMGF=1"); waitForResponse(1000); sendCommand("AT+CNMI=1,2,0,0,0"); waitForResponse(1000); Serial.println("System Ready. Send 'DATA' to get sensor info."); |
В функции loop() мы постоянно проверяем, поступили ли данные: if (mySerial.available()). Затем функция waitForResponse(2000) считывает всё, что накопилось в буфере за 2 секунды, и собирает это в одну строку msg. Строка очищается от лишних пробелов ( trim()) и переводится в верхний регистр ( toUpperCase()). Это гарантирует, что команда пользователя сработает независимо от регистра букв («data», «Data» или «DATA»).
Затем проверяем, поступила ли команда DATA. Если да — считываем показания с датчика и отправляем их на указанный номер ( String phone = "+7хххххххххх";). Здесь необходимо подставить реальный номер для получения сообщений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void loop() { if (mySerial.available()) { String msg = waitForResponse(2000); Serial.println("Received: " + msg); msg.toUpperCase(); msg.trim(); if (msg.indexOf("DATA") > -1) { float h = dht.readHumidity(); float t = dht.readTemperature(); sms(String("Temp: " + String(t) + "C Hum: " + String(h) + "%"), String("+7хххххххххх")); } } } |
Следующая функция отправляет команду в модем и дублирует её в монитор порта с пометкой >> для удобства отладки.
1 2 3 4 5 |
void sendCommand(const String& cmd) { mySerial.println(cmd); Serial.print(">> "); Serial.println(cmd); } |
Следующая функция в течение заданного времени копирует все приходящие байты из порта в одну строку и возвращает её.
1 2 3 4 5 6 7 8 9 10 11 12 |
String waitForResponse(unsigned long timeout) { unsigned long startTime = millis(); String response = ""; while (millis() - startTime < timeout) { if (mySerial.available()) { char c = mySerial.read(); response += c; } } return response; } |
Последней функцией отправляем сообщение.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void sms(String text, String phone) { Serial.println("\nSending SMS..."); sendCommand("AT+CMGS=\"" + phone + "\""); if (waitForResponse(5000).indexOf('>') > -1) { mySerial.print(text); mySerial.write(26); // Ctrl+Z delay(3000); Serial.println("SMS Sent command executed."); } else { Serial.println("Failed to enter SMS prompt."); } } |
Полезные ссылки
| № | Описание | Скачать |
|---|---|---|
| 1 | Библиотека Adafruit Unified | Adafruit Unified Sensor v.1.1.15.zip |
| 2 | Библиотека для DHT11 | DHT sensor library v.1.4.7.zip |