GSM модули находят применение в проектах электроники, в которых требуется удаленный доступ к чему-либо. С помощью данных модулей можно выполнять те же самые функции, что и с помощью обычных сотовых телефонов: осуществление и прием вызовов, передачу/прием SMS, соединению с сетью интернет с помощью технологии GPRS и т.д. Подключив микрофон и динамик к подобному модулю вы можете превратить его в сотовый телефон. В данной статье мы рассмотрим подключение GSM модуля SIM900A к микроконтроллеру PIC и продемонстрируем передачу и прием вызовов с его помощью.
Также на нашем сайте вы можете посмотреть проекты подключения GSM модуля к другим микроконтроллерам (платам):
Необходимые компоненты
- Микроконтроллер PIC16F877A (купить на AliExpress).
- GSM модуль SIM900 (или любой другой) (купить на AliExpress).
- Держатель микросхем на 40 контактов (купить на AliExpress).
- Программатор PICkit 3 (купить на AliExpress).
- Кварцевый генератор 20 МГц (купить на AliExpress).
- Конденсаторы 22 пФ (2 шт.), 0,1 мкФ и 10 мкФ (купить на AliExpress).
- Регулятор напряжения 7805 (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Светодиод.
- Адаптер на 12V.
- Перфорированная плата.
- Соединительные провода.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
GSM модуль SIM900A
GSM модуль можно использовать без микроконтроллера, управляя его работой с помощью AT команд. Внешний вид GSM модуля SIM900A показан на следующем рисунке.
Как видно из представленного рисунка, GSM модуль содержит в своем составе адаптер USART (последовательный порт связи), поэтому его можно напрямую подключить к компьютеру используя модуль MAX232, либо же его контакты Tx и Rx можно подключить к микроконтроллеру. Также у GSM модуля есть контакты MIC+, MIC-, SP+, SP-, к которым можно подключить микрофон и громкоговоритель (динамик) соответственно. Модуль можно запитать от адаптера 12V через стандартный разъем постоянного тока (DC barrel jack).
Когда вы вставите SIM карту в GSM модуль вы должны заметить что на нем загорится светодиод, индицирующий подачу питания. После этого подождите минуту или чуть дольше – светодиод красного (или другого) цвета должен начать мигать с интервалом 3 секунды. Это будет означать что модуль установил соединение с вашей SIM картой. После этого вы можете подключить его к компьютеру или микроконтроллеру.
Взаимодействие с GSM модулем с помощью AT команд
GSM модуль понимает только один "язык" управления им – это AT команды. К примеру, если вы хотите узнать активен модуль или нет, вы можете послать ему команду “AT”, GSM модуль должен ответить на нее “OK”.
Полный список AT команд достаточно обширен и англоязычный даташит на них включает 271 страницу. Поэтому в следующей таблице мы привели список наиболее часто используемых AT команд.
AT | Отвечает OK на запрос |
AT+CPIN? | Проверка качества сигнала |
AT+COPS? | Поиск имени провайдера |
ATD96XXXXXXXX; | Вызов указанного номера |
AT+CNUM | Определение номера SIM карты (для некоторых SIM карт может не работать) |
ATA | Ответ на входящий вызов |
ATH | Отклонение входящего звонка (повесить трубку) |
AT+COLP | Отобразить номер входящего звонка |
AT+VTS=(number) | Передать DTMF номер (number) |
AT+CMGR | AT+CMGR=1 считывает сообщение на первой позиции |
AT+CMGD=1 | Удаление сообщения на первой позиции |
AT+CMGDA=”DEL ALL” | Удаление всех сообщений с SIM карты |
AT+CMGL=”ALL” | Чтение всех сообщений с SIM карты |
AT+CMGF=1 | Установка конфигурации SMS. “1” – только текстовый режим |
AT+CMGS = “+91 968837XXXX”
>CircuitDigest Text<Ctrl+z> |
Передача SMS на определенный номер, например, на 968837XXXX. Когда увидите “>” начинайте набирать текст. Для передачи текста нажмите Ctrl+Z |
AT+CGATT? | Проверка интернет соединения на SIM карте |
AT+CIPSHUT | Завершение TCP соединения, что означает отключение от интернета |
AT+CSTT = “APN”,”username”,”Pass” | Соединение с GPRS с помощью ваших APN и Pass key. Их можно получить у провайдера сети |
AT+CIICR | Проверка имеет ли ваша SIM карта пакет данных |
AT+CIFSR | Получить IP SIM сети |
AT+CIPSTART = “TCP”,”SERVER IP”,”PORT” | Установка TCP IP соединения |
AT+CIPSEND | Передача данных на сервер. |
Далее перейдем к схеме нашего проекта.
Схема проекта
Схема подключения GSM модуля к микроконтроллеру PIC представлена на следующем рисунке.
Как видите, мы соединили контакты Tx и Rx GSM модуля с контактами Rx и Tx микроконтроллера PIC, что позволит установить между ними последовательную связь. Также не забудьте соединить общие провода (ground) GSM модуля и микроконтроллера.
Внешний вид собранной конструкции проекта показан на следующем рисунке.
Перфорированную плату с установленным на нее микроконтроллером PIC мы использовали из проекта мигания светодиодом.
Объяснение программы для микроконтроллера PIC
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты. Код программы взаимодействие с ЖК дисплеем, если вы ранее с ним никогда не работали, то советуем прочитать статью про подключение ЖК дисплея к микроконтроллеру PIC.
Как мы отмечали ранее, управлять работой GSM модуля мы будем с помощью AT команд. Поэтому сначала нам необходимо инициализировать модуль USART в микроконтроллере PIC с помощью функции Initialize_SIM900(). Внутри этой функции мы объявим контакты Tx и RX и инициализируем асинхронную последовательную связь со скоростью 9600 бод в 8-битном режиме.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
//***Initialize UART for SIM900**// void Initialize_SIM900(void) { //****Setting I/O pins for UART****// TRISC6 = 0; // TX Pin set as output TRISC7 = 1; // RX Pin set as input //________I/O pins set __________// /**Initialize SPBRG register for required baud rate and set BRGH for fast baud_rate**/ SPBRG = 129; //SIM900 operates at 9600 Baud rate so 129 BRGH = 1; // for high baud_rate //_________End of baud_rate setting_________// //****Enable Asynchronous serial port*******// SYNC = 0; // Asynchronous SPEN = 1; // Enable serial port pins //_____Asynchronous serial port enabled_______// //**Lets prepare for transmission & reception**// TXEN = 1; // enable transmission CREN = 1; // enable reception //__UART module up and ready for transmission and reception__// //**Select 8-bit mode**// TX9 = 0; // 8-bit reception selected RX9 = 0; // 8-bit reception mode selected //__8-bit mode selected__// } //________UART module Initialized__________// |
После этого нам необходимо передавать и принимать информацию от GSM модуля. Для этого мы запрограммируем функции _SIM900_putch(), _SIM900_getch(), _SIM900_send_string(), _SIM900_print(). Эти функции будут использовать буферные регистры TXREG и RCREG для считывания и записи данных.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
//**Function to send one byte of date to UART**// void _SIM900_putch(char bt) { while(!TXIF); // hold the program till TX buffer is free TXREG = bt; //Load the transmitter buffer with the received value } //_____________End of function________________// //**Function to get one byte of date from UART**// char _SIM900_getch() { if(OERR) // check for Error { CREN = 0; //If error -> Reset CREN = 1; //If error -> Reset } while(!RCIF); // hold the program till RX buffer is free return RCREG; //receive the value and send it to main function } //_____________End of function________________// //**Function to convert string to byte**// void SIM900_send_string(char* st_pt) { while(*st_pt) //if there is a char _SIM900_putch(*st_pt++); //process it as a byte data } //___________End of function______________// //**End of modified Codes**// void _SIM900_print(unsigned const char *ptr) { while (*ptr != 0) { _SIM900_putch(*ptr++); } |
Представленные функции являются универсальными и могут быть использованы и в других похожих проектах.
Затем внутри нашей функции main мы инициализируем соединение с USART и ждем пока GSM модуль не ответит нам “OK”, что будет означать что он готов к работе.
1 2 3 4 5 6 7 8 |
do { Lcd_Set_Cursor(2,1); Lcd_Print_String("Module not found"); }while (!SIM900_isStarted()); //wait till the GSM to send back "OK" Lcd_Set_Cursor(2,1); Lcd_Print_String("Module Detected "); __delay_ms(1500); |
Функция SIM900_isStarted() будет передавать команду “AT” на GSM модуль и будет ждать от него ответа “OK” . Если она такой ответ получит, то она возвращает 1, иначе она возвращает 0.
Если GSM модуль не обнаружен или есть какие либо проблемы с его подключением, то на ЖК дисплее высветится сообщение “Module not found”. Если все нормально, то высветится сообщение о том, что модуль обнаружен. После этого мы будем проверять присутствует ли в модуле SIM карта.
1 2 3 4 5 6 7 8 9 |
/*Check if the SIM card is detected*/ do { Lcd_Set_Cursor(2,1); Lcd_Print_String("SIM not found "); }while (!SIM900_isReady()); //wait till the GSM to send back "+CPIN: READY" Lcd_Set_Cursor(2,1); Lcd_Print_String("SIM Detected "); __delay_ms(1500); |
Функция SIM900_isReady() будет передавать на GSM модуль команду “AT+CPIN?” и ждать от него ответа “+CPIN: READY”. При получении этого ответа она возвратит 1, иначе она возвратит 0.
При обнаружении SIM карты мы высветим соответствующее сообщение на ЖК дисплее. Затем мы будем пытаться совершить звонок используя команду “ATDmobilenumber;”. Для примера мы использовали номер ATD93643159XX. Вы можете заменить его на свой, необходимый вам номер.
1 2 3 4 5 6 7 8 9 10 |
/*Place a Phone Call*/ do { _SIM900_print("ATD93643XXXXX;\r\n"); //Here we are placing a call to number 93643XXXXX Lcd_Set_Cursor(1,1); Lcd_Print_String("Placing Call...."); }while (_SIM900_waitResponse() != SIM900_OK); //wait till the ESP send back "OK" Lcd_Set_Cursor(1,1); Lcd_Print_String("Call Placed...."); __delay_ms(1500); |
При совершении вызова на экран ЖК дисплея будет выведено сообщение "Call Placed...." и вы сможете принимать входящие звонки с этого номера.
Также вы можете совершить входящий звонок на номер SIM карты, вставленной в GSM модуль. Соответствующее сообщение об этом также будет выведено на экран ЖК дисплея.
1 2 3 4 5 6 7 8 |
while(1) { if (_SIM900_waitResponse() == SIM900_RING) //Check if there is an incoming call { Lcd_Set_Cursor(2,1); Lcd_Print_String("Incoming Call!!."); } } |
Когда GSM модуль будет обнаруживать входящий звонок он будет отображать его на второй строке ЖК дисплея. Функция _SIM900_waitResponse() будет проверять принимаемые GSM модулем данные. Когда она будет принимать SIM900_RING, что в нашем случае будет эквивалентно “RING” из-за waitResponce(), мы будем отображать на ЖК дисплее “Incoming call”.
Также вы можете создать свой собственный набор функций для работы с GSM модулем. Также вы можете использовать функцию __SIM900_print() для передачи любой AT команды на модуль, например:
1 |
_SIM900_print("AT+CPIN?\r\n"); |
Но в этом случае помните о том, что все ваши команды должны оканчиваться комбинацией символов “\r\n”, которые будут свидетельствовать о том, что команда завершена.
Моделирование работы проекта
Прежде чем приступать к сборке проекта в "реальном железе" вы можете смоделировать его работу в симуляторе Proteus. Схема проекта в данном симуляторе приведена на следующем рисунке.
Как вы можете видеть, мы в Proteus использовали опцию виртуального терминала чтобы проверить что программа отвечает необходимым образом. Мы можем передать эти данные через всплывающее диалоговое окно (pop-up dialog box). При запуске проекта на выполнение будет появляться черное диалоговое окно, в котором вы можете вводить AT команды для их передачи на GSM модуль. Также мы можем вводить ответы модуля для микроконтроллера PIC, например, “OK”.
Тестирование работы проекта
После загрузки кода программы в микроконтроллер PIC, если все нормально, то на экране ЖК дисплея вы должны увидеть последовательно сменяемые друг друга сообщения “Module Detected”, “SIM detected” и “call Placed”. Когда вы увидите сообщение “Call placed” это значит, что вы совершаете вызов на номер, записанный в программе.
Также вы можете совершить вызов на номер SIM карты модуля, в этом случае на ЖК дисплее появится сообщение “Incoming call”.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
// CONFIG #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT enabled) #pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) //End of CONFIG registers #define _XTAL_FREQ 20000000 #define RS RD2 #define EN RD3 #define D4 RD4 #define D5 RD5 #define D6 RD6 #define D7 RD7 #define SIM900_OK 1 #define SIM900_READY 2 #define SIM900_FAIL 3 #define SIM900_RING 4 #define SIM900_NC 5 #define SIM900_UNLINK 6 #include<xc.h> // Wait for any response on the input inline unsigned char _SIM900_waitResponse(void); int recv; char p =1; //LCD Functions Developed by Circuit Digest. void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines { if(data_bit& 1) D4 = 1; else D4 = 0; if(data_bit& 2) D5 = 1; else D5 = 0; if(data_bit& 4) D6 = 1; else D6 = 0; if(data_bit& 8) D7 = 1; else D7 = 0; } void Lcd_Cmd(char a) { RS = 0; Lcd_SetBit(a); //Incoming Hex value EN = 1; __delay_ms(4); EN = 0; } void Lcd_Clear() { Lcd_Cmd(0); //очищаем экран ЖК дисплея Lcd_Cmd(1); //перемещаем курсор на 1-ю позицию } void Lcd_Set_Cursor(char a, char b) { char temp,z,y; if(a== 1) { temp = 0x80 + b - 1; //80H is used to move the curser z = temp>>4; //младшие 8 бит y = temp & 0x0F; //старшие 8 бит Lcd_Cmd(z); //устанавливаем строку Lcd_Cmd(y); //устанавливаем столбец } else if(a== 2) { temp = 0xC0 + b - 1; z = temp>>4; // младшие 8 бит y = temp & 0x0F; // старшие 8 бит Lcd_Cmd(z); // устанавливаем строку Lcd_Cmd(y); // устанавливаем столбец } } void Lcd_Start() { Lcd_SetBit(0x00); for(int i=1065244; i<=0; i--) NOP(); Lcd_Cmd(0x03); __delay_ms(5); Lcd_Cmd(0x03); __delay_ms(11); Lcd_Cmd(0x03); Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD Lcd_Cmd(0x08); //Select Row 1 Lcd_Cmd(0x00); //Clear Row 1 Display Lcd_Cmd(0x0C); //Select Row 2 Lcd_Cmd(0x00); //Clear Row 2 Display Lcd_Cmd(0x06); } void Lcd_Print_Char(char data) //Send 8-bits through 4-bit mode { char Lower_Nibble,Upper_Nibble; Lower_Nibble = data&0x0F; Upper_Nibble = data&0xF0; RS = 1; // => RS = 1 Lcd_SetBit(Upper_Nibble>>4); //Send upper half by shifting by 4 EN = 1; for(int i=2130483; i<=0; i--) NOP(); EN = 0; Lcd_SetBit(Lower_Nibble); //Send Lower half EN = 1; for(int i=2130483; i<=0; i--) NOP(); EN = 0; } void Lcd_Print_String(char *a) { int i; for(i=0;a[i]!='\0';i++) Lcd_Print_Char(a[i]); //разделяем строку на отдельные символы с помощью указателей и по очереди передаем каждый символ } /*****End of LCD Functions*****/ //***инициализация UART для SIM900**// void Initialize_SIM900(void) { //****Setting I/O pins for UART****// TRISC6 = 0; // TX Pin set as output TRISC7 = 1; // RX Pin set as input //________I/O pins set __________// /**Initialize SPBRG register for required baud rate and set BRGH for fast baud_rate**/ SPBRG = 129; //SIM900 operates at 9600 Baud rate so 129 BRGH = 1; // for high baud_rate //_________End of baud_rate setting_________// //****Enable Asynchronous serial port*******// SYNC = 0; // асинхронный режим SPEN = 1; // Enable serial port pins //_____Asynchronous serial port enabled_______// //**Lets prepare for transmission & reception**// TXEN = 1; // разрешаем передачу CREN = 1; // разрешаем прием //__UART module up and ready for transmission and reception__// //**выбираем 8-битный режим**// TX9 = 0; // выбор 8-битного режима передачи RX9 = 0; // выбор 8-битного режима приема //__8-bit mode selected__// } //________UART module Initialized__________// //**функция для передачи одного байта данных через UART**// void _SIM900_putch(char bt) { while(!TXIF); // задерживаем выполнение программы до тех пор буфер передачи (TX buffer) не освободится TXREG = bt; // загружаем в буфер передачи значение, которое необходимо передать } //_____________End of function________________// //**функция для приема одного байта из UART**// char _SIM900_getch() { if(OERR) // проверяем на наличие ошибок { CREN = 0; //If error -> Reset CREN = 1; //If error -> Reset } while(!RCIF); // задерживаем выполнение программы до тех пор пока буфер приема (RX buffer) не освободится return RCREG; //принимаем значение и передаем (возвращаем) его в функцию main } //_____________End of function________________// //**функция для преобразования строки в байт**// void SIM900_send_string(char* st_pt) { while(*st_pt) //if there is a char _SIM900_putch(*st_pt++); //process it as a byte data } //___________End of function______________// //**End of modified Codes**// void _SIM900_print(unsigned const char *ptr) { while (*ptr != 0) { _SIM900_putch(*ptr++); } } bit SIM900_isStarted(void) { _SIM900_print("AT\r\n"); return (_SIM900_waitResponse() == SIM900_OK); } bit SIM900_isReady(void) { _SIM900_print("AT+CPIN?\r\n"); return (_SIM900_waitResponse() == SIM900_READY); } inline unsigned char _SIM900_waitResponse(void) { unsigned char so_far[6] = {0,0,0,0,0,0}; unsigned const char lengths[6] = {2,12,5,4,6,6}; unsigned const char* strings[6] = {"OK", "+CPIN: READY", "ERROR", "RING", "NO CARRIER", "Unlink"}; unsigned const char responses[6] = {SIM900_OK, SIM900_READY, SIM900_FAIL, SIM900_RING, SIM900_NC, SIM900_UNLINK}; unsigned char received; unsigned char response; char continue_loop = 1; while (continue_loop) { received = _SIM900_getch(); for (unsigned char i = 0; i < 6; i++) { if (strings[i][so_far[i]] == received) { so_far[i]++; if (so_far[i] == lengths[i]) { response = responses[i]; continue_loop = 0; } } else { so_far[i] = 0; } } } return response; } void main(void) { //I/O Declarations// TRISD = 0x00; //LCD pins on port D as output //End of I/O declaration// Lcd_Start(); //инициализируем ЖК дисплей Initialize_SIM900();//lets get our Serial ready for action (инициализируем GSM модуль) Lcd_Set_Cursor(1,1); Lcd_Print_String("SIM900 & PIC"); /*Check if the SIM900 communication is successful*/ do { Lcd_Set_Cursor(2,1); Lcd_Print_String("Module not found"); }while (!SIM900_isStarted()); //ждем пока GSM модуль не ответит нам "OK" Lcd_Set_Cursor(2,1); Lcd_Print_String("Module Detected "); __delay_ms(1500); /*Check if the SIM card is detected*/ do { Lcd_Set_Cursor(2,1); Lcd_Print_String("SIM not found "); }while (!SIM900_isReady()); // ждем пока GSM модуль не ответит нам "+CPIN: READY" Lcd_Set_Cursor(2,1); Lcd_Print_String("SIM Detected "); __delay_ms(1500); Lcd_Clear(); /*Place a Phone Call*/ do { _SIM900_print("ATD93643XXXXX;\r\n"); //Here we are placing a call to number 93643XXXXX Lcd_Set_Cursor(1,1); Lcd_Print_String("Placing Call...."); }while (_SIM900_waitResponse() != SIM900_OK); //wait till the ESP send back "OK" Lcd_Set_Cursor(1,1); Lcd_Print_String("Call Placed...."); __delay_ms(1500); while(1) { if (_SIM900_waitResponse() == SIM900_RING) //Check if there is an incoming call { Lcd_Set_Cursor(2,1); Lcd_Print_String("Incoming Call!!."); } } } |