At команды sim900

Работа с GSM-модулем на примере SIM900D

Не так давно друг предложил мне работу, связанную с созданием прошивки для микроконтроллера, который должен был связываться с сервером при помощи GSM-модуля SIM900D. Ранее я с программированием микроконтроллеров дела не имел, да и на C программировал последний раз в студенческие времена, но любопытство перевесило и я принялся за работу. Документация по данной железке присутствует в интернете, однако хороших примеров работы с TCP/IP в коде найти не удалось. Ничего не оставалось, кроме как обложиться документацией, запастись сигаретами и чаем и приступить к лавированию между граблями. А граблей оказалось немало. Собственно, поэтому я и написал эту статью — чтобы другим было легче.
Далее будет много AT-команд, не слишком много кода и очень много букв.

Что было нужно

Требовалось написать код, который мог бы инициализировать GSM-модуль, устанавливать подключение с сервером, получать и отправлять произвольные данные, проверять состояние подключения и работать без сбоев. А также быть достаточно компактным, чтобы уместиться в ограниченной памяти микроконтроллера и оставить место для основной функциональности и еще чуть-чуть про запас.

Что получилось в итоге

Получился код на C, который может все, что было нужно. Из-за требований компактности, разбирать ответы и генерировать строки пришлось при помощи своего кода, который даже стыдно показать честному народу. Поэтому рекомендую всем использовать для этих целей регулярные выражения. Свой код я тоже собираюсь перевести на легковесный движок регулярных выражений, но уже после создания полнофункциональной прошивки.
Код требует функций/макросов для работы с последовательным портом, а также наличия функций memset и memcpy. Так что его с относительной легкостью можно перенести на другую платформу, не зацепив по пути кучу библиотек.

И как оно выглядит?

Программирование и тестирование проводилось под Windows 7. Код, полученный в результате, стал основным материалом для этой статьи. Я не стану приводить код полностью и комментировать его, а вместо этого покажу алгоритм настройки и работы с GSM-модулем.
Функции, которые требуются коду:

  • uint16_t init_serial_port(char *port_name) Эта функция настраивает указанный последовательный порт. Под Windows.
  • uint16_t puts_serial(uint8_t *buffer, uint16_t size) А эта пишет строку байт в этот порт.
  • gets_serial(uint8_t *buffer, uint16_t size) Эта, соответственно, читает строку байт из последовательного порта.

Функции, которые код предоставляет:

  • init_gprs() & stop_gprs() Соответственно инициализируют и вырубают GSM-модуль.
  • uint16_t connect_gprs(uint8_t index, uint8_t mode, char *address, char *port) Устанавливает подключение с сервером. Стоит отметить, что модуль умеет работать с протоколами TCP и UDP как в качестве клиента, так и будучи клиентом. Поддерживается максимум 8 одновременных подключений.
  • uint16_t close_gprs(uint8_t index) Закрывает указанное подключение.
  • uint16_t send_gprs(uint8_t index, uint8_t *buffer, uint16_t size) Отправка сообщения через указанное подключение.
  • uint16_t recv_gprs(uint8_t index, uint8_t *buffer, uint16_t size) Получение сообщения. Неблокирующая функция, что значит она не будет ждать появления данных в потоке, а вернет управление, если получать нечего. Стоит отметить, что такое поведение реализовать проще, чем блокирующее.

Как работать с последовательным портом

Это достаточно просто. Под целевой микроконтроллер есть макросы для отправки/получения данных через USART, но так как отлаживать такой код проще со стационарного компьютера, мне была предоставлена связка из переходника USB<->USART и GSM-модуля. Оставалось только научиться работать с последовательным портом под Windows. Это оказалось просто. Вкратце, последовательный порт представляется в ОС обычным файлом, передача информации осуществляется функциями ReadFile и WriteFile. Нужно только установить кое-какие параметры при помощи функций SetCommTimeouts и SetCommState.
Вот как выглядит функция инициализации порта:
uint16_t init_serial_port(char *port_name) { COMMTIMEOUTS timeouts; DCB parameters; int result; serial_port_handle = CreateFile(port_name, // «\\\\.\\COMx» GENERIC_READ | GENERIC_WRITE, 0, // Значения последующих параметров фиксированы при работе с портом NULL, OPEN_EXISTING, 0, NULL); if (serial_port_handle == INVALID_HANDLE_VALUE) { printf(«Error opening a serial port!\n»); return 1; } // Максимальное время между чтением двух байт подряд timeouts.ReadIntervalTimeout = 100; // Следующее значение умножается на количество читаемых из порта символов timeouts.ReadTotalTimeoutMultiplier = 0; // и прибавляется к этому значению, получается максимальное время на выполнение // всей операции timeouts.ReadTotalTimeoutConstant = 1000; // Значение то же, что и у предыдущих двух параметров, однако таймаут считается на запись. timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 1000; result = SetCommTimeouts(serial_port_handle, &timeouts); if (result == 0) { printf(«Error setting timeouts for serial port!\n»); close_serial_port(); return 1; } // В параметры порта занесены самые простые настройки — без контроля // четности, без управления потоком, 1 стоп-бит. memset(&parameters,0,sizeof(parameters)); parameters.DCBlength = sizeof(DCB); GetCommState(serial_port_handle, &ampparameters); parameters.BaudRate = (DWORD)BAUD_RATE; parameters.ByteSize = 8; parameters.Parity = NOPARITY; parameters.StopBits = ONESTOPBIT; parameters.fAbortOnError = TRUE; parameters.fDtrControl = DTR_CONTROL_DISABLE; parameters.fRtsControl = RTS_CONTROL_DISABLE; parameters.fBinary = TRUE; parameters.fParity = FALSE; parameters.fOutX = FALSE; parameters.fInX = FALSE; parameters.XonChar = (uint8_t)0x00; parameters.XoffChar = (uint8_t)0xff; parameters.fErrorChar = FALSE; parameters.fNull = FALSE; parameters.fOutxCtsFlow = FALSE; parameters.fOutxDsrFlow = FALSE; parameters.XonLim = 128; parameters.XoffLim = 128; result = SetCommState(serial_port_handle, &ampparameters); if (result == 0) { printf(«Error setting serial port parameters!\n»); close_serial_port(); return 1; } return 0; }

Как происходит общение с GSM-модулем

После того, как последовательный порт настроен, в него можно отправлять AT-команды. Первой командой должна быть последовательность «AT\r», позволяющая модулю автоматически настроить скорость передачи по последовательному порту. Ответ, который можно получить после этого из порта, будет выглядеть как «AT\r\r\nOK\r\n».

Команда является простой строкой из ASCII-символов. Чтобы команду воспринял модуль, в ее конце нужно поставить символ перевода каретки «\r». В ответ модуль передаст строку символов, состоящую из двух частей — команды, на которую модуль отвечает и отделенным от нее символами «\r\r\n» ответом, заканчивающимся символами «\r\n». Чтобы было удобнее разбирать ответы я создал макрос, который устанавливает указатель на начало ответа в принимающем буфере. Если хочется вывести ответ в консоль, нужно добавить нулевой символ в конец принятого сообщения.
void at_send(char *cmd, uint16_t size) { uint16_t result; cmd = ‘\r’; result = puts_serial(cmd, size); return; } uint16_t at_recv(uint8_t *buffer, uint16_t size) { uint16_t result; result = gets_serial(buffer, size); return result; }
Примерно так и выглядят вспомогательные функции для отправки команды и получения ответа.

Инициализация модуля

Самая большая функция в коде отвечает за настройку модуля. При инициализации отправляется много AT-команд. Я опишу их в порядке посылки модулю. Специально не расписываю аргументы и варианты ответов подробно, ибо их можно найти в документации.

  • «AT+CPIN=pin-code» Как несложно догадаться, эта команда разблокирует SIM-карту путем ввода пин-кода. Чтобы проверить, требуется ли пин-код, можно использовать команду «AT+CPIN?».
  • «AT+CREG?» Эта команда возвращает статус регистрации модуля в сети. Нужно выполнять ее, пока модуль не ответит, что в сети он зарегистрирован.
  • «AT+CGATT=1» Заставляет модуль подключиться к GPRS. Проверить, подключен ли он, можно командой «AT+CGATT?».
  • «AT+CIPRXGET=1» Включает получение данных, переданных через соединение, вручную. По умолчанию этот параметр отключен и данные передаются в последовательный порт сразу после получения. Это не слишком удобно, хотя и не критично — можно настроить модуль так, чтобы вместе с данными он передавал и заголовки IP, по которым можно определить, от кого был получен пакет. Я решил, что вручную данные получать проще и не ошибся. Как я понял, данная команда воспринимается только GSM-модулями SIM.COM.
  • «AT+CIPMUX=1» По умолчанию модуль может устанавливать только одно подключение. Этот параметр включает возможность создавать несколько подключений. Отправка и прием данных будут отличаться только на один параметр — индекс подключения.
  • «AT+CSTT=»internet»» APN — Access Point Name, имя точки доступа для GPRS. Для моего провайдера выглядит именно так.
  • «AT+CIICR» Устанавливает беспроводное подключение GPRS. Может занять некоторое время, так что ее нужно выполнять в цикле и проверять ответ.
  • «AT+CIFSR» Возвращает IP-адрес модуля. Я использую ее чтобы проверить, подключен ли модуль к интернету.
  • «AT+CDNSCFG=»8.8.8.8″,»8.8.4.4″» Этой командой устанавливаются сервера DNS, которые будет использовать модуль.
  • «AT+CIPSTATUS» Помимо данных о состоянии подключений эта команда дает информацию о том, готов ли модуль к установке соединений. Так что нужно проверить ее ответ.

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

Установка и разрыв подключений

Создание подключения производится командой «AT+CIPSTART=index,»mode»,»address»,»port»».

  • index указывает порядковый номер подключения, может принимать значения от 0 до 7.
  • mode определяет протокол, который будет использоваться соединением. Может быть «TCP» или «UDP».
  • address задает адрес сервера. Если при настройке были указаны DNS-сервера, то можно использовать как IP-адрес, так и доменное имя.
  • port задает порт сервера, с которым будет устанавливаться соединение.

Замечу, что при использовании протокола UDP по умолчанию датаграммы будут отсылаться и приниматься только с одного адреса. Для того, чтобы использовать UDP на полную катушку и отсылать/принимать данные с любых адресов, можно использовать так называемый расширенный режим UDP, настраиваемый командой «AT+CIPUDPMODE». За подробностями отсылаю к документации.
В ответ на команду можно получить несколько вариантов ответов. Если все хорошо, то после стандартного «OK» через небольшой промежуток времени можно получить один из трех ответов:

  • «index,ALREADY CONNECT» это значит, что подключение с заданным индексом уже установлено и стоит его поискать.
  • «index,CONNECT OK» тут все очевидно.
  • «index,CONNECT FAIL» означает, что возникли проблемы с установкой соединения.

Разорвать соединение можно командой «AT+CIPCLOSE=index». Разорвать все соединения и деактивировать интерфейс GPRS можно командой «AT+CIPSHUT».

Передача данных

Данные передаются командой «AT+CIPSEND=index,length», где index указывает подключение, по которому нужно передать данные, а length задает длину пакета данных. Кстати, узнать MTU для каждого подключения можно при помощи команды «AT+CIPSEND=?».
Если все хорошо, то модуль в ответ на команду выдаст приглашение «>», после которого нужно переслать в последовательный порт данные. Как только модуль получит количество байт, равное length, он скажет что-то типа «index,SEND OK». Вообще, можно не использовать параметр length, однако в таком случае окончание пакета данных должно быть указано явно при помощи символа 0x1A, в терминале сочетание Ctrl+Z. Для передачи произвольных данных такой вариант, очевидно, не подходит.
Как видите, передача данных — процесс не слишком сложный. Поэтому переходим к самому интересному — приему данных.

Прием данных

Как только GSM-модуль принимает данные, он сигнализирует об этом, посылая в последовательный порт строку вида «+CIPRXGET:1,index\r\n». Я честно не знаю, что означает единица, ибо данная функция модуля документирована достаточно слабо, но у меня она фигурирует во всех сообщениях о приеме пакета.
Мне не доставляла радости мысль о том, что придется тем или иным образом отслеживать сообщения модуля. Однако, немного поигравшись с дебаггером, я выяснил, что никаких других асинхронных сообщений модуль не посылает, а также то, что после выполнения любой AT-команды это сообщение оказывается в начале буфера. Так как я составил макрос для отделения ответа от команды путем поиска подстроки «\r\r\n», меня это никоим образом не задевало. Так что функция приема данных была реализована достаточно просто.

Так вот, принимать данные можно командой «AT+CIPRXGET=2,index,length». Двойка означает режим приема, в данном случае байты просто высыпаются в последовательный порт. Можно также задать получение данных в виде HEX-текста, видимо, ради предотвращения конфликтов с программным управлением потоком. Мне это не потребовалось, ибо управление потоком я вообще не использую. Параметр length задает размер пакета данных, который мы желаем получить за один раз.
В ответ мы получим нечто вида «+CIPRXGET:2,index,received,excess\r\n__DATA__\r\nOK\r\n». В поле received будет находиться количество байт, находящихся в пакете данных __DATA__, а поле excess будет содержать количество байт, ожидающих своей очереди в буфере модуля. Так что если поле received равно нулю, можно с чистой совестью заявлять, что получать нечего. Собственно, пользуясь этим, я и реализовал неблокирующую функцию для приема данных.

В заключение

Настоятельно рекомендую перед написанием кода освоиться в AT-командах при помощи PuTTY, который прекрасно работает с последовательным портом.
Надеюсь, информация из этой статьи поможет кому-нибудь написать код для своего SIM900. Вполне возможно, что принципы работы с GSM-модулем, изложенные выше, можно применить и к модулям других моделей, а, возможно, и производителей.

Подключение GSM SIM900A к Arduino
Модем SIM900A построен с двухмодульным GSM900 / GSM модемом SIM900A от SIMCOM. Он работает на частотах 900/1800 МГц. SIM900A может автоматически выполнять поиск этих двух диапазонов. Полосы частот также могут быть установлены с помощью AT-команд. Скорость передачи в бодах конфигурируется в диапазоне 1200-115200 по AT-команде. Модем GSM / GPRS имеет внутренний стек TCP / IP, чтобы вы могли подключиться к Интернету через GPRS. SIM900A — это ультракомпактный и надежный беспроводной модуль. Это полноценный GSM / GPRS-модуль в SMT-типа, спроектированный с очень мощным одночиповым процессором, интегрирующим ядро AMR926EJ-S, что позволяет вам использовать небольшие размеры и экономичные решения.
Спецификация
Двухдиапазонные частоты 900/1800 МГц
GPRS многослотовый класс 10/8 GPRS для мобильных станций класса B
Соответствует GSM фазе 2/2 +
Размеры: 24 * 24 * 3 мм
Вес: 3,4 г
Управление через AT-команды (GSM 07.07, 07.05 и SIMCOM с расширенными AT-командами)
Диапазон напряжения питания: 5 В
Низкое энергопотребление: 1,5 мА (спящий режим)
Рабочая температура: от -40 ° C до +85 °
Шаг 1: Элементы

В этой статье вам понадобятся:
1. GSM SIM900A (MINI V3.9.2)
2. Плата Arduino Uno
3. Перемычки
4. Адаптер питания 5В
5. SIM-карта
6. Макетная плата
Шаг 2. Загрузка в SIM900A
1. Вставьте SIM-карту в модуль GSM и заблокируйте ее.
2. Включите питание вашего GSM-приемника, подключив его к 5V и GND
3. Подключите антенну
4. Теперь подождите некоторое время (скажем, 1 минута) и посмотрите мигание индикатора «Status LED» или «Network LED» (D6). // Это займет некоторое время, чтобы установить соединение с мобильной сетью //
5. После успешного установления соединения индикатор состояния / сети будет непрерывно мигать каждые 3 секунды. Вы можете попробовать позвонить на мобильный номер SIM-карты внутри GSM-модуля. Если вы слышите звонок, модуль gsm успешно установил сетевое соединение.
Шаг 3: Схема соединения


Вы можете увидеть вывод TTL с 3VR, 3VT, 5Vr, 5VT, VCC и GND на вашем sim900a около вашего контакта питания. Вам необходимо подключить 5VT GSM к Arduino D9 и 5VR к Arduino D10 для последовательной связи между модулем arduino и sim900a.
Шаг 4: Основные команды AT
1. Чтобы изменить режим отправки смс: AT + CMGF = 1
MySerial.println («AT + CMGF = 1»);
2. Для чтения SMS в текстовом режиме: AT + CNMI = 2,2,0,0,0
MySerial.println («AT + CNMI = 2,2,0,0,0»);
3. Чтобы позвонить: ATD + 60XXXXXXXXX; // заменим X на номер, который вы хотите вызвать, измените +60 на код страны
MySerial.println («ATD + 60XXXXXXXX;»);
4. Отключение / отключение: ATH
MySerial.println («ATH»);
5. Повторный набор номера: ATDL
MySerial.println («ATDL»);
6. Чтобы получить телефонный звонок: ATA
MySerial.println («ATA»);
Шаг 5: Библиотека

SoftwareSerial — это библиотека Arduino, которая обеспечивает последовательную передачу данных через другие цифровые выходы Arduino. Библиотека реплицирует аппаратные функции и выполняет задачу последовательной связи. Чтобы иметь возможность связывать модуль gsm с arduino, вам нужно будет загрузить эту библиотеку и извлечь ее в свои библиотеки Arduino.
Скачать файл: softwareserial.zip.zip (cкачиваний: 275)
Шаг 6: Пример исходного кода


Загрузите исходный код примера ниже и откройте его на вашей Arduino IDE. Выберите вашу плату и порт и загрузите ее в свою плату Arduino Uno.
Скачать файл: sim900amini.rar (cкачиваний: 462)
Шаг 7: Последовательный монитор

После того как вы успешно загрузили исходный код, откройте свой серийный монитор. Последовательный монитор отобразится, как показано на рисунке выше.
Шаг 8: Результат: вызов / повторный набор


1. Когда вы вводите ключ c: чтобы позвонить, gsm прочитает команду ATD и сделает вызов по номеру телефона, который вы загрузили в исходный код.

2. Когда вы вводите ключ h: для разъединения / разговора, gsm прочитает команду ATH и отключит соединение.

3. Когда вы вводите ключ e: для повторного набора, gsm читает команду ATDL и выполняет повторный набор предыдущего номера, который он вызвал

4. Когда есть входящий вызов, вы можете увидеть RING, напечатанный на последовательном мониторе, и вы можете нажать i: чтобы получить звонок, и будет выполнена команда ATA GSM, и вы будете подключены к соединению вызова.
Шаг 9: Результат: отправка и получение SMS


1. Введите ключ для отправки SMS. Номер получателя и текстовое сообщение, напечатанное на серийном мониторе. ПРИМЕЧАНИЕ. Вы можете отредактировать телефонный номер получателя и текстовое сообщение в исходном коде.
2. Когда gsm получит сообщение, текстовое сообщение и номер будут напечатаны на серийном мониторе.
Перевод статьи «Tutorial to Interface GSM SIM900A With Arduino»

Пусть у нас есть сервер, на который нам нужно передать какие-либо данные с удаленного девайса (например передать информацию о температуре, или о давлении или количестве подсчитанных импульсов, или о чем-то другом). Проделаем это мы через GPRS, используя модем SIM900.

В SIM900 встроен tcp/ip стек, а установка связи и управление происходит с помощью AT-команд. Далее описаны команды необходимые для установки соединения.

Общение с SIM900 происходит через USART — скорость USART SIM900 по умолчанию определяет сам — но для этого первой командой должна быть AT (заглавными буквами)

-> AT — первая команда для определения модемом скорости передачи и проверки работоспособности

<- OK — если все хорошо

-> AT+CPIN? — проверка работоспособности SIM карты и наличия отсутствия PIN-кода

<- +CPIN: READY — данный ответ при правильной работоспособности SIM карты и отсутствие PIN-кода

-> AT+CREG? — проверка регистрации в сети

-< +CREG: 0, 1: — ответ указывает на состояние регистрации

-> AT+CGATT? — проверка регистрации в GPRS сети

<- +CGATT: 1 — состояние регистрации в GPRS сети

NOTE: Выход модема STATUS будет выдавать импульсы различной длительности (см. DataSheet) в зависимости от состояния регистрации в GPRS и GSM сети

-> AT+CIPSHUT — сброс всех tcp/ip соединений

<- SHUT OK — все соединения разорваны

-> AT+CIPSTATUS — проверяет состояние инициализации IP стека

<- STATE: IP INITIAL — ответ когда стек проинициализирован

-> AT+CIPMUX=0 настраиваем соединение только с одним сервером

<- OK

-> AT+CSTT= “APN”, “UNAME”, “PWD” — данные настройки выдаются оператором связи, например, AT+CSTT=»internet.mts.ru»,»mts»,»mts»

<- OK

-> AT+CIICR — пытаемся установить GPRS соединение с настройками, заданными предыдущей командой. Ответ от этой команды может задержаться достаточно надолго — вплоть до 2 минут.

<- OK

-> AT+CIFSR — получаем локальный IP адрес

<- xxx.xxx.xxx.xxx — в ответе содержится непосредственно сам IP адрес

-> AT+CIPSTART= “TCP” , “IP-adr”, “TCP-port″ — подключаемся к серверу, указывая IP и TCP порт, например на котором работает сервер, AT+CIPSTART=»TCP»,»81.210.200.174″,»23070″

<- CONNECT OK — ответ при удачном соединение

-> AT+CIPSEND — запрос на посылку сообщения серверу

<- > — в ответе символ готовности, после его получения можно вводить данные, которые надо передать

-> data — данные которые необходимо передать. После ввода данных необходимо указать модему, что сообщение окончено и его надо передавать серверу — для этого передают следующую команду

-> 26 — команда конца сообщения (0x1A) после нее модем передает серверу данные data

-< SEND OK

-> AT+CIPCLOSE — закрытие соединения с сервером или можно вызвать AT+CIPSHUT

Если вы хотите использовать SIM900 как сервер, то вам нужна SIM карта c белым IP адресом. Обычно оператор вместе с такой SIM картой дает новый APN. Таким образом команда AT+CSTT должна указывать на тот APN, который вам дал оператор.

Стартовая инициализация сервера почти такая-же как и описана выше для клиента. Рассмотрим отличия:

Вместо AT+CIPSTART, надо давать команду:

-> AT+CIPSERVER=1, 3000 — где 1 указывает на то, что мы запускаем сервер, а 3000 — номер TCP порта, на котором поднимается сервер. IP адрес сервера — IP адрес SIM карты.

После, необходимо подключиться клиентом к серверу, тогда SIM900 выдаст ответ:

-< REMOTE IP: 10.78.103.220 — 10.78.103.220 — ip адрес, подключившегося клиента.

После можно отправлять данные с SIM900 также, как и было описано выше для клиента.

Для отключения cервера:

Будем использовать команды стандарта GSM07.05.
Перед отправкой сообщения необходимо провести подготовку модуля. Сначала перевести формат передаваемого модулю текста сообщения в текстовый режим командой «AT+CMGF=1\\r».
По умолчанию используется режим PDU, сообщения передаются в HEX-виде, что есть неудобно.
Переключаем кодировку на GSM командой «AT+CSCS=»GSM»\\r».
Кодировка определяет в каком виде будут передаваться номера телефонов, тексты сообщений и USSD-запросы.
Самой удобный является «GSM», где символы представлены в ASCII кодах и их без труда понимает компилятор.
Но есть минусы будет доступна только латиница.
Для кириллицы необходимо использовать режим «UCS2» Unicode. Далее пока рассмотрим вариан с кириллицей

Отправляем СМС-сообщение. а) Посылаем «AT+CMGS=»+79XXXXXXXXX»\\r», получаем в ответ приглашение набрать текст сообщения — символ ‘>’. б) Отправляем текст. По окончании нужно отправить код комбинации клавиш Ctrl+Z (код 0x1A), только тогда модуль поймет, что текст набран и можно посылать сообщение адресату. в)Получаем «OK» — поздравляю, сообщение улетело.

Ниже пример функции отправки:

/** * Отправляет SMS-сообщение * @param number — номер получателя, строка char * @param msg — текст сообщения * @return — OK, если сообщение отправлено, иначе ERROR */ int8_t Sim900_SendSMS (char * number, char* msg) { /// Перевод модуля в режим работы с тектовыми сообщениями if (Sim900_WriteCmdWithCheck(«AT+CMGF=1\r»)) return ERROR; /// Включаем кодировку GSM if (Sim900_WriteCmdWithCheck(«AT+CSCS=\»GSM\»\r»)) return ERROR; Sim900_WriteCmd(«AT+CMGS=\»»); /// Команда отправить SMS Sim900_WriteCmd(number); /// Ввод номера абонента DelayMs(100); /// Задержка на запись Sim900_WriteCmd(«\»\r»); /// Ожидаем символ готовности ввода текста if (Sim900_CompareStr(«>»)) return ERROR; Sim900_WriteCmd(msg); /// Отправляем комбинацию окончания ввода Ctrl+Z PutCharToSim900(0x1A); /// Отправка байта кода Ctrl+Z /// Если нет подтверждения, возвращаем код ошибки if (Sim900_CompareStr(«OK»)) return ERROR; return OK; }

Общение с модулем при работе с СМС построено на индексах.
Каждому сообщению присваивается индекс, по нему мы указываем, какое сообщение прочитать/удалить.
При получении нового сообщения модуль уведомит отправкой в UART «+CMTI: «SM»,INDEX\\r».
Значит в программе МК надо постоянно проверять приемный буфер на наличие данного сообщения, находить INDEX и сохранять его.

/** * Проверяет, принято ли новое собщение, и возвращает его индекс * @return — индекс нового SMS-сообщения */ uint32_t Sim900_EventNewSMS(void) { struct TBufferUsart *buffer = &BUFFER; /// Указатель на буфер UART const int8_t size = 4; char ch; /// Массив для хранения принятого индекса uint8_t i = 0; uint32_t pos; char cmd = «+CMTI: \»SM\»,»; if (buffer->rxflag == RX_COMPLETE) { if (Sim900_CompareStr(cmd) != NULL) { pos = sizeof(cmd) — 1; /// Заполнение массива цифрами индекса while (buffer->rxbuf != ‘\r’){ ch = buffer->rxbuf; } ch = ‘\0’; /// Преобразование строки с индексом в число return ConvertStringToNumber(ch); } } return 0; }

Можно упростить код разбора принятого сообщения с выделением его индекса если использовать библиотечную sscanf. Но дело в том, что sscanf и printf объемны и не всегда уместны во встраиваемых системах.

Зная индекс принятого сообщения, прочитать и удалить его не составит труда. Прочитать одно сообщение — «AT+CMGR=INDEX,0\\r», второй параметр: 0 — обычный режим (по умолчанию) 1 — не изменять состояние сообщения. Получим ответ вида: «+CMGR: “REC UNREAD”,“+79XXXXXXXXX”, «» ,”DATE,TIME”\\r\\nMessage text\\r\\n\\r\\nOK» REC UNREAD — группа сообщений (см. ниже), DATE – дата формата YY/MM/DD, TIME – время в формате hh:mm:ss±hh.

Удалить одно сообщение по индексу — «AT+CMGD=INDEX\\r».

Удалить сообщения по критерию — «AT+CMGD=INDEX,FLAG\\r», где FLAG: 0 — удалить сообщение по индексу (по умолчанию) 1 — удалить все прочитанные сообщения 2 — удалить прочитанные и отправленные сообщения 3 — удалить прочитанные, отправленные и не отправленные сообщения 4 — удалить все сообщения. Исходя из вышеуказанного, удалить все сообщения — «AT+CMGD=1,4\\r».

Прочитать группу сообщений — «AT+CMGL=”GROUP”\\r», где параметр GROUP имеет следующие значения, числовое/текстовое: 0/REC UNREAD — все непрочитанные сообщения; 1/REC READ — прочитанные сообщения, 2/STO UNSENT — все не отправленные, 3/STO SENT — все отправленные, 4/ALL – все сообщения.

Cписок комманд при работе с SMS.

AT+CMGF=1 Включение текстового режима данных AT+CSCS=»GSM» Выбор ASCII кодировки AT+CMGS=(см. выше) Отправка SMS-сообщения +CMTI: «SM»,INDEX Получение индекса нового SMS-сообщения AT+CMGR=INDEX,0 Чтение сообщение по индексу AT+CMGD=INDEX Удаление одного сообщения по индексу AT+CMGD=INDEX,FLAG Удаление сообщения по критерию AT+CMGL=”GROUP” Чтение группы сообщений