|
В этой статье цикла будут подробно описаны 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 |
Далее также не составит труда получить необходимую информацию и задать требуемую логику приложения. |
|







