Купил на алиэкспрессе GPS-модуль GY-NEO6MV2, с помощью которого можно определить координаты местоположения. Интересно для всяких рыбаков, лесников, грибников и тех, кто не может с помощью телефона определить свои координаты, или находится там, где нет сотовых телефонных станций.
GPS является аббревиатурой, т.е. расшифровывается как: Global Position System. GPS-модуль предназначен для получения сигналов позиционирования со спутников, которые летают над Землёй. Связь, само-собой, осуществляется в одном направлении – на приём. Поэтому при подключении модуля к Ардуино достаточно подключить вывод Tx модуля с Rx Ардуино. Так как само Ардуино использует последовательный порт Rx/Tx для связи с компьютером, то необходимо для GPS-модуля создать последовательный порт, который бы использовал иные контакты, отличные от 0(Rx)/ 1(Tx). Для этого можно воспользоваться функцией библиотеки SoftwareSerial. Используя эту библиотеку можно назначить любые порты под Rx/Tx. В моей программе они назначены на RXPin = 4, TXPin = 3. Скорость передачи данных с модуля по умолчанию: 9600 бод. Поэтому в скетче устанавливаем такое же значение при инициализации программного последовательного порта.
По последовательному порту с приёмника GPS-модуля поступают текстовые символы, поля которых отделены запятыми. В конце строки стоит завершающий символ перевода строки. Формат сообщений соответствует стандарту NMEA – National Marine Electronics Association. Несколько подробнее этот формат описан ниже в начале скетча. Отмечу лишь, что посылка с основными данными начинается с кодового слова $GPRMC, поэтому декодировать будем ту сторку, которая имеет вначале это слово.
Для вывода информации, полученной с GPS-модуля, использую небольшой OLED дисплей под управлением контроллера SSD1306. Почему OLED дисплей? Потому, что его можно считывать при дневном освещении, что затруднительно с TFT дисплеем.
Схема подключения
Схема подключения GPS-модуля GY-NEO6MV2 к Ардуино простейшее: Питание на модуль на контакт VCC подавал и +5 В, и +3.3 В, какой-либо разницы не заметил, в обоих случаях модуль выдаёт необходимую информацию. Сам контроллер GPS-модуля работает от +3.3 В, на плате модуля есть стабилизатор на это напряжение, поэтому модуль можно запитывать напрямую от +5 В Ардуино – удобно, если будет использоваться Arduino Pro Mini, у которой на плате нет стабилизатора на +3.3 В.
Выходная информация снимается с контакта Tx модуля, его подключаем к программному последовательному порту Ардуино. В моём скетче это цифровой контакт 4 Ардуино.
Контакт Rx модуля не используется.
Кому интересно, то схема самого модуля ниже.
Скетч
Были проблемы с выводом на OLED дисплей информации типа string. Поэтому вывожу координаты в том формате, в котором их выдаёт сам модуль, то есть значение широты и долготы необходимо дополнительно разделить на 100, тогда получим значение в градусах и минутах разделённых десятичной точкой.
Дополнительно кроме широты и долготы можно выводить: скорость, дату и точное время. Время вывожу с точностью до секунды, хотя модуль принимает очень точное время с точностью до тысячной секунды.
Ниже представлен скетч считывания информации с GPS-модуля GY-NEO6MV2. Файл со скетчем можно скачать в подразделе Приложение.
/******************************************************
* Информация по декодированию посылки с GPS-module
*
Формат сообщений соответствует стандарту национальной
ассоциации морской электроники NMEA
(National Marine Electronics Association).
Сообщение — это текстовая строка, завершающаяся
символом перевода строки, с полями,
разделенными запятыми.
Далее показано, как выглядит типичное сообщение:
$GPRMC,081019.548,A,5342.6316,
N,00239.8728,W,000.0,079.7,110613,,,A*76
Поля в данном примере имеют следующие значения:
• 0 $GPRMC — тип сообщения;
• 1 081019.548 — время (очень точное)
в 24-часовом формате, 8:10:19.548;
• 2 A — метка готовности A - ok, V - недействительно
• 3,4 5342.6316, N — широта, умноженная на 100,
то есть 53,426316 градуса северной широты;
• 5,6 00239.8728,W — долгота, умноженная на 100,
то есть 0,2398728 градуса западной долготы;
• 7 000.0 — скорость;
• 8 079.7 — курс 79,7 градуса;
• 9 110613 — дата, 11 июня 2013.
Остальные поля для данного примера не имеют значения.
ПРИМЕЧАНИЕ
Полный список сообщений NMEA GPS можно найти
по адресу http://aprs.gids.nl/nmea/
$ GPBOD - пеленг, исходная точка к пункту назначения
$ GPBWC - пеленг и расстояние до маршрутной точки,
большой круг
$ GPGGA - данные о фиксации глобальной
системы позиционирования
$ GPGLL - географическое положение,
широта / долгота
$ GPGSA - GPS DOP и активные спутники
$ GPGSV - спутники GPS в вид
$ GPHDT - товарную, True
$ GPR00 - Список путевых точек
в настоящее время активный маршрут
$ GPRMA - Рекомендуемый минимальный
удельный Loran-C данные
$ GPRMB - Рекомендуемая минимальная
информация навигации
$ GPRMC - Рекомендуемый минимальный
удельный GPS / Транзитные данные
$ GPRTE - Маршруты
$ GPTRF - Данные исправления транзита
$ GPSTN - Несколько идентификаторов данных
$ GPVBW - Двойная скорость
относительно земли / воды
$ GPVTG - Трек и скорость относительно земли
$ GPWPL - Местоположение маршрутной точки
$ GPXTE - Поперечная ошибка, измеренная
$ GPZDA - Дата и время
Существует полный список $GPxxx кодов
членов предложений, доступных,
без ссылок на деталь формата.
$GPRMC, hhmmss.ss, A, llll.ll, a, yyyyy.yy,
a, xx, xx, ddmmyy, xx, a * hh
1 = UTC время ччммсс.сс
2 = статус данных А = норма
(V = предупреждение навигационного приемника)
3 = Широта
4 = N или S
5 = долгота
6 = E или W
7 = скорость относительно земли в узлах
8 = Трасса исправлена в градусах Истина
9 = дата UT
10 = Степени магнитного отклонения
(восточная вариация вычитается из истинного курса)
11 = E или W
12 = Контрольная сумма
$GPZDA - Дата и время
метка, UTC, день, месяц, год и местный часовой пояс.
$GPZDA, hhmmss.ss, xx, xx, xxxx, xx, xx
1 = hhmmss.ss = UTC
2 = xx = день, с 01 по 31
3 = xx = месяц, с 01 по 12
4 = xxxx = год
5 = xx = описание локальной зоны, от 00 до + / - 13 часов
6 = xx = Описание минут
местной зоны (тот же знак, что и часы)
*/
/***********************************************************
http://www.mralb.ru/sections/programming/arduino_16.php
2020-07-29 Mr.ALB Тренировка в программировании Ардуино
2020-11-11 Mr.ALB Проверка на OLED SSD 0.96 inch 128*64
2020-11-12 Mr.ALB Модуль GPS NEO-6M
2020-11-15 Mr.ALB Переделка всей программы и функций
2020-12-01 Mr.ALB Выборочный вывод доп.строк
Arduino UNO NEO-6M
+3.3V/5V VCC
GND GND
pin4 TX
- RX - не используется
Программное подключение дисплея по SPI
ARDUINO R OLED SSD 0.96' 128*64
pin9 - R=1k - SCL
pin10 - R=1k - SDA
pin8 - R=1k - RST | RES
pin11 - R=1k - DC
pin12 - R=1k - CS
+3.3V - VCC
GND - GND
****************************************************/#include<SPI.h>#include<Adafruit_GFX.h>#include<Adafruit_SSD1306.h>// OLED display width, in pixels#define SCREEN_WIDTH 128
// OLED display height, in pixels#define SCREEN_HEIGHT 64
// Declaration for SSD1306 display
// connected using software SPI:
// Программный SPI:#define OLED_RESET 8
#define OLED_SCK 9
#define OLED_SDA 10
#define OLED_DC 11
#define OLED_CS 12
// Создаём объект дисплея oled
// Adafruit_SSD1306(uint8_t w, uint8_t h,
// int8_t mosi_pin,int8_t sclk_pin,
// int8_t dc_pin,int8_t rst_pin,
// int8_t cs_pin);
Adafruit_SSD1306 oled
(
SCREEN_WIDTH,
SCREEN_HEIGHT,
OLED_SDA,
OLED_SCK,
OLED_DC,
OLED_RESET,
OLED_CS
);
const uint8_t znak_w = 6,// Ширина знака в пикселях
znak_h = 8; // Высота знака в пикселяхconst uint8_t pos_x = 31,// Позиция параметра 31 пикс// Позиция размерности
pos_x_d = pos_x + 72,// Строка широты
pos_y_lat = znak_h * 2 + 2,// Строка долготы
pos_y_long = pos_y_lat + znak_h + 1;
uint8_t pos_y_spd = pos_y_long + znak_h + 1,// Скорость
pos_y_date = pos_y_spd + znak_h + 1,// Строка даты
pos_y_time = pos_y_date + znak_h + 1;// Строка времени// Поясное время: Самарское UTC+4constint time_offset = 4;
// Массив для считанной строки с модуля GPSconstint sentenceSize = 80;// Размер строкиchar sentence[sentenceSize];// Массив под строку// Массив строк для заставкиconstchar*zastav[] =
{
"GPS","-module","Mr.ALB","v1.2","2020-12-01"
};
// Массив строк основных надписейconstchar*text[] =
{
"Lat:","Lng:","Spd:","Date:","Time:"
};
// Программный серийный порт#include<SoftwareSerial.h>// TXpin-не используетсяstaticconstint RXPin = 4, TXPin = 3;
staticconstuint32_t GPSBaud = 9600;
// Программный серийный(последовательный) порт для GPS deviceSoftwareSerial ss(RXPin, TXPin);
// Флаги выбора дополнительных строкbool flag_spd =false; // Скоростьbool flag_date =true; // Датаbool flag_time =true; // Время
/**********************
Настройка программы
**********************/voidsetup()
{
Serial.begin(9600);
// Подключение дисплеяif (!oled.begin(SSD1306_SWITCHCAPVCC))
{
Serial.println(F("SSD1306 allocation failed"));
while (true); // Ошибка дисплея. Останов программы
}
// Старт программного серийного порта для считывания с GPS
ss.begin(GPSBaud);
// Заставка
oled.clearDisplay();
fnStrPrintOLED(30, 0, zastav[0], 2,WHITE,false);
fnStrPrintOLED(68, 0, zastav[1], 1,WHITE,false);
fnStrPrintOLED(46, znak_h * 3, zastav[2], 1,WHITE,false);
fnStrPrintOLED(52, znak_h * 4 + 3, zastav[3], 1,WHITE,false);
fnStrPrintOLED(36, znak_h * 5 + 6, zastav[4], 1,WHITE,true);
oled.display(); // Вывод на экранdelay(3000);
// Очистка буфера
oled.clearDisplay();
// Вывод заголовка
fnStrPrintOLED(0, 0, zastav[3], 1,WHITE,false);
fnStrPrintOLED(30, 0, zastav[0], 2,WHITE,false);
fnStrPrintOLED(68, 0, zastav[1], 1,WHITE,true);
// Вывод основных надписей
fnStrPrintOLED(0, pos_y_lat, text[0], 1,WHITE,false);
fnStrPrintOLED(0, pos_y_long, text[1], 1,WHITE,false);
if (flag_spd)
{
fnStrPrintOLED(0, pos_y_spd, text[2], 1,WHITE,false);
}
else
{ // Если скорость не выводим,
// то дату и время выводим выше на строчку
pos_y_date -= znak_h;
pos_y_time -= znak_h;
}
if (flag_date)
{
fnStrPrintOLED(0, pos_y_date, text[3], 1,WHITE,false);
}
else
{ // Если дату не выводим,
// то время выводим выше на строчку
pos_y_time -= znak_h;
}
if (flag_time)
{
fnStrPrintOLED(0, pos_y_time, text[4], 1,WHITE,true);
}
}
/*********************
Основная программа
********************/voidloop()
{
staticint i = 0;
char ch =' ';
while (ss.available() && ch !='\n'&& i < sentenceSize)
{
//Читаем посимвольно с программного последовательного портаchar ch = ss.read();
if (ch =='$'&& i == 0)
{
sentence[i] = ch;
i++;
}
else
{
if (sentence[0] ='$')
{
sentence[i] = ch;
i++;
}
}
}
sentence[i] ='\0';
i = 0;
Serial.println(sentence);
displayGPS(); // Вывод параметровdelay(300);
}
/***************************************
Функция вывода значений с модуля GPS
2020-11-12 Mr.ALB
*/void displayGPS()
{
char field[12];// Буфер под значение поляString str;
getField(field, 0); // Нулевое поле с меткойif (strcmp(field,"$GPRMC") == 0)
{
// Вывод значения широты
getField(field, 3);
// Очистка места под новое значение
fnClearPlace(pos_x, pos_y_lat, SCREEN_WIDTH - pos_x - 1);
fnStrPrintOLED(pos_x, pos_y_lat, field, 1,WHITE,false);
// Размерность широты N/S
getField(field, 4);
str = field[0];
fnClearPlace(pos_x_d, pos_y_lat, znak_w * 2);
fnStrPrintOLED(pos_x_d, pos_y_lat, str, 1,WHITE,true);
// Вывод значения долготы
getField(field, 5);
fnClearPlace(pos_x, pos_y_long, SCREEN_WIDTH - pos_x - 1);
fnStrPrintOLED(pos_x, pos_y_long, field, 1,WHITE,false);
// Размерность долготы E/W
getField(field, 6);
str = field[0];
fnClearPlace(pos_x_d, pos_y_long, znak_w * 2);
fnStrPrintOLED(pos_x_d, pos_y_long, str, 1,WHITE,true);
// Вывод значения скоростиif (flag_spd)
{
getField(field, 7);
fnClearPlace(pos_x, pos_y_spd, SCREEN_WIDTH - pos_x - 1);
fnStrPrintOLED(pos_x, pos_y_spd, field, 1,WHITE,true);
}
// Вывод датыif (flag_date)
{
getField(field, 9);
str = field[0];
str += field[1];
// Очистка места под новое значение
fnClearPlace(pos_x, pos_y_date, znak_w * 10);
fnStrPrintOLED(pos_x, pos_y_date, str, 1,WHITE,false);
fnStrPrintOLED(pos_x + 12, pos_y_date,"-", 1,WHITE,false);
str = field[2];
str += field[3];
fnStrPrintOLED(pos_x + 18, pos_y_date, str, 1,WHITE,false);
fnStrPrintOLED(pos_x + 30, pos_y_date,"-20", 1,WHITE,false);
str = field[4];
str += field[5];
fnStrPrintOLED(pos_x + 48, pos_y_date, str, 1,WHITE,true);
}
// Вывод значения времениif (flag_time)
{
getField(field, 1);
// Очистка места под новое значение
fnClearPlace(pos_x, pos_y_time, znak_w * 10);
str = field[0];
str += field[1];
int ihour = str.toInt() + time_offset;
if (ihour < 10)str ="0";
else str ="";
str +=String(ihour);
fnStrPrintOLED(pos_x, pos_y_time, str, 1,WHITE,false);
str = field[2];
str += field[3];
fnStrPrintOLED(pos_x + 12, pos_y_time,":", 1,WHITE,false);
fnStrPrintOLED(pos_x + 18, pos_y_time, str, 1,WHITE,false);
str = field[4];
str += field[5];
fnStrPrintOLED(pos_x + 30, pos_y_time,":", 1,WHITE,false);
fnStrPrintOLED(pos_x + 36, pos_y_time, str, 1,WHITE,true);
}
}
}
/*******************************************************
Функция получения поля из массива в буффер по индексу
buffer - указатель на массив
index - номер необходимого поля
2020-11-15 Mr.ALB
*/void getField(char*buffer,int index)
{
int sentencePos = 0;
int fieldPos = 0;
int fieldCount = 0;
for (sentencePos = 0; sentencePos < sentenceSize; sentencePos++)
{
if (fieldCount == index)
{
if (sentence[sentencePos] ==',')break;
// Заполнение поляbuffer[fieldPos] = sentence[sentencePos];
fieldPos ++;
}
if (fieldCount < index)
{ // Поиск заданного поляif (sentence[sentencePos] ==',')fieldCount++;
}
}
buffer[fieldPos] ='\0';// Завершающий символ
}
/*************************************************
Функция вывода строкового параметра на дисплее
2020-07-29 Mr.ALB начальная
2020-11-12 Mr.ALB переделка
2020-11-15 Mr.ALB добавлен flag_display
*/void fnStrPrintOLED
(
byte x,//x-параметраbyte y,//y-параметраString str,//строка-параметрbyte fsp,//font size-параметраint color,//Цвет WHITE=on|BLACK=offbool flag_display //Вывод на экран
)
{
oled.setCursor(x, y);
oled.setTextSize(fsp);
oled.setTextColor(color);
oled.print(str);
// Вывод на экранif (flag_display)oled.display();
}
/********************************************
Функция стирания места под новое значение
Закрашиваем чёрным прямоугольником
2020-11-12 Mr.ALB
*/void fnClearPlace(byte x,byte y,byte w)
{
oled.fillRect(x, y, w, znak_h,BLACK);
}
Реализация
Для проверки работоспособности GPS-модуля использовал Arduino UNO R3. Можно использовать любое, только для дисплея необходимо напряжение +3.3 В, его можно получить через стабилизатор или подключать контакт VCC дисплея через сопротивление около 470 Ом на +5 В. Контакты дисплея используемые для SPI подключены через сопротивления 1.2 кОм.
Чтобы устранить помехи, подключил параллельно питанию Ардуино два конденсатора: на 0.1 мкФ, и на 1000 мкФ 6.3 В.
Этот проект чисто пробный, проверить работоспособность модуля. Какую-то конструкцию не делаю, т.к. до законченности требуется добавить несколько кнопок настройки, чтобы, к примеру, можно было бы устанавливать поясное время. В этом скетче стоит поясное время Самары UTC+4, себе установите Ваше поясное время.
В заключение хочу сказать, что на GPS-модуле GY-NEO6MV2 есть красный светодиодик. Если он не светится и не мигает, то значит ваш модуль не обнаружил достаточное количество спутников и данные поступают неверные. Ещё может быть, что батарейка хранения данных в EEPROM модуля разрядилась, требуется какое-то время, пока она не подзарядится. Проверять работу модуля лучше всего на открытом пространстве или, на крайний случай, на подоконнике или балконе. Если у вас есть USB удлиннитель, то можно подключить к компьютеру всё устройство и через монитор последовательного порта смотреть какие посылки принимет ваш GPS-модуль. Будет более понятно.
Заметил у себя, что когда недостаточно спутников, то в полсылке поля с координатами пустые, а вот время и дата заполнены, поэтому на дисплей выводится только дата и время.