GPS модули широко используются в современной электронике для определения местоположения, основываясь на координатах долготы и широты. Системы мониторинга транспортных средств, часы GPS, системы предупреждения о чрезвычайных происшествиях, системы наблюдения – это лишь небольшой список приложений, в которых может потребоваться технология GPS. Система GPS обеспечивает информацию о высоте, долготе, широте, реальном времени и ряд другой информации о местоположении, которая берется с нескольких спутников. В данной статье мы рассмотрим подключение GPS модуля к микроконтроллеру AVR, с помощью которого мы будем считывать информацию из данного модуля (широту и долготу) и отображать ее на жидкокристаллическом (ЖК) дисплее 16x2.

Необходимые компоненты
- Микроконтроллер ATmega16/32 (купить на AliExpress).
- Программатор AVR-ISP (купить на AliExpress), USBASP (купить на AliExpress) или другой подобный.
- GPS модуль (uBlox Neo 6M GPS (или 7M) (купить на AliExpress).
- ЖК дисплей 16x2 (купить на AliExpress).
- Антенна типа "длинный провод".
- Резисторы 2,2 кОм, 1 кОм.
- Конденсатор 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).
#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, широты, долготы и флагов.
char buf[100];
volatile char ind,flag,stringReceived;
char gpgga[]={'$','G','P','G','G','A'};
char latitude[12];
char logitude[12];
Запрограммируем ряд функций для работы с ЖК дисплеем.
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".
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) извлечем и отобразим на экране ЖК дисплея координаты широты и долготы нашего местоположения.
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, извлечения из него координат широты и долготы и их отображения на экране ЖК дисплея.
/*
* 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.
Но я стараюсь разбираться во всех статьях которые перевожу, поэтому если есть вопросы могу попробовать ответить на них.