GPS модули широко используются в современной электронике для определения местоположения, основываясь на координатах долготы и широты. Системы мониторинга транспортных средств, часы GPS, системы предупреждения о чрезвычайных происшествиях, системы наблюдения – это лишь небольшой список приложений, в которых может потребоваться технология GPS. Система GPS обеспечивает информацию о высоте, долготе, широте, реальном времени и ряд другой информации о местоположении, которая берется с нескольких спутников. В данной статье мы рассмотрим подключение GPS модуля к микроконтроллеру AVR, с помощью которого мы будем считывать информацию из данного модуля (широту и долготу) и отображать ее на жидкокристаллическом (ЖК) дисплее 16x2.
Необходимые компоненты
- Микроконтроллер ATmega16/32 (купить на AliExpress).
- Программатор AVR-ISP (купить на AliExpress), USBASP (купить на AliExpress) или другой подобный.
- GPS модуль (uBlox Neo 6M GPS (или 7M).
- ЖК дисплей 16x2 (купить на AliExpress).
- Антенна типа "длинный провод".
- Резисторы 2,2 кОм, 1 кОм (купить на AliExpress).
- Конденсатор 1000 мкФ (купить на AliExpress).
- Конденсатор 10 мкФ (купить на AliExpress).
- Преобразователь напряжения LM7805 (купить на AliExpress).
- DC Jack.
- Адаптер 12 В.
- Макетная плата.
- Соединительные провода.
- Burgstips (соединительные колодки).
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Получение данных местоположения от GPS модуля
Ublox Neo 6M представляет собой последовательный GPS модуль, который передает детали местоположения через последовательный порт. Он имеет 4 контакта, назначение которых представлено в следующей таблице.
Контакт | Описание |
Vcc | 2.7 – 5V питающее напряжение |
Gnd | земля |
TXD | передача данных |
RXD | прием данных |
Его внешний вид представлен на следующем рисунке.
GPS модуль Ublox neo 6M является TTL совместимым и его спецификация представлена в следующей таблице.
Время захвата | холодный старт - 27 сек., горячий старт - 1 сек. |
Протокол связи | NMEA |
Последовательная связь | 9600 бод/с , 8 бит данных , 1 стоповый бит , нет контроля четности и управления потоком |
Потребляемый ток | 45 мА |
GPS модуль будет передавать данные в виде последовательности строк на скорости 9600 бод/с. Если мы будем использовать последовательный терминал (UART) на скорости 9600 бод/с мы сможем принимать данные от GPS модуля.
GPS модуль передает данные местоположения в реальном времени в NMEA формате. NMEA формат состоит из нескольких предложений (частей), четыре из которых представлены ниже. Более подробно данный формат можно изучить в соответствующей литературе – информации о нем в сети достаточно много.
• $GPGGA: фиксированные данные глобального позиционирования;
• $GPGSV: спутники GPS в зоне видимости;
• $GPGSA: GPS DOP и активные спутники;
• $GPRMC: минимум специфических данных GPS/транзитных данных.
Пример данных, передаваемых GPS модулем на скорости 9600 бод/с, выглядит следующим образом:
$GPRMC,141848.00,A,2237.63306,N,08820.86316,E,0.553,,100418,,,A*73
$GPVTG,,T,,M,0.553,N,1.024,K,A*27
$GPGGA,141848.00,2237.63306,N,08820.86316,E,1,03,2.56,1.9,M,-54.2, M,,*74
$GPGSA,A,2,06,02,05,,,,,,,,,,2.75,2.56,1.00*02
$GPGSV,1,1,04,02,59,316,30,05,43,188,25,06,44,022,23,25,03,324,*76
$GPGLL,2237.63306,N,08820.86316,E,141848.00,A,A*65
Когда мы используем GPS модуль для определения местоположения нам из всего этого набора данных будут нужны только координаты, поэтому из представленных данных нам будет нужна только строка $GPGGA, в которой содержатся фиксированные данные системы глобального позиционирования (Global Positioning System Fix Data):
$GPGGA,141848.00,2237.63306,N,08820.86316,E,1,03,2.56,1.9,M,-54.2,M,,*74
Расшифровка данной строки (данных глобального позиционирования):
- Строка всегда начинается со знака “$”.
- Аббревиатура GPGGA означает фиксированные данные системы глобального позиционирования.
- “,” означает разделение между двумя значениями.
- 141848.00: всемирное время по Гринвичу 14(hr):18(min):48(sec):00(ms).
- 2237.63306,N: Широта (Latitude) 22(градуса) 37(минут) 63306(секунд) North (Север).
- 08820.86316,E: Долгота (Longitude) 088(градуса) 20(минут) 86316(секунд) East (Восток).
- 1 : Fix Quantity (Фиксированное количество) 0= неправильные данные, 1= достоверные данные, 2=DGPS fix.
- 03 : число спутников, которые мы в данный момент видим.
- 1.0: HDOP.
- 2.56,M : высота над уровнем моря (в метрах).
- 1.9,M : Geoids height (геоидная высота).
- *74 : контрольная сумма.
То есть, фактически, нам будут необходимы только п.5 и п.6 из представленных данных чтобы получить информацию о местоположении модуля.
Схема устройства
Схема устройства приведена на следующем рисунке.
Устройство запитывается от адаптера на 12В постоянного тока, но, поскольку схема работает от напряжения 5В, то в схеме присутствует регулятор напряжения LM7805. ЖК дисплей 16x2 сконфигурирован для работы в 4-битном режиме. GPS модуль также запитывается от напряжения 5В и его вывод передачи (tx pin) напрямую подсоединен к приемному выводу (Rx) микроконтроллера Atmega. Для задания тактовой частоты микроконтроллера используется кварцевый генератор на 8 МГц.
Последовательность действий по подключению GPS модуля к микроконтроллеру AVR
- Установить конфигурацию микроконтроллера, включая установку тактовой частоты.
- Установить необходимый для подключения ЖК дисплея порт.
- Подсоединить GPS модуль к микроконтроллеру используя USART (универсальный синхронно-асинхронный приемопередатчик).
- Инициализировать систему UART в режиме ISR (Interrupt Service Routine - процедура обработки прерывания), со скоростью 9600 бод/с и ЖК дисплеем в 4-битном режиме.
- Задать в программе 2 символьных массива, в которые будем сохранять широту и долготу.
- Принимать по одному символу в каждый момент времени и проверять является ли символ $ или нет.
- Если мы приняли $ (нашли его в составе принимаемой строки символов) нам необходимо проверить $GPGGA, то есть эти 6 букв, включая и символ $.
- Если это действительно GPGGA, то принимаем всю эту строку и устанавливаем необходимые флаги.
- Извлекаем из этой строки широту и долготу и записываем их в наши массивы.
- Выводим значения этих массивов на экран ЖК дисплея.
Объяснение кода программы
Полный код программы вместе с видео, демонстрирующем работу схемы, приведены в конце статьи. В этом разделе объяснены наиболее важные участки кода.
В начале подключим необходимые заголовки и запишем макросы для поразрядной маски для ЖК дисплея и конфигурирования последовательного порта (UART).
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 |
#define F_CPU 8000000ul #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> /***MACROS*/ #define USART_BAUDRATE 9600 #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) #define LCDPORTDIR DDRB #define LCDPORT PORTB #define rs 0 #define rw 1 #define en 2 #define RSLow (LCDPORT&=~(1<<rs)) #define RSHigh (LCDPORT|=(1<<rs)) #define RWLow (LCDPORT&=~(1<<rw)) #define ENLow (LCDPORT&=~(1<<en)) #define ENHigh (LCDPORT|=(1<<en)) enum { CMD=0, DATA, }; |
Теперь объявим и инициализируем некоторые переменные и массивы для хранения строк GPS, широты, долготы и флагов.
1 2 3 4 5 6 |
char buf[100]; volatile char ind,flag,stringReceived; char gpgga[]={'$','G','P','G','G','A'}; char latitude[12]; char logitude[12]; |
Запрограммируем ряд функций для работы с ЖК дисплеем.
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 |
void lcdwrite(char ch,char r) { LCDPORT=ch & 0xF0; RWLow; if(r == 1) RSHigh; else RSLow; ENHigh; _delay_ms(1); ENLow; _delay_ms(1); LCDPORT=ch<<4 & 0xF0; RWLow; if(r == 1) RSHigh; else RSLow; ENHigh; _delay_ms(1); ENLow; _delay_ms(1); } void lcdprint(char *str) { while(*str) { lcdwrite(*str++,DATA); //__delay_ms(20); } } void lcdbegin() { char lcdcmd[5]={0x02,0x28,0x0E,0x06,0x01}; for(int i=0;i<5;i++) lcdwrite(lcdcmd[i], CMD); } |
После этого инициализируем последовательную связь с GPS модулем и сравним принимаемую строку с "GPGGA".
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 |
void serialbegin() { UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); UBRRH = (BAUD_PRESCALE >> 8); UBRRL = BAUD_PRESCALE; UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE); } ISR(USART_RXC_vect) { char ch=UDR; buf[ind]=ch; ind++; if(ind<7) { if(buf[ind-1] != gpgga[ind-1]) // $GPGGA ind=0; } if(ind>=50) stringReceived=1; } void serialwrite(char ch) { while ((UCSRA & (1 << UDRE)) == 0); UDR = ch; } |
Теперь, если мы успешно нашли строку, содержащую GPGGA, то в основной функции (main) извлечем и отобразим на экране ЖК дисплея координаты широты и долготы нашего местоположения.
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 |
lcdwrite(0x80,0); lcdprint("Lat:"); serialprint("Latitude:"); for(int i=15;i<27;i++) { latitude[i]=buf[i]; lcdwrite(latitude[i],1); serialwrite(latitude[i]); if(i==24) { lcdwrite(' ',1); i++; } } serialprintln(" "); lcdwrite(192,0); lcdprint("Log:"); serialprint("Logitude:"); for(int i=29;i<41;i++) { logitude[i]=buf[i]; lcdwrite(logitude[i],1); serialwrite(logitude[i]); if(i==38) { lcdwrite(' ',1); i++; } } |
Программа получилась немного сложноватой, но если для аналогичной задачи использовать плату Arduino, то работа с с GPS модулем значительно упростится:
- GPS часы на Arduino Uno;
- отслеживание местоположения автомобиля с использованием GPS, GSM и Arduino;
- отслеживание местоположения автомобиля на Google Maps с помощью Arduino, ESP8266 и GPS.
Полный текст программы на языке С (Си)
В этом разделе статьи приведен полный текст программы, позволяющий произвести подключение GPS модуля к микроконтроллеру AVR ATmega16/32, извлечения из него координат широты и долготы и их отображения на экране ЖК дисплея.
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 |
/* * GPS_interfacing.c * * Created: 8/26/2019 10:17:24 PM * Author: Evan */ #define F_CPU 8000000ul #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> /***MACROS*/ #define USART_BAUDRATE 9600 #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) #define LCDPORTDIR DDRB #define LCDPORT PORTB #define rs 0 #define rw 1 #define en 2 #define RSLow (LCDPORT&=~(1<<rs)) #define RSHigh (LCDPORT|=(1<<rs)) #define RWLow (LCDPORT&=~(1<<rw)) #define ENLow (LCDPORT&=~(1<<en)) #define ENHigh (LCDPORT|=(1<<en)) enum { CMD=0, DATA, }; char buf[100]; volatile char ind,flag,stringReceived; char gpgga[]={'$','G','P','G','G','A'}; char latitude[12]; char logitude[12]; void serialwrite(char ch); void lcdwrite(char ch,char r) { LCDPORT=ch & 0xF0; RWLow; if(r == 1) RSHigh; else RSLow; ENHigh; _delay_ms(1); ENLow; _delay_ms(1); LCDPORT=ch<<4 & 0xF0; RWLow; if(r == 1) RSHigh; else RSLow; ENHigh; _delay_ms(1); ENLow; _delay_ms(1); } void lcdprint(char *str) { while(*str) { lcdwrite(*str++,DATA); //__delay_ms(20); } } void lcdbegin() { char lcdcmd[5]={0x02,0x28,0x0E,0x06,0x01}; for(int i=0;i<5;i++) lcdwrite(lcdcmd[i], CMD); } void serialbegin() { UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); UBRRH = (BAUD_PRESCALE >> 8); UBRRL = BAUD_PRESCALE; UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE); } ISR(USART_RXC_vect) { char ch=UDR; buf[ind]=ch; ind++; if(ind<7) { if(buf[ind-1] != gpgga[ind-1]) // $GPGGA ind=0; } if(ind>=50) stringReceived=1; } void serialwrite(char ch) { while ((UCSRA & (1 << UDRE)) == 0); UDR = ch; } void serialprint(char *str) { while(*str) { serialwrite(*str++); } } void serialprintln(char *str) { serialprint(str); serialwrite(0x0d); serialwrite(0x0a); } int main() { LCDPORTDIR=0xFF; serialbegin(); serialprint("Saddam Khan"); lcdbegin(); lcdprint("GPS Interfacing"); lcdwrite(192,CMD); lcdprint("Using Atmega16 "); _delay_ms(2000); lcdwrite(1,0); lcdprint("Waiting for GPS"); _delay_ms(2000); sei(); while(1) { if(stringReceived == 1) { cli(); serialprint("Received String:"); for(int i=0;i<ind;i++) serialwrite(buf[i]); ind=0; stringReceived=0; serialprintln(" "); lcdwrite(0x80,0); lcdprint("Lat:"); serialprint("Latitude:"); for(int i=15;i<27;i++) { latitude[i]=buf[i]; lcdwrite(latitude[i],1); serialwrite(latitude[i]); if(i==24) { lcdwrite(' ',1); i++; } } serialprintln(" "); lcdwrite(192,0); lcdprint("Log:"); serialprint("Logitude:"); for(int i=29;i<41;i++) { logitude[i]=buf[i]; lcdwrite(logitude[i],1); serialwrite(logitude[i]); if(i==38) { lcdwrite(' ',1); i++; } } serialprintln(" "); serialFlush(); _delay_ms(2000); sei(); } } return 0; } |
Здравствуйте!Помогите пожалуйста собрать устройство на основе сравнения GPS координаты с координатой из списка и выдачи сигнала при нахождении в предустановленном радиусе.ПРинимаю любые советы. Моё мыло sergonijсобакаgmail.com. Спасибо!
Здравствуйте,сможете скинуть разведенную плату в протеусе?
Добрый день. К сожалению, не могу, у меня ее нет
Здравствуйте,у меня вопрос по программированию МК в Atmel studio.
Вопрос такой:интересует алгоритм написания функции для МК AVR 32,
отправка показаний датчика через GSM модуль (SIM800C) по СМС на мобильник,
например:напряжение с АЦП(зарядное для акб.),
или запрос с мобильного баланса GSM модуля,
есть функция отправки смс с заранее написанными смс,
не могу понять как переделать функцию ,чтобы отправлять по смс ,
постоянно меняющиеся данные с датчика или запрос о балансе,
вот функция USART
void USART_SendString(char *str) /* Отправить строку функции данных USART */
{
int i=0;
while (str[i]!=0)
{
USART_TxChar(str[i]); /* Отправить каждый символ строки до NULL */
i++;
}
}
вот функция отправки смс:
void GSM_Send_Msg(char *num,char *sms)
{
char sms_buffer[35];
buffer_pointer=0;
sprintf(sms_buffer,"AT+CMGS=\"%s\"\r",num);
USART_SendString(sms_buffer); //*отправить команду AT+CMGS="Mobile No."\r */
while(1)
{
if(buff[buffer_pointer]==0x3e) //*ждать символа '>'*/
{
LCD_String_xy(1,0,"OTPRAVL1");
_delay_ms(3000);
LCD_Clear();
buffer_pointer = 0;
memset(buff,0,strlen(buff));
USART_SendString(sms); //* отправить сообщение на указанный nom. */
USART_TxChar(26);
USART_TxChar(0); //* отправьте Ctrl + Z, тогда будет передаваться только сообщение*/
break;
}
buffer_pointer++;
}
buffer_pointer = 0;
memset(buff,0,strlen(buff));
memset(sms_buffer,0,strlen(sms_buffer));
}
если не трудно объясните,что нужно дописать,
или скиньте ссылку на эту тему.
Добрый вечер. По этому вопросу вам можно прочитать статью на нашем сайте про подключение GSM модуля к микроконтроллеру AVR ATmega16. В ней рассмотрены прием и передача сообщений с помощью GSM модуля.
В коде программы какое исходное (начальное) значение у регистров PORTB и DDRB?
В функции int main() первой строкой идет команда "LCDPORTDIR=0xFF;", в соответствии с определенным в начале программы макросом "#define LCDPORTDIR DDRB" получаем что начальное значение DDRB=0xFF. Затем в функции int main() происходит вызов функции lcdbegin(), внутри которой вызывается функция lcdwrite, в которой первой строкой идет команда LCDPORT=ch & 0xF0, а в соответствии с ранее определенным макросом "#define LCDPORT PORTB" получаем что начальное значение PORTB=ch & 0xF0. К сожалению, программа написана достаточно сложновато, но поскольку она не моя, то я в нее никаких изменений не вносил. Значительно более просто о работе микроконтроллера AVR с ЖК дисплеем можно прочитать в этой статье.
"Но я стараюсь разбираться во всех статьях которые перевожу"
Тогда вопрос к автору статьи, вы этот проект собирали?
В Студии этот исходник не компилируется. Есть функции в программе, которые просто не заявлены.
Но, все поддается лечению "ломать, не строить".
Нет, я этот проект лично не собирал. У меня, пока, к сожалению не хватает времени чтобы их собирать, я пока успеваю только переводить статьи. Но в том, что подключить GPS модуль к микроконтроллеру можно - я уверен. Авторы программы - индусы, они могли использовать не студию, а другое программное обеспечение - поэтому она может в студии не компилироваться. Либо же в тексте программы могла закрасться небольшая опечатка.
Цель моего сайта - не дать готовые решения, а научить посетителей сайта их делать самим,чтобы они разобрались и сами могли потом видоизменять программу под те возможности, которые им нужны. Поэтому каждый проект на сайте снабжен достаточно подробным объяснением. Если у вас есть конкретные вопросы по тексту статьи или программы, с радостью отвечу на них.
Спасибо ! Тем интереснее будет разобраться )
Спасибо и вам что оценили мой труд. Если у вас получится сделать эту конструкцию и запустить ее в работу буду признателен если поделитесь ценными советами относительно ее создания - ведь всегда при написании статьи "что то остается за кадром". Готов даже опубликовать ваш мини-очерк о создании этого устройства в конце статьи с вашими фотографиями.
В будущем я и сам хочу попробовать реализовывать те статьи, которые я перевожу, в "железе", но пока, к сожалению, не хватает времени заняться этим
Вы написали "В этом проекте мы будем использовать GPS библиотеку, в которой есть функции для извлечения широты и долготы из данных GPS модуля, поэтому нам не придется программировать это вручную."
Но где подключение этой библиотеки ? Похоже, что Вы запрограммировали все вручную.
Если код писался в Code Vision , то хотелось бы ясно понять где самостоятельно написанный код, а где "творчество" CodeVision
Добрый вечер. Спасибо что нашли опечатку, библиотека действительно не использовалась, автор статьи совершил опечатку (видимо он скопировал это предложение из похожей статьи на Arduino), а я не заметил это при переводе. К сожалению, программа не моя - не люблю присваивать себе чужой труд. Статья переведена с иностранного сайта, ее оригинал - https://circuitdigest.com/microcontroller-projects/gps-module-interfacing-with-atmega16-32-avr-microcontroller.
Но я стараюсь разбираться во всех статьях которые перевожу, поэтому если есть вопросы могу попробовать ответить на них.