Отправка и получение SMS, используя GSM модуль SIM300

Отправка и получение SMS, используя GSM модуль SIM300

В этой части статьи мы рассмотрим функции, связанные с текстовыми сообщениями. К концу этой статьи вы будете иметь точное представление о том, как ожидать текстовое сообщение, читать сообщение, отправлять новое текстовое сообщение и удалять полученное сообщение. Мы уже разбирали основы в предыдущей статье . В ней приводиться схема и команды с примером кода для модуля SIM300.

После прочтения предыдущей статьи вы узнали, как соединить SIM300, AVR ATmega32 и ЖК-дисплей, чтобы получить испытательный стенд. Кроме того, в статье подробно рассматривается  асинхронная последовательная связь между SIM300 и микроконтроллером AVR, которая осуществляется с помощью AVR USART. В статье показано использование библиотеки AVR USART для передачи и приема данных в/от GSM модуля. Мы также рассмотрели функцию возврата команды, используемую для работы с модулем, работа с ней показана в демонстрационном коде. Все эти команды используются в этой статье, поэтому мы рекомендуем вам прочесть предыдущую статью и собрать демонстрационный проект, показанный там.

Ожидание текстового сообщения (SMS)

Если текстовое сообщение (SMS) поступает на GSM модуль SIM300, то он отправляет незапрашиваемый ответ <CR> <LF> + CMTI: <mem>, <n> <CR> <LF>

В предыдущей статье уже говорилось, что <CR> является управляющим символом,  ASCII код которого  0D(Hex) и <LF>,  ASCII код которого 0A (Hex). Вы узнаете о новой вещи – незапрашиваемый ответ. Ранее говорилось, что за командой следует ответ. Но ответ показанный выше, не привязан к команде и может прийти в любой момент. Это незапрашиваемый ответ (unsolicited response).

Значение mem обозначает место хранения SMS сообщения. Обычно это значение SM, что означает память SIM-карты.

Значение n означает ячейку, в которой хранится SMS. В зависимости от размера памяти вашей SIM-карты, в ней 20 или около того ячеек. При получении сообщения, оно сохраняется с наименьшим номером в пустую ячейку.  Допустим, вы получили 4 сообщения, и удалили 1, и тогда 5 сообщение сохраниться в первую ячейку.

Пример кода, показывающий ожидание текстового сообщения:

int8_t SIM300WaitForMsg(uint8_t *id) { //Wait for a unsolicited response for 250ms uint8_t len=SIM300WaitForResponse(250); if(len==0) return SIM300_TIMEOUT; sim300_buffer[len-1]=’\0′; //Check if the response is +CMTI (Incoming msg indicator) if(strncasecmp(sim300_buffer+2,”+CMTI:”,6)==0) { char str_id[4]; char *start; start=strchr(sim300_buffer,’,’); start++; strcpy(str_id,start); *id=atoi(str_id); return SIM300_OK; } else return SIM300_FAIL; }

Анализ кода

1. Мы ждем ответа от SIM300 с тайм-аутом 250 миллисекунд. Это значит, что если ничего не приходит в течение 250 миллисекунд, мы перестаем ждать!

2. Если мы получили ответ, функция SIM300WaitForResponse () сообщает его длину до последнего <CR>. Поэтому если мы получили ответ <CR><LF>+CMTI: SM,1<CR><LF> то len будет 14.

3. Следующая строка sim300_buffer[len-1]=’\0′; Ставит нулевое значение на место len-1, и теперь у нас 13 знаков (конец ответа <CR>). Ответ становится таким <CR><LF>+CMTI: SM,1

4. Теперь мы проверяем, что первые 6 символов +CMTI: , вернее, мы проверяем первые 6 символов только потому, что за +CMTI следует <n>. Как вы помните, это номер ячейки, в которой хранится сообщение. Также при сравнении мы пренебрегаем регистром, а это значит, что CMTI+ или +cMtI совпадают. Этот тип сравнения легко реализуется с помощью стандартной функции strncasecmp () из стандартной библиотеки С . Если вы учили C, то вы должны помнить STRCMP(), и поймете strncasecmp ().В названии функции добавилось только n и case. n в названии указывает на то, что не нужно сравнить всю строку, а нужно проверить только первые n букв. case в названии указывает на сверку без учета регистра. Также вы заметили, что мы сравниваем не непосредственно sim300_buffer (в нем находиться ответ), а используем sim300_buffer+2, что убирает первые <LF><CR> в ответе.

5. Если ответ верен, то необходимо извлечь значение <n>, то есть номер ячейки в которой хранится сообщение. Поэтому мы ищем первую запятую (,) в ответе. Это делается с помощью функции strchr() из стандартной библиотеки. Запустите функцию указав строку с ",1".

6. Мы запускаем поиск командой start++, и находим строку с ",1", но помните, что это ещё строка. Поэтому мы используем стандартную функции библиотеки atoi(), которая преобразует строку в целое число. Его мы храним в *id. Помните, что параметр id переходит по ссылочному типу, если вы не знаете этого, то перечитайте вашу книгу по C.

7. Наконец мы отравляем константу SIM300_OK, которая указывает на успех и определенна в sim300.h

Чтение содержания текстовых сообщений

Для чтения текстового сообщения используется команда AT+CMGR=<n> где <n> целое значение, обозначающее номер ячейки из которой необходимо считать сообщение.  Как я уже говорил, что их несколько слотов для входящих сообщений.

Ответ выглядит так:

+CMGR: "STATUS","OA",,"SCTS"<CR><LF>Message Body<CR><LF><CR><LF>OK<CR><LF>

STATUS показывает состояние сообщения. Его значение может быть REC UNREAD или REC READ.

ОА – Originating Address (Адрес отправителя). Показывает номер мобильного телефона отправителя.

SCTS (Service Center Time Stamp) – Время получения сообщения

Этот простой пример для того, чтобы убрать лишнюю информацию, т.е. STATUS, OA и SCTS и получить только само сообщение.

При попытке чтения сообщения может случиться три события:

1. Успешное чтение. В этом случае мы получаем ответ показанный выше.

2. Пустая ячейка! Это означает, что была сделана попытка чтения содержимого ячейки, но она пуста. В этом случае ответ такой: <CR><LF>OK<CR><LF>

3. SIM-карта не готова! В этом случае возвращается ошибка +CMS ERROR: 517.

Наша функция обрабатывает все три ситуации.

int8_t SIM300ReadMsg(uint8_t i, char *msg) { //Clear pending data in queue UFlushBuffer(); //String for storing the command to be sent char cmd[16]; //Build command string sprintf(cmd,”AT+CMGR=%d”,i); //Send Command SIM300Cmd(cmd); uint8_t len=SIM300WaitForResponse(1000); if(len==0) return SIM300_TIMEOUT; sim300_buffer[len-1]=’\0′; //Check of SIM NOT Ready error if(strcasecmp(sim300_buffer+2,”+CMS ERROR: 517″)==0) { //SIM NOT Ready return SIM300_SIM_NOT_READY; } //MSG Slot Empty if(strcasecmp(sim300_buffer+2,”OK”)==0) { return SIM300_MSG_EMPTY; } //Now read the actual msg text len=SIM300WaitForResponse(1000); if(len==0) return SIM300_TIMEOUT; sim300_buffer[len-1]=’\0′; strcpy(msg,sim300_buffer+1);//+1 for removing trailing LF of prev line return SIM300_OK; }

Анализ кода

1. Отменяем ожидание данных буфером.

2. Командная строка пишется с использование функции sprintf() из библиотеки.  

     1. sprintf(cmd,"AT+CMGR=%d",i);

     2. В этой строке значение %d заменяется на значение i.

3. Команда отправляется модулю SIM300.

4. Ожидание ответа.

5. Анализ ответа.

6. Наконец сообщение читается и копируется в память указанную *msg с использованием функций стандартной библиотеки strcpy().

Отправка текстового сообщения

Мы расскажем о функции, которая позволяет легко отправить сообщение на любой мобильный номер.  Эта функция принимает следующие аргументы:

Num (IN) – Номер телефона, на который надо отправить сообщение "+7903 XXXXXXX"

MSG (IN) – Текст сообщения "Текст сообщения"

msg_ref (OUT) – После успешной отправки, функция сохраняет уникальный указатель сообщения в этой переменной.

Функция возвращает целое значение, сообщающее о результате операции. Оно может быть следующим:

SIM300_TIMEOUT – Такой ответ приходит при проблемах с линией связи или когда GSM модуль не отвечает или выключен.

SIM300_FAIL – Не удалось отправить сообщение. Возможно, недостаточно денег на счету.

SIM300_OK – Сообщение отправлено успешно!

int8_t SIM300SendMsg(const char *num, const char *msg,uint8_t *msg_ref) { UFlushBuffer(); char cmd[25]; sprintf(cmd,”AT+CMGS= %s”,num); cmd[8]=0x22; //” uint8_t n=strlen(cmd); cmd[n]=0x22; //” cmd[n+1]=’\0′; //Send Command SIM300Cmd(cmd); _delay_ms(100); UWriteString(msg); UWriteData(0x1A); //Wait for echo while( UDataAvailable()<(strlen(msg)+5) ); //Remove Echo UReadBuffer(sim300_buffer,strlen(msg)+5); uint8_t len=SIM300WaitForResponse(6000); if(len==0) return SIM300_TIMEOUT; sim300_buffer[len-1]='\0'; if(strncasecmp(sim300_buffer+2,"CMGS:",5)==0) { *msg_ref=atoi(sim300_buffer+8); UFlushBuffer(); return SIM300_OK; } else { UFlushBuffer(); return SIM300_FAIL; } }

Анализ кода

1. Начало функции похоже на предыдущие – сначала мы очищаем буфер и строим командную строку. Она должна быть такой:

    – AT+CMGS=<DA>, где DA адрес назначения, т.е. номер мобильного телефона на который необходимо отправит сообщение, например AT+CMGS="+919939XXXXXX"

    – Функция sprintf(cmd,"AT+CMGS= %s",num); дает такую строку: AT+CMGS= +919939XXXXXX

    – cmd[8]=0x22; //" эта команда заменяет пробел перед +91 на " и мы получаем строку AT+CMGS="+919939XXXXXX

    – cmd[n]=0x22; //" эта команда добавляет " в конец и мы получаем такую строку  AT+CMGS="+919939XXXXXX" , но она удаляет ‘\0’ – нулевой символ, который отмечает конец строки в С. Следующая команда возвращает его. 

    – cmd[n+1]=’\0′;   

2. Затем мы посылаем командную строку подготовленную выше.  

3. Теперь напишем само сообщение для модуля SIM300 с помощью функции UWriteString(msg);

4. UWriteData(0x1A); Эта функция используется для передачи управляющего символа EOF (End of File, конец файла), чтобы отметить конец сообщения.

5. SIM300 возвращает обратно все, что принял, поэтому мы очищаем буфер

6. Наконец мы дожидаемся ответа, читаем ответ и сравниваем его, чтобы выяснить удалась-ли отправка сообщения или нет.

Удаление текстовых сообщений

Эта функция принимает в качестве входного параметра целое значение, указывающие на номер ячейки, в которой хранится сообщение.  Функция может давать следующие ответы:

SIM300_TIMEOUT – Такой ответ приходит при проблемах с линией связи или когда GSM модуль не отвечает или выключен.

SIM300_FAIL – Не удалось удалить сообщение. Возможно, неверно указана ячейка.

SIM300_OK – Сообщение удалено успешно!

AT команда для удаления сообщения AT+CMGD=<n> где n номер ячейки сообщения, которое требуется удалить.  Если удаление прошло успешно, то возвращается ответ OK. Реализация функции очень проста по сравнению с предыдущей функцией. Команда похожа на все остальные: Сначала идет построение командной строки, потом отправка команды, ожидание и проверка ответа.

int8_t SIM300DeleteMsg(uint8_t i) { UFlushBuffer(); //String for storing the command to be sent char cmd[16]; //Build command string sprintf(cmd,”AT+CMGD=%d”,i); //Send Command SIM300Cmd(cmd); uint8_t len=SIM300WaitForResponse(1000); if(len==0) return SIM300_TIMEOUT; sim300_buffer[len-1]=’\0′; //Check if the response is OK if(strcasecmp(sim300_buffer+2,”OK”)==0) return SIM300_OK; else return SIM300_FAIL; }

Демонстрационная программа для получения и отправки сообщения SIM300

Чтобы показать работу всех вышеперечисленных функции, мы разработали небольшую программу. Эта программа совершает следующие действия после загрузки:

– инициализирует ЖК-дисплей и модуль SIM300.

– отображает IMEI, название производителя и модели.

– проверяет наличие SIM-карты и подключения к сети.

– когда соединение установлено, отображается название оператора, например  MTS или Megafon.

– после этого отправляется сообщение с текстом "Test" на телефон.

– затем ожидается ответ. Когда он приходит, отображается.

– потом сообщение удаляется.

Скачать проект AVR Studio 5

Оригинал статьи на английском языке (перевод: Александр Касьянов для сайта cxem.net)


Категория: Микроконтроллеры
Метки:

Написать коментарий

*
= 3 + 0

Добавить изображение

Последние статьи