Подключение GPS модуля к микроконтроллеру AVR ATmega16/32

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

Подключение GPS модуля к микроконтроллеру AVR ATmega16/32: внешний вид конструкции

Необходимые компоненты

Микроконтроллер ATmega16/32
Программатор AVR-ISP, USBASP или другой подобный
GPS модуль (uBlox Neo 6M GPS)
ЖК дисплей 16×2
Антенна типа «длинный провод»
Резистор 2,2 кОм
Конденсатор 1000 пФ
Конденсатор 10 пФ
Соединительные провода
Преобразователь напряжения LM7805
DC Jack
Адаптер 12 В
Burgstips
Макетная плата

Получение данных местоположения от GPS модуля

Ublox Neo 6M представляет собой последовательный GPS модуль, который передает детали местоположения через последовательный порт. Он имеет 4 контакта, назначение которых представлено в следующей таблице.

Контакт Описание
Vcc 2.7 – 5V питающее напряжение
Gnd земля
TXD передача данных
RXD прием данных

Его внешний вид представлен на следующем рисунке.

Внешний вид GPS модуля Ublox Neo 6M

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

Расшифровка данной строки (данных глобального позиционирования):

  1. Строка всегда начинается со знака “$”.
  2. Аббревиатура GPGGA означает фиксированные данные системы глобального позиционирования.
  3. “,” означает разделение между двумя значениями.
  4. 141848.00: всемирное время по Гринвичу 14(hr):18(min):48(sec):00(ms).
  5. 2237.63306,N: Широта (Latitude) 22(градуса) 37(минут) 63306(секунд) North (Север).
  6. 08820.86316,E: Долгота (Longitude) 088(градуса) 20(минут) 86316(секунд) East (Восток).
  7. 1 : Fix Quantity (Фиксированное количество) 0= неправильные данные, 1= достоверные данные, 2=DGPS fix.
  8. 03 : число спутников, которые мы в данный момент видим.
  9. 1.0: HDOP.
  10. 2.56,M : высота над уровнем моря (в метрах).
  11. 1.9,M : Geoids height (геоидная высота).
  12. *74 : контрольная сумма.

То есть, фактически, нам будут необходимы только п.5 и п.6 из представленных данных чтобы получить информацию о местоположении модуля. В этом проекте мы будем использовать GPS библиотеку, в которой есть функции для извлечения широты и долготы из данных GPS модуля, поэтому нам не придется программировать это вручную.

Схема устройства

Схема устройства приведена на следующем рисунке.

Схема подключения GPS модуля к микроконтроллеру AVR ATmega16/32

Устройство запитывается от адаптера на 12В постоянного тока, но, поскольку схема работает от напряжения 5В, то в схеме присутствует регулятор напряжения LM7805. ЖК дисплей 16×2 сконфигурирован для работы в 4-битном режиме. GPS модуль также запитывается от напряжения 5В и его вывод передачи (tx pin) напрямую подсоединен к приемному выводу (Rx) микроконтроллера Atmega. Для задания тактовой частоты микроконтроллера используется кварцевый генератор на 8 МГц.

Подача питающего напряжения и подключение антенны

Последовательность действий по подключению GPS модуля к микроконтроллеру AVR

  1. Установить конфигурацию микроконтроллера, включая установку тактовой частоты.
  2. Установить необходимый для подключения ЖК дисплея порт.
  3. Подсоединить GPS модуль к микроконтроллеру используя USART (универсальный синхронно-асинхронный приемопередатчик).
  4. Инициализировать систему UART в режиме ISR (Interrupt Service Routine — процедура обработки прерывания), со скоростью 9600 бод/с и ЖК дисплеем в 4-битном режиме.
  5. Задать в программе 2 символьных массива, в которые будем сохранять широту и долготу.
  6. Принимать по одному символу в каждый момент времени и проверять является ли символ $ или нет.
  7. Если мы приняли $ (нашли его в составе принимаемой строки символов) нам необходимо проверить $GPGGA, то есть эти 6 букв, включая и символ $.
  8. Если это действительно GPGGA, то принимаем всю эту строку и устанавливаем необходимые флаги.
  9. Извлекаем из этой строки широту и долготу и записываем их в наши массивы.
  10. Выводим значения этих массивов на экран ЖК дисплея.

Пример работы схемы

Объяснение кода программы

Полный код программы вместе с видео, демонстрирующем работу схемы, приведены в конце статьи. В этом разделе объяснены наиболее важные участки кода.

В начале подключим необходимые заголовки и запишем макросы для поразрядной маски для ЖК дисплея и конфигурирования последовательного порта (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++;
}
}

Полный текст программы на языке С (Си)

В этом разделе статьи приведен полный текст программы, позволяющий произвести подключение GPS модуля к микроконтроллеру AVR ATmega16/32, извлечения из него координат широты и долготы и их отображения на экране ЖК дисплея.

#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;
}

Видео, демонстрирующее работу схемы

(1 голосов, оценка: 5,00 из 5)
Загрузка...
145 просмотров

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *