SIM900D+ATmega
Дата: 6 Июля 2014. Автор: Алексей
Отладочная плата на базе SIM900D
По просьбе трудящихся продолжаю тему GSM девайсов, а именно подключение модуля SIM900D к ATmega. Какая модель это не важно. В этой статье я буду использовать ATmega8515. Этот контроллер я использовал исключительно по фен-шую))) Вся нужная информация будет выводится на ЖК дисплей 20х4 фирмы МЭЛТ. Его тоже выбирал по фен-шую))) И также потому что он понимает кодировку Windows-1251 что сильно упрощает вывод русских буковок.
А теперь собственно поставим задачу.
- 1. Требуется включать и выключать 8 светодиодов(реле, вентиляторов и т.д.)
- 2. Включат и выключать по переданному коду по средством SMS.
- 3. Выводить на дисплей уровень приема GSM сигнала.
- 4. Вывод на экран последнюю команду переданную по средством SMS.
Задача поставлена. GSM-модуль общается с МК по UART. Схема включения GSM-модуля можно посмотреть здесь. МК будет работать на частоте 3,6864 МГц. Это нужно для снижения ошибок в UART. Скорость обмена 19200. За все время тестирования ошибок с передачей не было. Правда помер один МК, что дало головомойки на пару дней, но потом с заменой на новый МК все пошло как по маслу. ЖК дисплей подключен к порту А. Порт С отдан на включение и выключение светодиодов. Ах да. тут есть один нюанс. GSM-модуль может получать данные на ногу RxD только 3 вольта и не более!!! Это важно!!! Отсюда было принято решение подавать данные через резисторный делитель. Расчет плечей оставляю за вами так как МК может работать в разных диапазонах от 2,8 до 5 вольт. Лично я питаю GSM-модуль 4 вольтами, а МК 5. Так, с железом вроде разобрались. Теперь поехали по коду. Первое что необходимо это способ принятия данных от GSM-модуля. Модуль пуляет ответы на запросы такого вида:
Запрос:
AT+CSQ\r\r\n
Ответ:
\r\n+CSQ: 17,0\r\n\r\nOK\r\n
Отсюда видно что запросы и ответы перемешаны кучей \r и \n ерундой. Ну для запроса это не проблема, так как мы сами его пишем, а вот ответ... Разгребать весь этот зоопарк каждым пришедшим байтом в UDR не комельфо, поэтому будем использовать кольцевой буфер. Кто не знает что это, идем сюда. При использовании кольцевого буфера добавим в обработчик прерывания по приходу данных в UDR проверку для игнорирования \r и \n.
ISR(USART_RX_vect) { char temp = UDR; if(!(temp == 0x0A || temp == 0x0D)) InBuffer(temp); }То есть мы записываем в буфер все кроме \r и \n. Как только мы получили данные начинаем их обрабатывать. Первое что нужно посмотреть, SMS это или ответ на команду. Так как GSM-модуль всегда возвращает фиксированный ответ, а меняет только данные, то отследить можно по названию ответа. Например запрос на уровень приема GSM.
if(time == 30) { time = 0; USART_STR("AT+CSQ"); USART_END(); _delay_ms(200); } if(GetData()) { _delay_ms(70); num = IndexNumber(); OutBufferStr(temp,num); }Теперь в массиве temp лежит ответ от GSM-модуля. Теперь давайте его распознаем.
if((temp[1] == 'C') & (temp[2] == 'S') & (temp[3] == 'Q')) { }Если в массиве лежит ответ на запрос уровня GSM, то условие выполнится и его можно обрабатывать по своему усмотрению. А если условие не выполнилось? То скорее всего пришло SMS. Как его вычислить? Как только приходит SMS сообщение, модуль возвращает строку вида.
+CMTI: "SM",1Все что здесь меняется, так это последний символ, а точнее цифра. Это номер SMS. А вот буквы SM не меняются никогда. Значит нам требуется проверить есть ли в сообщении эти буквы.
if((temp[8] == 'S') & (temp[9] == 'M')) { }Конечно еще бы было не плохо проверить название самой команды для более точного убеждения, но я этим пренебрег так как это пока просто объяснения работы МК с GSM-модулем. Поле того как распознали принятие SMS не плохо бы было его прочитать. Кидаем GSM-модулю запрос вида.
USART_STR("AT+CMGR="); USART_TXD(temp[12]); USART_STR(",0"); USART_END(); _delay_ms(200);В ячейке массива temp[12] лежит номер SMS. Данная команда будет адекватна при SMS сообщениях меньше 9. Ну это понятно почему. А вообще чтобы не забивать память SIM карты SMSками я после прочтения SMS сразу удаляю ее, поэтому больше 1 SMS в памяти не бывает. Но все же я использовал не жестко число 1, а именно выдрал его из массива. Я не знаю почему, но иногда SMS не всегда приходят сразу, а с неким опозданием. Если такое произошло, то возможен такой косяк, SMSка еще не пришла, мы думаем что не прошла и шлем за ней еще одну. Тут проходит время и они приходят две подряд одна за одной. Первую мы читаем как 1, а вторая пришла как 2. Вот от таких косяков и защищает ячейка массива. Теперь запросив текст SMS GSM-модуль вернет нам ответ вида.
+CMGR: "REC UNREAD","+71234567890","","14/07/06,13:04:38+16" сообщение OKПосле этого можно читать сообщение. Так как ответы всегда фиксированы, то можно смело начинать читать с temp[60]... и может возникнуть косяк))) Я на него нарвался. Пока я разбирался с GSM-модулем мне тихим сапом Beeline прислал SMSку. Все бы ничего да подстава засела в месте где прописывается номер отправляющего SMS абонента. Вместо "+71234567890" мне пришло "My Beeline". Ну понятно чем это пахнет. Короче МК ни фига не понял и вошел в ступор. Поэтому я решил все таки проверять номер. Да и для безопасности это не помешает. А то вдруг зависливый сосед прознает про управление котлом по SMS и пошлет команду зимой выключит котел))).
for(uint8_t i=0; i<12; i++) { if(temp[i+21] == phone[i]) { flag=1; } else { flag=0; break; } }Смысл прост. В цикле сравниваем ячейки массива буфера отвечающие за номер с массивом в который заранее положили требуемый номер. Пока цифры совпадают флаг равен 1, но как только цифра не совпадет, обнуляем флаг и выходим из цикла. Если флаг в нуле, то не читаем SMSку, а если в единице, то SMSка наша. Если все проверки прошли, то читаем команду. Команды я сделал такие. Заглавния буква V значит включить, O значит отключить. Для того чтобы узнать какой светодиод включить или выключить, после буквы пишем его номер от 1 до 8. Пример, нужно включить 4-й светодиод. Шлем SMS с текстом V4, а для отключения O4.
< if(flag) { if(temp[60] == 'V') { lcd_xy(0,2); lcd_putsf("LED-"); lcd_putchar(temp[61]); lcd_putsf(" Bключен "); switch (temp[61]) { case 0x31: PORTC |= (1<<7); break; case 0x32: PORTC |= (1<<6); break; case 0x33: PORTC |= (1<<5); break; case 0x34: PORTC |= (1<<4); break; case 0x35: PORTC |= (1<<3); break; case 0x36: PORTC |= (1<<2); break; case 0x37: PORTC |= (1<<1); break; case 0x38: PORTC |= (1<<0); break; } } if(temp[60] == 'O') { lcd_xy(0,2); lcd_putsf("LED-"); lcd_putchar(temp[61]); lcd_putsf(" Отключен "); switch (temp[61]) { case 0x31: PORTC &= ~(1<<7); break; case 0x32: PORTC &= ~(1<<6); break; case 0x33: PORTC &= ~(1<<5); break; case 0x34: PORTC &= ~(1<<4); break; case 0x35: PORTC &= ~(1<<3); break; case 0x36: PORTC &= ~(1<<2); break; case 0x37: PORTC &= ~(1<<1); break; case 0x38: PORTC &= ~(1<<0); break; } } }Собственно вот весь код. Сначала проверяем буковку и по ней выполняем ту или иную команду и параллельно выводим сообщение на ЖК. А после того как закончили работу с SMS скидываем флаг и удаляем все SMS.
USART_STR("AT+CMGD=1,4"); USART_END(); _delay_ms(100); flag=0;Отладочная плата на базе SIM900D
Вот и все. Ниже видео всего этого безобразия и архив с проектом.
Проект GSM+ATmega8535
Загрузка плеера...
Vl 04.03.15 12:01
Подскажите пожалуйста Fuse биты для
данного проекта для PonyProg.
Заранее спасибо!
Алексей 04.03.15 21:11
Вот где не помогу, так это тут. Я даже
не знаю как выглядит PonyProg. Скачайте
лучше дудку.
usbasp-avrdude-prog
Михаил 07.06.15 16:13
Алексей 07.06.15 18:29
AtmelStudio 6.2
Михаил 08.06.15 22:18
Подскажите, а разве в начале не нужно
отправлять команду, которая настраивает
GSM режим? ведь иначе нельзя будет
прочитать текст сообщения.
Алексей 09.06.15 08:41
Телефон службы СМС сообщений нужно было
вводить в далеких 90-х. Сейчас при
покупке сим карты в ней уже все забито.
Единственная команда нужна, так это
отключение эхо, дабы не читать
собственные команды.
okumurapanda@gmail.com. 13.08.16 19:01
Как всё это оформить на ATmega32a
Алексей 13.08.16 19:47
Собрать проект под 32 мегу. UART платформо независим.
V 04.05.17 23:32
Всё- таки не понятно, как мы принимаем решение, что пора лопатить буфер. Мы же не знаем по идее какой длинны от модема будет ответ и вообще какой. Признаков что модем передал всё что хотел передать - нету...
Алексей 05.05.17 19:59
Все очень просто. В кольцевом буфере есть функция GetData(). Данная функция возвращает количество байт записанные в буфер в данный момент. Если данные не пришли, то возвращает 0. Таким образом в теле программы постоянно вызываем данную функция и проверяем на наличие данных в буфере. Как только что-то появилась, то делаем задержку на 70мс, а потом получаем данные из буфера. За 70мс модуль передает весь пакет.
Владимир 01.03.18 00:07
Как отправить СМС по номеру из записной книжки.