В этой статье цикла будут подробно описаны AT-команды, правильное программирование отправки AT-команд и получения ответов на них, подключение динамика и микрофона для осуществления звонков, отправка и получение SMS-сообщений, управление при помощи SMS. |
|
04 |
Для полноценной работы с GSM/GPRS-модулем SIM800L понадобится официальный справочник по AT-командам — SIM800 Series_AT Command Manual_V1.10.pdf (4,01 MB).
|
|
05 |
Перед тем как приступить к программированию взаимодействия с GSM-модулем, необходимо ознакомиться с типами AT-команд. |
|
06 |
Синтаксис AT-команд Как уже было сказано выше, общение с модулем происходит при помощи AT-команд. Каждая AT-команда должна начинаться с двух букв AT, набранных в любом регистре: AT, aT, At, at. Команда должна начинаться с новой строки(параметр Newline в окне Serial). |
|
07 |
Все AT-команды синтаксически делятся на 3 основные группы: базовые, с параметром S и расширенные. |
|
08 |
Базовые команды имеют следующий синтаксис: AT<x><n> или AT&<x><n>, где <x> является командой, а <n> — передаваемым параметром(параметрами). Параметр(-ы) <n> является необязательным и в случае его отсутствия будет использовано значение по-умолчанию. Примерами могут служить, отправляемая ранее, команда ATI, возвращающая идентификационные данные модуля, или команда AT&V возвращающая текущую конфигурацию модуля. |
|
09 | На заметку: |
Команды ATV и AT&V — это разные команды.
|
|
10 |
Команды с параметром S выглядят следующим образом: ATS<i>=<m>, где <i> — индекс S-регистра, а <m> — значение, которое ему необходимо присвоить. В случае отсутствия значения <m>, будет присвоено значение по-умолчанию. Например, регистр ATS0 отвечает за количество гудков перед автоматическим ответом на входящий вызов, и, соответственно, команда ATS0 установит значение по умолчанию — 0(не отвечать на вызов), а команда ATS0=2 заставит отвечать модуль автоматически после 2 гудка. |
|
11 |
Расширенные команды могут вызываться в нескольких режимах: |
AT-команды(от англ. ATtention —«внимание») — набор команд, состоящий из серий коротких текстовых строк, которые объединяются вместе, чтобы сформировать полные команды операций, таких как набор номера, начала соединения или изменения параметров подключения.
Подробно с полным набором AT-команд можно ознакомиться в официальном руководстве — SIM800 Series_AT Command Manual_V1.09.pdf (3,07 MB) |
12 |
|
|
13 |
Примером использования расширенных команд могут являться команды для управления FM-радио — AT+FMOPEN, AT+FMCLOSE и т.д. Об этом будет подробно рассказано в соответствующем разделе данной статьи. |
|
14 |
В качестве примера данной группы команд, также можно привести команду AT+IPR. Командой AT+IPR=? можно узнать значения, которые может принимать параметр. Командой AT+IPR? можно узнать текущую скорость обмена данными с модулем, а командой AT+IPR=<...> — задать другую скорость. |
|
16 | На заметку: |
Для того, чтобы использовать скорости выше 9600 бод, необходимо спаивать элементы схемы. В схеме, собранной на макетной плате, при обмене данными на высоких скоростях возникают проблемы.
|
|
17 |
В одной строке можно указывать несколько команд. Все последующие команды(исключая первую) записываются без префикса AT. После каждой расширенной команды необходимо ставить точку с запятой ;. После базовых команд или команд с параметром S, точка с запятой ; не нужна. Пример: |
|
18 |
1
ATV0E1+DDET=1,0,1;Q0S0=1+CLIP=1;+CMGF=1;&W
|
|
19 |
Длина всей строки с несколькими командами не должна превышать 556 символов(не считая начального префикса AT). |
|
20 |
AT-командой A/ можно повторить предыдущую команду. |
|
21 |
За дублирование в терминале отправленной команды отвечает параметр Echo Mode. Для изменения значения этого параметра существует команда ATE<value>, где <value> — значение параметра, 0 — выключен, 1 — включен(по умолчанию). Например, команда ATE0 отключит этот режим, а команда ATE1 включит. |
|
22 |
Существует также команда ATV<value>, которая отвечает за формат ответов модуля на отправляемые команды — текстовый(<value>=1, по-умолчанию, ответы вида OK, CONNECT, RING, ERROR и т. д.) и цифровой код(<value>=0, ответы вида 0, 1, 2, 3 и т. д.). Например, команда ATV0 включит цифровой формат ответов, а команда ATV1 — текстовый. |
Подробно, таблица соответствия цифровых кодов текстовым, приведена в разделе 2.2.25 Справочника по AT-командам (3,07 MB))
|
23 |
Работа с ошибками Как правило, в ответ на отправленные команды, в случае успешного их исполнения, модуль возвращает OK. Но если команда не была исполнена, модуль сообщит об ошибке исполнения. |
|
24 |
В модуле SIM800L существует параметр, устанавливающий степень информативности выпадающих ошибок. |
|
|
26 |
Для работы через терминал в ручном режиме удобно использовать значение этого параметра 2 — AT+CMEE=2. |
|
27 |
Теперь, после установки расширенного информирования об ошибках, можно попробовать отправить несуществующую команду ATE?, на что модем ответит развернуто: +CME ERROR: unknown(неизвестная команда). |
|
28 |
Незапрашиваемые уведомления Есть ещё одна категория сообщений получаемых от модуля — незапрашиваемые уведомления. Это сообщения, которые, как видно из названия, могут приходить без совершения пользователем каких-либо действий. |
|
29 |
Самыми распространенными примерами незапрашиваемых уведомлений, являются: |
Незапрашиваемое уведомление или незапрашиваемый код результата(англ. Unsolicited notification, Unsolicited Result Code) — сообщение от GSM-модуля, генерируемое самим модулем в ответ на изменение своего состояния, не спровоцированное отправленной AT-командой.
Полный перечень незапрашивамых уведомлений приведен в разделе 19.3 Справочника по AT-командам (3,07 MB)) |
30 |
|
|
31 | На заметку: |
Команды ATE и ATV никак не влияют на формат незапрашиваемых уведомлений(Unsolicited Result Code).
|
|
32 |
О сохранении установленных параметров Несмотря на то, что модуль SIM800L это сложное устройство со своей энергонезависимой памятью, не каждый параметр, установленный какой-либо AT-командой, может быть в ней сохранен. В документации по AT-командам, у каждой команды есть свойство Режим сохранения(Parameter Saving Mode), которое дает пользователю информацию о том, что случится с установленным параметром после перезагрузки устройства. Это очень важное свойство AT-команд, необходимо учитывать при написании программ. Например, в программе используется АОН(автоматический определитель номера), который включается командой AT+CLIP=1. Но этот параметр не сохраняемый, а значит активировать его нужно при каждом запуске. В то же время режим DTMF(активируется командой AT+DDET=1), может быть сохранен и после перезагрузки его значение не изменится. |
|
33 |
Поведение каждого из параметров, характеризуется одним из трех значений свойства Parameter Saving Mode:
|
|
34 |
Как правильно программировать взаимодействие с модемом — команды и ответы Программирование взаимодействия с модулем не такая очевидная задача, какой кажется на первый взгляд. |
|
35 | На заметку: |
В готовых проектах, в целях экономии памяти МК рекомендуется использовать комбинацию параметров: отключенный Echo Mode(ATE0), цифровой формат ответов модуля(ATV0) и цифровой код ошибок(AT+CMEE=1). Для единовременной установки всех параметров можно выполнить следующую команду(&W от AT&W — сохранить):
1
ATE0V0+CMEE=1;&W
В образовательных целях и тестировании ПО: включенный(по умолчанию) Echo Mode(ATE1), текстовый(по умолчанию) формат ответов модуля(ATV1) и текстовый код ошибок(AT+CMEE=2). 1
ATE1V1+CMEE=2;&W
|
|
36 |
Все примеры далее выполняются после, единожды выполненной в терминале, команды ATE1V1+CMEE=2;&W. |
|
37 |
На выполнение каждой команды модулю требуется время. Отправив модулю последовательно несколько команд, он, прекрасно справится и отчитается об успешном выполнении. |
|
38 |
|
|
39 |
Ответ на вторую команду пришел четвертым. Причем порядок исполнения постоянно меняется.
|
|
40 |
Но при внимательном рассмотрении видно, что порядок ответов не совпадает с порядком отправленных команд, а это значит, что невозможно однозначно идентифицировать соответствие пришедшего ответа отправленной команде. |
|
41 |
Но что произойдет, если в списке команд будет команда, которая исполнится с ошибкой(AT+DDET=1,0,3)? |
|
42 | Arduino (C++) |
#include void setup() { void loop() { |
|
44 |
Вряд ли кто-то со 100% уверенностью сможет сказать, в ответ на исполнение каких команд модуль ответил OK, в какой команде ошибка, и какова судьба последней команды AT+CLIP=1? |
|
45 |
Первой мыслью, которая может прийти в голову — дожидаться выполнения каждой команды, и потом отправлять следующую. А паузу мы можем делать при помощи функции delay(): |
|
46 | Arduino (C++) |
#include void setup() { void loop() { |
|
47 |
Запустив скетч, можно с удивлением обнаружить, что после команды AT+DDET=1,0,3 наступает глубокая неизвестность о её дальнейшей судьбе и судьбе последней команды. |
|
48 |
Что дальше?...
|
|
49 |
Такой же ошибкой грешит большинство примеров в сети по отправке SMS. Некорректный пример: |
|
50 | Arduino (C++) |
void sendSMS(String phone, String message) // Некорректный пример
{ SIM800.print("AT+CMGF=1\r"); // Устанавливаем текстовый (не PDU) формат сообщений delay(100); // Даем модулю отработать команду SIM800.println("AT+CMGS=\"" + phone + "\""); // Задаем номер телефона адресата delay(100); SIM800.println(message); // Вводим сообщение delay(100); SIM800.println((char)26); // Уведомляем GSM-модуль об окончании ввода delay(100); SIM800.println(); delay(4000); // Ожидаем отправки } |
|
51 | Важно: |
Неправильно устанавливать паузы для того, чтобы дать модулю выполнить команду. Дело в том, что во время ожидания МК«парализован» и игнорирует всю информацию отправляемую модулем.
|
|
52 | На заметку: |
Корректная функция отправки SMS будет приведена в соответствующем разделе ниже
|
|
53 |
Более корректным является подход, при котором МК остановит исполнение программы до тех пор, пока не будет получен ответ на отправленную команду. Для этого, автор предлагает использовать следующие 2 функции — sendATComand() и waitResponse(): |
|
54 | Arduino (C++) |
String sendATCommand(String cmd, bool waiting) { String waitResponse() { // Функция ожидания ответа и возврата полученного результата |
|
55 |
В функции sendATCommand(cmd, waiting) первый параметр содержит отправляемую команду, а второй параметр waiting задает, нужно ли программе дожидаться ответа от GSM-модуля или нет. |
|
56 | На заметку: |
Если Echo Mode выключен, строки 8-10 в предыдущем коде(функция sendATCommand()) можно закомментировать.
|
|
57 |
При таком подходе, появляется возможность, во-первых, дожидаться ответа от модуля, когда это необходимо, а во-вторых, появляется возможность анализировать полученный ответ: |
|
58 | Arduino (C++) |
#include // Библиотека програмной реализации обмена по UART-протоколу String _response = ""; // Переменная для хранения ответа модуля do { Serial.println("CLI enabled"); // Информируем, что АОН включен String sendATCommand(String cmd, bool waiting) { String waitResponse() { // Функция ожидания ответа и возврата полученного результата void loop() { |
|
59 |
Все команды строго по порядку, друг за другом, вне зависимости от статуса исполнения
|
|
60 |
Теперь остается немного модифицировать процедуру loop() таким образом, чтобы можно было анализировать прочие незапрашиваемые ответы и уведомления в основном теле программы: |
|
61 | Arduino (C++) |
void loop() {
if (SIM800.available()) { // Если модем, что-то отправил... _response = waitResponse(); // Получаем ответ от модема для анализа Serial.println(_response); // Если нужно выводим в монитор порта // ... здесь можно анализировать данные полученные от GSM-модуля } if (Serial.available()) { // Ожидаем команды по Serial... SIM800.write(Serial.read()); // ...и отправляем полученную команду модему }; } |
|
62 |
Здесь и далее, предлагается использовать данный шаблон в качестве основы для написания программ: |
|
63 | Arduino (C++) |
#include // Библиотека програмной реализации обмена по UART-протоколу String _response = ""; // Переменная для хранения ответа модуля } String sendATCommand(String cmd, bool waiting) { String waitResponse() { // Функция ожидания ответа и возврата полученного результата void loop() { |
|
64 |
Входящие/исходящие вызовы Возможны ситуации, когда необходимо воспользоваться голосовыми функциями модуля SIM800L, а именно осуществлять исходящие звонки в качестве оперативных уведомлений, либо принимать входящие звонки, для осуществления управления по DTMF. Для использования голосовых функций по прямому назначению, к аудиоинтерфейсам микрофона(MICP и MICN) и колонок(SPKP и SPKN) можно напрямую подключить раздельные динамик и микрофон: |
|
66 |
Либо проводную гарнитуру, через разъем Jack 3.5 мм PJ-342: |
|
67 |
|
|
68 |
В данном примере полярность подключения значения не имеет
|
|
69 |
Основные команды для управления голосовыми функциями представлены в таблице: |
|
|
71 |
Для осуществления исходящих вызовов используется команда ATD<phonenumber>; где <phonenumber> — номер телефона в любом полном формате — +7928******* или 8928*******, например, ATD+78001000800;. |
|
72 | На заметку: |
Нельзя забывать двоеточие ; в конце команды — в этом случае модем отреагирует сообщением NO CARRIER(не доступно)
|
|
73 |
Добавлено 19.01.2018
|
Для того, чтобы отследить момент ответа на исходящий вызов, необходимо выполнить команду AT+COLP=1. Дело в том, что по умолчанию(AT+COLP=0), модуль ответит ОК, сразу после отправки команды ATD. Команда AT+COLP=1 устанавливает такой режим, при котором, после отправки команды модулю, ответ ОК будет получен, только когда вызов будет принят, иначе — BUSY, NO DIAL TONE, NO CARRIER. |
|
74 |
Ответить на входящий звонок в ручном режиме можно командой ATA. Либо командой ATS0=<n> можно установить возможность автоматического ответа после <n>-гудков. |
|
75 | На заметку: |
Исходящий вызов, также как и уже установленное соединение, можно отменить/прервать командой ATH. Отмена невозможна в некоторых состояниях, например, во время установки соединения.
|
|
76 |
Для того, чтобы реагировать на входящие звонки, нужно отслеживать незапрашиваемое уведомление RING, и далее предпринимать действия — либо отвечать на входящий вызов командой ATA, либо сбрасывать его командой ATH. |
|
77 | На заметку: |
Для того, чтобы автоматически отвечать на все входящие вызовы достаточно один раз установить автоответ командой ATS0=1.
|
|
78 | Arduino (C++) |
#include // Библиотека програмной реализации обмена по UART-протоколу String _response = ""; // Переменная для хранения ответа модуля sendATCommand("AT", true); // Отправили AT для настройки скорости обмена данными // Команды настройки модема при каждом запуске String sendATCommand(String cmd, bool waiting) { String waitResponse() { // Функция ожидания ответа и возврата полученного результата void loop() { |
|
80 |
Чтобы обеспечить индивидуальный подход к каждому вызову необходимо включить автоопределитель номера(АОН) — команда AT+CLIP=1(по умолчанию отключен). После того как АОН включен, каждое незапрашиваемое уведомление RING будет дополнительно содержать информацию о номере телефона: |
|
82 |
Теперь нетрудно сделать белый список телефонных номеров, на которые модуль будет автоматически отвечать. Все входящие вызовы с посторонних номеров, не включенных в белый список, будут сбрасываться: |
|
83 | Arduino (C++) |
#include // Библиотека програмной реализации обмена по UART-протоколу String _response = ""; // Переменная для хранения ответа модуля sendATCommand("AT", true); // Отправили AT для настройки скорости обмена данными // Команды настройки модема при каждом запуске String sendATCommand(String cmd, bool waiting) { String waitResponse() { // Функция ожидания ответа и возврата полученного результата void loop() { |
|
85 |
Прием/отправка/удаление SMS Тема, которая акутальна при взаимодействии с GSM-модулем в 95% случаев — это, конечно же, прием и отправка SMS, при помощи которых происходит удаленное управление чем-либо, например, микроконтроллером. |
|
86 | На заметку: |
В данном разделе будет рассмотрена работа с SMS в текстовом формате(Text Mode), все примеры будут также приведены для работы с SMS в текстовом формате. Работа с SMS в PDU-формате(PDU mode) — тема отдельной статьи и здесь будет опущена. Текстовый формат намного проще, но он не позволяет обмениваться SMS-сообщениями на языках, отличных от английского. PDU-формат имеет более обширные возможности, но достаточно сложен в освоении и использовании.
|
|
87 |
Для взаимодействия с SMS существует внушительный список команд. Самые используемые из них приведены в таблице: |
|
|
89 | На заметку: |
В любом случае, команд для работы с SMS немного больше и все они подробно описаны в официальном мануале по AT-командам (3,07 MB) в 4 разделе.
|
|
90 |
Перед работой с SMS, для использования текстового формата, его нужно включить командой AT+CMGF=1. Поскольку этот параметр сохраняется по команде AT&W, в скетче он будет устанавливаться в начале в формате«несколько команд в одной строке»: AT+CMGF=1;&W |
|
91 |
Отправка SMS. Формат отправки SMS в текстовом формате выглядит следующим образом:
|
|
92 | На заметку: |
Как отправить комбинацию клавиш Ctrl+Z или символ ESC через командную строку терминала Serial?
Если отправка SMS осуществляется через окно Serial среды Arduino IDE, то после ввода основного текста сообщения необходимо отправить модулю команду завершения SMS — Ctrl+Z. Сделать это можно копированием символа между кавычками " " и последующей его вставкой в поле отправки данных. Чтобы отправить символ ESC(для отмены сообщения) нужно скопировать его между этими кавычками — " " . |
|
93 |
Пример программной отправки SMS(для удобства, функционал отправки SMS вынесен в отдельную функцию sendSMS()). В данном примере также используется контроль статуса отправки. В случае неудачной попытки отправки, сообщение об этом появится в терминале: |
|
94 | Arduino (C++) |
#include // Библиотека програмной реализации обмена по UART-протоколу String _response = ""; // Переменная для хранения ответа модуля sendATCommand("AT", true); // Отправили AT для настройки скорости обмена данными // Команды настройки модема при каждом запуске sendSMS("+7928xxxxxxx", "test message"); } String sendATCommand(String cmd, bool waiting) { String waitResponse() { // Функция ожидания ответа и возврата полученного результата void loop() { if (result == "OK") { // Если результат ОК - все нормально void sendSMS(String phone, String message) |
|
96 |
Прием и чтение SMS. Здесь не так все просто, как при отправке сообщений. Дело в том, что все принятые сообщения хранятся в памяти SIM-карты. И память эта ограничена. Объем памяти можно узнать командой AT+CPMS?. Если допустить переполнение памяти, сообщения больше не смогут приходить. Поэтому, чтобы сохранить работоспособность приложения, после получения каждого сообщения, его нужно обрабатывать и удалять. Мануал предоставляет большой набор команд, при помощи которых можно совершать любые манипуляции с принятыми сообщениями. |
|
97 |
Во время прихода SMS, SIM800L генерирует незапрашиваемое уведомление вида +CMTI: "SM",4. После прихода такого уведомления, можно программно инициировать процедуру чтения полученного сообщения командой AT+CMGR=<index>,<mode>, где в качестве параметра <index> необходимо указать индекс, полученный в уведомлении — +CMTI: "SM",4. В приведенном ниже примере, после получения и обработки пришедшего сообщения, все сообщения удаляются командой AT+CMGDA="DEL ALL" для экономии памяти модуля: |
|
98 | Arduino (C++) |
#include // Библиотека програмной реализации обмена по UART-протоколу String _response = ""; // Переменная для хранения ответа модуля sendATCommand("AT", true); // Отправили AT для настройки скорости обмена данными // Команды настройки модема при каждом запуске } String sendATCommand(String cmd, bool waiting) { String waitResponse() { // Функция ожидания ответа и возврата полученного результата void loop() {
void parseSMS(String msg) { msg = msg.substring(msg.indexOf("+CMGR: ")); msgbody = msg.substring(msgheader.length() + 2); int firstIndex = msgheader.indexOf("\",\"") + 3; Serial.println("Phone: "+msgphone); // Далее пишем логику обработки SMS-команд.
void sendSMS(String phone, String message) |
|
100 |
Ну а что произойдет, если МК пропустит незапрашиваемое уведомление о приходе SMS? Ему придется ждать прихода следующего сообщения, что является неприемлемым сценарием. И если будет принято сразу несколько сообщений — будет обработано только последнее. Для подстраховки от таких ситуаций необходимо ввести периодическую(например, раз в минуту) проверку наличия непрочитанных сообщений. В случае наличия таковых, каждое сообщение из списка будет обработано и удалено. Пример скетча приведен ниже в разделе об управлении по SMS. |
|
101 |
Управление по SMS Для демонстрации возможностей управления с обратной связью будет использоваться следующая схема с 3 светодиодами: |
|
102 |
Резисторы для подключения светодиодов 100 Ом, для подключения модуля — 10 КОм
|
О там как правильно подключать светодиоды и каких ошибок следует избегать при их подключении написано в статье Как правильно подключать светодиоды |
103 |
Команды будут состоять из двух цифр — первая цифра будет обозначать номер светодиода(1-3), вторая — его состояние(1 — включен, 0 — выключен). Получается, что допустимых команд(сочетаний цифр) всего 6: 11, 10, 21, 20, 31, 30. Прочие команды будут игнорироваться. Информация о статусе исполнения или некорректности команды, будет выводиться в терминал. Скетч: |
|
104 | Arduino (C++) |
#include // Библиотека програмной реализации обмена по UART-протоколу int pins[3] = {5, 6, 7}; // Пины с подключенными светодиодами String _response = ""; // Переменная для хранения ответа модуля String phones = "+7928xxxxxxx, +7920xxxxxxx, +7918xxxxxxx"; // Белый список телефонов void setup() { sendATCommand("AT", true); // Отправили AT для настройки скорости обмена данными // Команды настройки модема при каждом запуске String sendATCommand(String cmd, bool waiting) { String waitResponse() { // Функция ожидания ответа и возврата полученного результата bool hasmsg = false; // Флаг наличия сообщений к удалению if (SIM800.available()) { // Если модем, что-то отправил... void parseSMS(String msg) { // Парсим SMS msg = msg.substring(msg.indexOf("+CMGR: ")); msgbody = msg.substring(msgheader.length() + 2); int firstIndex = msgheader.indexOf("\",\"") + 3; Serial.println("Phone: " + msgphone); // Выводим номер телефона if (msgphone.length() > 6 && phones.indexOf(msgphone) > -1) { // Если телефон в белом списке, то... void setLedState (String result, String phone) {
void sendSMS(String phone, String message) |
|
105 |
Далее также не составит труда получить необходимую информацию и задать требуемую логику приложения. |
|