STM32 - GPRS





Здравствуйте.

Продолжение описания работы с GSM-модемом и stm32. В предыдущей статье рассматривалось взаимодействие с модемом как с телефоном (звонки, смс), а здесь рассказано как передавать/получать данные через GPRS.

HTTP пример
TCP пример


Как и в предыдущем примере (ознакомьтесь), здесь используются два USART'а, один таймер и выход для светодиода. То есть ничего нового за исключением одного — добавлен выход (PA0) для управления реле через которое запитан модуль…



Это нужно чтобы вместе с ресетом платы модуль обесточивался и сбрасывал все свои настройки. Рекомендую это сделать, чтоб было меньше непоняток.


Работает следующим образом:

При старте, автоматически устанавливается скорость USART'а — 57600, и начинают отсылаться команды настройки с помощью функции set_comand(...) (файл gprs.c). Посылая эти команды программа проверяет ответы модуля, и в случае ошибки выполнение программы приостановится, а светик (PA7) начнёт мигать.


Передавать/получать данные можно несколькими способами — TCP/UDP, HTTP, FTP. Я сделал два отдельных примера, первый для передачи по HTTP, а второй по TCP. Через HTTPS тоже можно, но нужно загружать в модуль сертификат — этого я не пробовал, поэтому ничего не расскажу.


HTTP


Предварительная настройка производится в начале программы, в блоке…

/*------------------- БЛОК HTTP START --------------------*/
//////////////////// HTTP НАСТРОЙКА /////////////////////
 set_comand(ATCGATT1);      // включить GPRS сервис 
...



Всё происходящее (и успешные команды, и ошибки) выводится в терминал.

В блоках обработки ошибок…

while(1) // мигаем 5 секунд и ресетим плату
{
	count_err++;
	HAL_GPIO_TogglePin(ER_LED_GPIO_Port, ER_LED_Pin);
	HAL_Delay(100);
	//if(count_err > 49) HAL_NVIC_SystemReset();
}

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


Всё что связано c отправкой/получением по HTTP, находится в функции send_http(...). Функция передаёт два аргумента (для примера две цифры), которые отправляются на сервер GET-запросом…

void send_http(uint8_t a, uint8_t b)
{
  char buf[64] = {0,}; // строка должна быть не больше 64 символов
  snprintf(buf, 64, "AT+HTTPPARA=\"URL\",\"http://some_site.ru/gsm.php?a=%d&b=%d\"\r\n", a, b); // адрес страницы
  //snprintf(buf, 64, "AT+HTTPPARA=\"URL\",\"http://example.com/\"\r\n");
  ...


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




Чтобы отправить данные на сервер, нужно чтоб у вас был этот самый сервер , а для проверки работы надо создать на нём файлик gsm.php

<?php
  $today = date("Y.m.d H:i:s"); //получаем текущие дату и время
  $argument_a = $_REQUEST['a']; //получаем значение посланной переменной "а"
  $argument_b = $_REQUEST['b']; //получаем значение посланной переменной "b"
  echo "Hello, reciv - "." $argument_a "." $argument_b ".", date - ". "$today";
?>


Раскомментить верхнюю строчку и вписать в неё ваш адрес. Аргументов может быть больше, но нужно следить за тем, чтобы строка (начиная с AT...) была не больше 64-ёх символов.

Если строка получается больше, тогда отправлять её нужно частями, и только последняя часть должна содержать символы \r\n.

То есть, если строка у вас такая...

"AT+HTTPPARA=\"URL\",\"http://some_site.ru/bla_bla_bla_bla_bla_bla_bla_bla_bla/gsm.php?a=45&b=78\"\r\n"   // 93 символа


Тогда отправка будет выглядеть так...

snprintf(buf, HTTP_BUFF_SIZE, "AT+HTTPPARA=\"URL\",\"http://some_site.ru/bla_bla_bla_bla_bla");
HAL_UART_Transmit(GSM, (uint8_t*)buf, strlen(buf), 1000);

snprintf(buf, HTTP_BUFF_SIZE, "_bla_bla_bla_bla/gsm.php?a=%d&b=%d\"\r\n", a, b);
HAL_UART_Transmit(GSM, (uint8_t*)buf, strlen(buf), 1000);



Вернётся то, что отправили, и дату/время…



Далее в функции производятся проверки и если всё хорошо, то посылается команда отправки данных — AT+HTTPACTION=0:

AT+HTTPACTION=0 — GET

AT+HTTPACTION=1 — POST

AT+HTTPACTION=2 — HEAD

После этого снова идут проверки и в случае успеха отправляется команда чтения ответа от сервера — AT+HTTPREAD (ниже весь процесс описан чуть подробнее).

Данные вычитываются по 1024 байта (можно увеличить в файле usart_ring.h) и выводятся в терминал. Обрабатывать данные нужно там где написано «тут можно парсить ответ».


///////////////////////////////// чтение ответа сервера /////////////////////////////////////
if(flag)
{
	flag = 0;
	HAL_Delay(500);
	char read_buf[GPRS_RX_BUFFER_SIZE] = {0,}; 

	while(gsm_available())
	{
		uint16_t i = 0;
		memset(read_buf, 0, GPRS_RX_BUFFER_SIZE);

		while(gsm_available())
		{
			read_buf[i++] = gsm_read();
			if(i > GPRS_RX_BUFFER_SIZE - 1) break;
		}

		HAL_UART_Transmit(DEBUG, (uint8_t*)"\n----------\nREAD_BUF:\n----------\n", strlen("\n----------\nREAD_BUF:\n----------\n"), 1000);
		HAL_UART_Transmit(DEBUG, (uint8_t*)read_buf, strlen(read_buf), 1000);

		// тут можно парсить ответ
	}
}

Там у меня ещё есть комменты — «как-то обрабатываем ошибку», я не знаю что лучше делать в этом случае. С одной стороны это может быть разовая ошибка (допустим вы периодически отправляете данные, а сервер по какой-то причине не принял запрос) и дальше всё будет работать нормально, а с другой стороны это может быть долговременная проблема (сбой сервера, сбой модуля, Вселенский апокалипсис), тогда надо что-то делать. Самое простое решение, это добавить туда счётчик ошибок, типа — «если десять раз насчёлкало, тогда ресетим плату», ну или ещё что-то.


Чтоб посмотреть как всё происходит, дайте в терминале команды…

AT+HTTPPARA="URL","http://example.com/"

Вернёт ОК.

AT+HTTPACTION=0

Сначала вернёт ОК. Потом после паузы должно вернуть +HTTPACTION:0,200,1270.

0 — данные были получены GET-запросом.
200 — код ответа сервера.
1270 — кол-во принятых байт.


AT+HTTPREAD

Вернёт +HTTPREAD:1270 и данные.



При отсылке команд через терминал, данные будут вычитываться в функции if(gsm_available()), в бесконечном цикле.


Если в течении некоторого времени (около 4-х часов) ничего не посылать серверу, то происходит разрыв GPRS-соединения, модуль присылает уведомление +SAPBR 1: DEACT. Чтоб восстановить соединение, нужно послать команду AT+SAPBR=1,1. Вручную ничего делать не надо, в коде есть обработка этой ситуации…

else if(strstr(buf, "+SAPBR") != NULL)
{
	if(strstr(buf, "DEACT") != NULL)
	{
		set_comand(ATSAPBR11);     // установить соединение
	}
}



Все команды описаны в файле gprs.h, в разделе «ИНТЕРНЕТ».


Если в бесконечном цикле раскомментировать функцию send_http(57, 69), то данные будут отсылаться раз в минуту…

if(count > 59) // каждые 60 секунд
{
    count = 0;
    //send_http(57, 69);
}



TCP


Здесь почти всё то же самое, различие только в методе запроса к серверу. При старте производятся настройка, проверка и обработка ошибок…



Добавлена функция chek_status(...), для проверки всяких статусов (в коде всё прокомментировано). Находится в файле gprs.c.

Вся работа с сетью происходит в функции send_tcp().

Запрос состоит из следующих команд…

AT+CIPSTART=«TCP»,«example.com»,«80» — отправляем в модуль адрес и порт, в ответ модуль пришлёт — «CONNECT OK». Если вместо имени указать ip — AT+CIPSTART=«TCP»,«134.123.45.67»,«80», тогда можно не настраивать DNS-сервера (команда set_comand(ATCDNSCFG); // установить сервера DNS в начале программы).

AT+CIPSEND — эта команда сообщает модулю, что сейчас будут вводится данные (в примере это «GET /» или «GET /gsm.php?a=33&b=55»). В ответ модуль пришлёт приглашение — символ '>'. После этого можно вводить данные. Чтоб модуль понял что ввод данных закончился и их можно отправлять на сервер, надо послать символ Ctrl + z ((char)26).

Если дать команду так — AT+CIPSEND=23 (цифра — это количество байт для отправки), то модуль отправит данные на сервер после ввода указанного количества символов, при этом Ctrl + z вводить не нужно.

Строка с данными (обычный GET-запрос) выглядит так:

"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: keep-alive\r\n\r\n"


В подтверждение что данные отправлены модуль вернёт «SEND OK». После этого можно ловить ответ от сервера…


Через терминал это ввести не получится. У меня там из середины строки удаляются символы "\r\n", а в конец добавляются.

По завершении приёма данных мы посылаем команду закрытия соединения — «AT+CIPCLOSE». Однако может так случиться, что пока мы вычитываем данные, модуль уже сам (автоматически) закроет соединение, тогда эта команда вернёт ошибку — +CME ERROR: operation not allowed, ничего страшного в этом нет. Кстати, модуль на все ошибки отвечает строкой operation not allowed.

Функция send_tcp() вызывается без каких-либо аргументов, но вам ничего не мешает передавать в неё всё что заблагорассудится.

Если долго ничего не отправлять, то модуль деактивирует GPRS и пришлёт сообщение «DEACT» — эта ситуация обрабатывается в бесконечном цикле.


В примерах предусмотрена возможность позвонить на модуль и при определении номера сделать что-то, например перезагрузку. Другие функции можно добавить из первой части.


Чтобы использовать модуль как сервер, нужно иметь сим-карту с «белым» IP (настройки APN будут другие) и немножко изменить инициализацию. Вместо AT+CIPSTART=«TCP»..., надо дать команду AT+CIPSERVER=1, 80, где 1 означает запуск сервера, а 80 это порт. Когда кто-то соединиться с сервером, модуль выдаст сообщение REMOTE IP: ip клиента. Что делать дальше я точно не знаю ибо не пробовал, но видимо отвечать нужно так же, как в TCP-примере. Отключается сервер командой AT+CIPSERVER=0.


И в довершение, пример для передачи и чтения данных с Thingspeak.


Это всё, если что-то непонятно — пишите в чат.


Всем спасибо


Телеграм-чат istarik

Телеграм-чат STM32


  • 0
  • 15715
Поддержать автора


Telegram-чат istarik

Задать вопрос по статье
Telegram-канал istarik

Известит Вас о новых публикациях






Комментарии (0)

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.