Самодельный gps трекер на ардуино. Лучшие GPS-трекеры для машины (маяки)

Самодельный gps трекер на ардуино. Лучшие GPS-трекеры для машины (маяки)
Самодельный gps трекер на ардуино. Лучшие GPS-трекеры для машины (маяки)

Индивидуальные GPS передатчики

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

Так устройства, основанные на GPS технологиях, добрались до карманных гаджетов и прочно там обосновались, даря людям новые возможности. Особенно стоит выделить индивидуальные GPS передатчики.

По сути, это те же самые GPS-трекеры, только рассчитанные на использование не на транспортном средстве, а человеком в повседневной жизни.

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

Внутри у неё расположен GPS модуль, определяющий координаты на местности, GSM/GPRS модуль, передающий информацию и принимающий управляющие команды, а так же источник питания, обеспечивающий автономную работу в течение длительного времени.

Функциональные возможности GPS передатчиков

По мере роста функциональности, появляются следующие возможности прибора:


Варианты исполнения GPS передатчиков

В зависимости от комплектации, могут значительно отличаться корпуса передатчиков. Различные модели имеют исполнения в виде сотовых телефонов, классических навигаторов, или даже наручных часов.

Красочный дизайн специальных версий и полезные дополнения позволяют детям относиться к данным устройствам не как к «родительским шпионам», а как к модным и практичным гаджетам.

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

Статьи о GPS-трекерах

В этой статье я покажу как использовать gsm модуль совместно с arduino на примере sim800L. Эта же инструкция вполне подойдет для использования любых других gsm модулей, например, sim900 и т.д., потому что все модули работают примерно по одному и тому же типу — это обмен АТ-командами через порт.

Использование модуля с arduino я покажу на примере SMS-реле, которое можно использовать для управления устройством удаленно, посредством SMS-команд. Это можно применять совместно с автосигнализацией и т.д.

Подключается модуль к Arduino через UART интерфейс программного серийного порта, работающего на 2 и 3 цифровых выводах Arduino nano.

Работа Arduino с GSM модулями

Для питания модуля необходимо напряжение в диапазоне от 3.6В до 4.2В, это значит, что придется использовать дополнительный стабилизатор напряжения, так в Arduino установлен стабилизатор на 3.3 вольта, что не подходит для питания модуля, вторая причина установить дополнительный стабилизатор — GSM модуль является серьезной нагрузкой, так как в нем имеется не слабый передатчик, обеспечивающий стабильную связь с сотовой станцией. Питание для Arduino nano подводится к контакту VIN — это встроенный в Arduino стабилизатор, обеспечивающий работу модуля в широких диапазонах напряжения (6-10В). Модуль реле подключается согласно приведенному тексту программы, к 10 выводу Arduino nano и легко может быть изменен на любой другой, работающий как цифровой выход.

Работает это так: устанавливаем SIM-карту в GSM модуль, включаем питание и отправляем SMS с текстом «1» на номер SIM карты для того чтобы включить наше реле, чтобы отключить отправляем SMS с текстом «0».

#include
SoftwareSerial gprsSerial(2, 3); // установка контактов 2 и 3 для программного порта
int LedPin = 10; // для реле

void setup()
{
gprsSerial.begin(4800);
pinMode(LedPin, OUTPUT);

// настройка приема сообщений

gprsSerial.print(«AT+CMGF=1\r»);
gprsSerial.print(«AT+IFC=1, 1\r»);
delay(500);
gprsSerial.print(«AT+CPBS=\»SM\»\r»);
delay(500); // задержка на обработку команды
gprsSerial.print(«AT+CNMI=1,2,2,1,0\r»);
delay(700);
}

String currStr = «»;
// если эта строка сообщение, то переменная примет значение True
boolean isStringMessage = false;

void loop()
{
if (!gprsSerial.available())
return;

char currSymb = gprsSerial.read();
if (‘\r’ == currSymb) {
if (isStringMessage) {
// если текущая строка - сообщение, то…
if (!currStr.compareTo(«1»)) {
digitalWrite(LedPin, HIGH);
} else if (!currStr.compareTo(«0»)) {
digitalWrite(LedPin, LOW);
}
isStringMessage = false;
} else {
if (currStr.startsWith(«+CMT»)) {
// если текущая строка начинается с «+CMT», то следующая сообщение
isStringMessage = true;
}
}
currStr = «»;
} else if (‘\n’ != currSymb) {
currStr += String(currSymb);
}
}

Видео версия статьи:

Теги: #Arduino, #SIM800L

Ваша оценка:

Товары, использованные в данной статье:

← GPS-логгер на arduino | Управление реле по COM порту →

GSM сканер на RTL-SDR

| Главная | English | Разработка | FAQ |

Основные характеристики сканера

GSM сканер выполняет сканирование нисходящих каналов GSM и отображает информацию об уровне сигнала и принадлежности канала одному из трех основных операторов сотовой связи МТС, Билайн и Мегафон. По результатам работы сканер позволяет сохранить список идентификаторов базовых станций MCC, MNC, LAC и CI для всех сканированных каналов.
GSM сканер может быть использован для оценки уровня GSM сигнала, сравнения качества сигнала разных операторов, оценки радиопокрытия, при принятии решения об установке усилителей сигналов сотовой связи и регулировке их параметров, в образовательных целях и др.
Сканер работает под Windows и использует простой и дешевый приемник — RTL-SDR. Прочитать о RTL-SDR можно на:
RTL-SDR (RTL2832U) and software defined radio news and projects,
RTL-SDR – OsmoSDR,
RTL-SDR по-русски.
Параметрами RTL-SDR и определяются основные характеристики сканера. Безусловно GSM сканер не является заменой нормального измерительного оборудования.
Сканер распространяется бесплатно, без каких либо ограничений на использование.
Текущая версия поддерживает диапазон GSM 900 и не поддерживает GSM 1800. Это определяется тем, что рабочая частота RTL-SDR с тюнером R820T ограничена значением 1760 МГц. Есть надежда что применение экспериментального драйвера RTL-SDR позволит реализовать работу хотя бы в части диапазона 1800 МГц.

Запуск сканера

Последнюю версию сканера можно скачать по ссылке. Просто разархивируйте файл в удобное место и запустите gsmscan.exe.
Предыдущие версии сканера, ссылка на репозиторий с исходниками и другая информация связанная с разработкой находится на странице разработки.
Для работы сканера требуется установка драйверов RTL-SDR, если они еще не были установлены, это удобно сделать с помощью программы Zadig описание процедуры установки.

Использование сканера

Ниже представлен вид окна программы сканера:

По горизонтальной оси откладывается номер канала GSM в виде ARFCN или в МГц, по вертикальной оси уровень сигнала в дБм. Высота линии показывает уровень сигнала.

GSM модуль NEOWAY M590 связь с Ардуино

Если идентификаторы БС были декодированы успешно и они соответствуют идентификаторам тройки основных операторов связи, линии окрашиваются в соответствующие цвета.
Выпадающие списки в верхней части экрана позволяют выбирать SDR приемник, если их подключено несколько, диапазон работы GSM 900 или GSM 1800 и единицы измерения по горизонтальной оси ARFCN или МГц.
Кнопки позволяют сохранить отчет о работе сканера в виде списка декодированных базовых станций, очистить результаты декодирования БС и получить информацию о программе.

Принципы и особенности работы.

В процессе работы программа сканирует рабочий диапазон частот с шагом 2.0 МГц (10 каналов GSM) и оцифровывает сигнал с частотой дискретизации 2.4 МГц. Процесс сканирования состоит из быстрого прохода всего диапазона для измерения мощности сигнала и медленного прохода для декодирования идентификаторов БС.

Один шаг декодирования выполняется после прохода всего диапазона для измерения мощности. Таким образом, в диапазоне GSM 900, уровень сигнала обновляется приблизительно раз в 2 с, а полный проход декодирования занимает порядка 1 мин.
Из-за плохого качества сигнала получаемого с RTL-SDR, вероятность правильного декодирования системной информации (SI) широковещательного управляющего канала (BCCH) БС оказывается не высокой. Флуктуации уровня сигнала в результате много-лучевого распространения так же снижают вероятность декодирования системной информации. По этим причинам, для получения идентификаторов БС необходимо чтобы сканер накапливал информацию в течении времени порядка 10 мин. Но даже в этом случае, далеко не все каналы обеспечивают в данном месте достаточный уровень и качество сигнала для декодирования даже самым идеальным приемником. Кроме этого, не все каналы GSM используются для работы по стандарту GSM, как видно на рисунке выше, каналы 975 — 1000 заняты Мегафоном для работы по стандарту UMTS.
В процессе работы, сканер добавляет системную информацию о новых декодированных каналах в общий массив информации по каналам. Но информация о декодированных ранее каналах не стирается при недекодировании системной информации на данном шаге, и остается в массиве. Для очистки этой информации служит кнопка очистки результатов декодирования БС.
При нажатии на кнопку сохранения отчета, накопленные результаты сохраняются в текстовый файл с названием составленным из названия программы, даты и времени сохранения данных. Ниже для примера приведена часть файла отчета:
Сканер предназначен для работы под Windows 7, 8.1 и 10. работа тестировалась с тремя экземплярами RTL-SDR с тюнером R820T, другие типы тюнеров не тестировались.
Для работы под Windows XP собрана специальная версия программы, работает она в несколько раз медленнее стандартной версии.

Развитие.

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

Вам необходим источник точного времени от GPS? Данная статья покажет вам, как использовать модуль GPS для получения времени, даты и координат, и как показать их на LCD индикаторе с помощью Arduino.

Что необходимо?

  • компьютер с установленной Arduino IDE;
  • Arduino (мы используем Arduino Mega);
  • GPS модуль (мы используем EM-411, возможны и другие, поддерживающие протокол NMEA, например, VK2828U7G5LF или GY-NEO6MV2);
  • макетная плата , перемычки и потенциометр 5 кОм;
  • библиотека TinyGPS (ссылка ниже).

Введение

Создание системы глобального позиционирования, или GPS, началось в начале 1970-х годов. Каждая страна (Россия, США, Китай и т.д.) обладают своей собственной системой, но большинство средств спутниковой навигации в мире используют систему США.

Каждый спутник системы имеет атомные часы, которые непрерывно контролируются и корректируются NORAD (командованием воздушно-космической обороны Северной Америки) каждый день.

По сути, приемник по своим часам измеряет TOA (время получения сигнала, time of arrival) четырех спутниковых сигналов. Исходя из TOA и TOT (времени отправки сигнала, time of transmission), приемник вычисляет четыре значения времени «пролета» сигнала (TOF, time of flight), которые отличаются друг от друга в зависимости от расстояния спутник-приемник. Затем, исходя из четырех значений TOF, приемник вычисляет свое положение в трехмерном пространстве и отклонение своих часов.

Самые недорогие GPS приемники обладают точностью около 20 метров для большинства мест на Земле. Теперь посмотрим, как изготовить свои собственные часы GPS с помощью Arduino.

Аппаратная часть

Мой GPS модуль имеет 6 контактов: GND, Vin, Tx, Rx и снова GND. Шестой вывод никуда не подключен. Контакт GND соединен с корпусом на Arduino, Vin подключаем к шине +5В на Arduino, Tx подключен к выводу 10 на Arduino, а вывод Rx никуда не подключаем, так как не будем посылать на GPS модуль никаких сообщений. Мой модуль передает спутниковые данные, используя интерфейс RS-232, со скоростью 4800 бит/сек, которые принимаются Arduino на выводе 10.

Ниже показана фотография GPS модуля:

GPS модуль EM-411

Модуль отправляет то, что известно как NMEA сообщения. Здесь вы можете увидеть пример одного NMEA сообщения и его разъяснение (выдержка из технического описания):

$GPGGA,161229.487,3723.2475,N,12158.3416,W,1,07,1.0,9.0,M,0000*18

Формат данных GGA
Название Пример Единицы Описание
ID сообщения $GPGGA Заголовок протокола GGA
Время UTC 161229.487 hhmmss.sss (две цифры часы, две цифры минуты, затем секунды с точностью до тысячных)
Широта 3723.2475
Флаг N/S N N - север, S - юг
Долгота 12158.3416 ddmm.mmmm (первые две цифры градусы, затем минуты с точностью до десятитысячных)
Флаг E/W W E - восток, W - запад
Индикатор местоположения 1
  • 0 - местоположение недоступно или некорректно;
  • 1 - режим GPS SPS, местоположение корректно;
  • 2 - дифференциальный GPS, режим SPS, местоположение корректно;
  • 3 - режим GPS PPS, местоположение корректно.
Количество используемых спутников 07 В диапазоне от 0 до 12
HDOP 1.0 Ухудшение точности по горизонтали
Высота относительно уровня моря 9.0 метры
Единицы измерения M метры
Геоидальное различие Различие между земным эллипсоидом WGS-84 и уровнем моря (геноидом)
Единицы измерения M метры
Возраст дифференциальных данных GPS секунды Нулевые поля, когда DGPS не используется
ID станции, передающей дифференциальные поправки 0000
Контрольная сумма *18
Конец сообщения

Все эти данные принимаются Arduino через вывод 10. Библиотека TinyGPS читает сообщения GPGGA и GPRMC (для подробной информации о GPRMC смотрите техническое описание).

Arduino на схеме не показан. Подключите периферийные устройства согласно подписанным соединениям.


Схема GPS часов на arduino

Программное обеспечение

При подаче питания GPS модуль затрачивает некоторое время, чтобы получить правильное местоположения от спутников. Когда местоположение получено, модуль шлет NMEA сообщения на Arduino. Библиотека TinyGPS содержит функцию для получения времени и даты из GPRMC сообщения. Она называется crack_datetime() и принимает в качестве параметров семь указателей на переменные: год year , месяц month , день месяца day , часы hour , минуты minute , секунды second , и сотые доли секунды hundredths . Вызов функции выглядит так:

Gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths);

Вызов данной функции возвращает вам в переменных правильные значения до тех пор, пока с железом всё в порядке.

Чтобы получить ваше местоположение, можно вызвать функцию f_get_position() . Данная функция принимает в качестве параметров два указателя на переменные: широта latitude и долгота longitude . Вызов данной функции выглядит так:

Gps.f_get_position(&latitude, &longitude);

Исходный текст программы:

#include #include #include #define RXPIN 10 #define TXPIN 9 #define GPSBAUD 4800 #define RS 2 #define EN 3 #define D4 4 #define D5 5 #define D6 6 #define D7 7 TinyGPS gps; SoftwareSerial uart_gps(RXPIN, TXPIN); LiquidCrystal lcd(RS, EN, D4, D5, D6, D7); // Переменные int seconds; int timeoffset = 1; // Пользователь должен изменить единицу на соответствующий часовой пояс. В примере используем сдвиг на +1 час. // Объявление функций. void getgps(TinyGPS &gps); // Функция настройки - запускается только при включении void setup() { Serial.begin(115200); // Запуск последовательного интерфейса для отладки uart_gps.begin(GPSBAUD); // Запуск приемника UART для GPS lcd.begin(16,2); // Объявление LCD lcd.print(" GPS clock"); // Сообщение приветствия delay(1000); // Ждем одну секунду lcd.clear(); // Очистить LCD } // Цикл главной программы - запущен всегда void loop() { while(uart_gps.available()) { int c = uart_gps.read(); if(gps.encode(c)) { getgps(gps); } } } /* * Данная функция получает данные от GPS модуля * и отображает их на LCD */ void getgps(TinyGPS &gps) { int year; float latitude, longitude; byte month, day, hour, minute, second, hundredths; gps.f_get_position(&latitude, &longitude); gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths); hour = hour + timeoffset; lcd.clear();//lcd.setCursor(0, 0); lcd.print("Time: "); if (hour <= 9) { lcd.print("0"); lcd.print(hour, DEC); } else { lcd.print(hour, DEC); } lcd.print(":"); if (minute <=9) { lcd.print("0"); lcd.print(minute, DEC); } else { lcd.print(minute, DEC); } lcd.print(":"); if (second <= 9) { lcd.print("0"); lcd.print(second, DEC); } else { lcd.print(second, DEC); } lcd.setCursor(0,1); lcd.print("Date: "); if (day <= 9) { lcd.print("0"); lcd.print(day, DEC); } else { lcd.print(day, DEC); } lcd.print("-"); if (month <= 9) { lcd.print(month, DEC); } else { lcd.print(month, DEC); } lcd.print("-"); lcd.print(year, DEC); delay(2000); lcd.clear(); lcd.print("Lat: "); lcd.print(latitude, DEC); lcd.setCursor(0,1); lcd.print("Lon: "); lcd.print(longitude, DEC); delay(2000); // Debugging purpose only. Serial.print(latitude, DEC); Serial.print(" - "); Serial.println(longitude, DEC); }

Сегодня мы сделаем GPS Tracker на основе Arduino MKR FOX 1200, который отправляет точный GPS-данные через сеть Sigfox.

Это становится еще актуальней для многих стран в связи усилением контроля за любыми ввозимыми техническими устройствами, а особенно связанными с GPS.

Шаг 1. Что нам пригодится

Набор деталей для этого урока не велик:

  • Arduino MKR Fox 1200 × 1
  • Модуль GPS (на выбор, но мы использовали реплику ublox NEO6m (ATGM332D) × 1
  • Транзистор общего назначения NPN (мы использовали BC548) × 1
  • Резистор 1 кОм × 1

Шаг 2. Информация о проекте

Трекер использует GPS-модуль ATGM332, чтобы получить GPS-положение с большей точностью, чем услуги определения местоположения, предоставляемые Sigfox. Затем данные позиции отправляются как «строка» через сеть Sigfox и, наконец, доставляются по электронной почте.

Arduino MKR FOX 1200

Плата похожа на Arduino Zero, которая основана на SAM D21 и включает модуль ATA8520 Sigfox. Это плата с низким энергопотреблением, которая поставляется вместе с платой с бесплатной подпиской на один год в сеть Sigfox (до 140 сообщений в день), а также бесплатным доступом к службе геолокации Spot"it .

GPS-модуль ATGM332

Этот недорогой маломощный GPS-модуль очень хорошо подходит для Arduino MKR FOX 1200, поскольку он работает только с 2,7 В (номинальный 3,3 В).

Первоначально должен был быть куплен модуль NEO6m2, который имеет режим ожидания, но пришлось использовать NEO6. Фактически это был модуль ATGM332. В результате у него не было режима ожидания, поэтому нужно было использовать транзистор для включения модуля GPS, когда это необходимо, и выключить его, чтобы сэкономить аккумулятор. Наша цель - иметь информацию о местоположении довольно редко, то есть 4 сообщения в час, поскольку Sigfox позволяет только 140 сообщений в день.

Мы используем библиотеку TinyGPS (https://github.com/mikalhart/TinyGPS) для декодирования кадров GPS.

Транзисторный переключатель

Нужно было включить и выключить GPS, когда это необходимо. Модули реле слишком громоздки и мощны, если нужно только переключить нагрузку 3 В и несколько миллиампер. Кроме того, для большинства модулей реле требуется 5 В. Таким образом, транзистор будет лучшим решением. Кроме того, MKR FOX 1200 обеспечивает только 7 мА на пине ввода/вывода.

Подойдет транзистор BC548 NPN. Когда нулевой сигнал подается на базу транзистора, он выключается, действуя как открытый выключатель, и ток коллектора не течет. При положительном сигнале, подаваемом на базу транзистора, он становится «включенным», действующим как замкнутый переключатель, и максимальный ток цепи протекает через устройство.

Шаг 3. Схема соединения

Единственным источником питания являются две 1,5-вольтовых батареи AA, которые питают Arduino MKR FOX 1200. Модуль GPS получает питание от платы Arduino.

Arduino MKR FOX 1200 взаимодействует с модулем GPS, используя второй последовательный порт через контакты 13 и 14, называемые Serial1 в коде. Выход TX-данных модуля GPS подключается к последовательному входу данных (контакт 13) платы Arduino.

Кроме того, плата Arduino использует PIN2 для включения и выключения модуля GPS, как объясняется выше.

Шаг 4. Код проекта

Код нашего проекта вы можете скачать или скопировать ниже:

#include #include #include //incluimos TinyGPS #define WAITING_TIME 15 #define GPS_PIN 2 #define GPS_INFO_BUFFER_SIZE 128 bool debug = false; TinyGPS gps;//GPS Object //GPS data variables int year; byte month, day, hour, minute, second, hundredths; unsigned long chars; unsigned short sentences, failed_checksum; char GPS_info_char; char GPS_info_buffer; unsigned int received_char; bool message_started = false; int i = 0; // GPS coordinate structure, 12 bytes size on 32 bits platforms struct gpscoord { float a_latitude; // 4 bytes float a_longitude; // 4 bytes float a_altitude; // 4 bytes }; float latitude = 0.0f; float longitude = 0.0f; float altitud = 0; //////////////// Waiting function ////////////////// void Wait(int m, bool s) { //m minutes to wait //s slow led pulses if (debug) { Serial.print("Waiting: "); Serial.print(m); Serial.println(" min."); } digitalWrite(LED_BUILTIN, LOW); if (s) { int seg = m * 30; for (int i = 0; i < seg; i++) { digitalWrite(LED_BUILTIN, HIGH); //LED on delay(1000); digitalWrite(LED_BUILTIN, LOW); //LED off delay(1000); } } else { int seg = m * 15; for (int i = 0; i < seg; i++) { digitalWrite(LED_BUILTIN, HIGH); //LED on delay(1000); digitalWrite(LED_BUILTIN, LOW); //LED off delay(3000); } } } /////////////////// Sigfox Send Data function //////////////// void SendSigfox(String data) { if (debug) { Serial.print("Sending: "); Serial.println(data); if (data.length() > 12) { Serial.println("Message too long, only first 12 bytes will be sent"); } } // Remove EOL //data.trim(); // Start the module SigFox.begin(); // Wait at least 30mS after first configuration (100mS before) delay(100); // Clears all pending interrupts SigFox.status(); delay(1); if (debug) SigFox.debug(); delay(100); SigFox.beginPacket(); SigFox.print(data); if (debug) { int ret = SigFox.endPacket(true); // send buffer to SIGFOX network and wait for a response if (ret > 0) { Serial.println("No transmission"); } else { Serial.println("Transmission ok"); } Serial.println(SigFox.status(SIGFOX)); Serial.println(SigFox.status(ATMEL)); if (SigFox.parsePacket()) { Serial.println("Response from server:"); while (SigFox.available()) { Serial.print("0x"); Serial.println(SigFox.read(), HEX); } } else { Serial.println("Could not get any response from the server"); Serial.println("Check the SigFox coverage in your area"); Serial.println("If you are indoor, check the 20dB coverage or move near a window"); } Serial.println(); } else { SigFox.endPacket(); } SigFox.end(); } ////////////////// Convert GPS function ////////////////// /* Converts GPS float data to Char data */ String ConvertGPSdata(const void* data, uint8_t len) { uint8_t* bytes = (uint8_t*)data; String cadena ; if (debug) { Serial.print("Length: "); Serial.println(len); } for (uint8_t i = len - 1; i < len; --i) { if (bytes[i] < 12) { cadena.concat(byte(0)); // Not tested } cadena.concat(char(bytes[i])); if (debug) Serial.print(bytes[i], HEX); } if (debug) { Serial.println(""); Serial.print("String to send: "); Serial.println(cadena); } return cadena; } ////////////////////////// Get GPS position function///////////////////// String GetGPSpositon() { int messages_count = 0; String pos; if (debug) Serial.println("GPS ON"); digitalWrite(GPS_PIN, HIGH); //Turn GPS on Wait(1, false); while (messages_count < 5000) { while (Serial1.available()) { int GPS_info_char = Serial1.read(); if (GPS_info_char == "$") messages_count ++; // start of message. Counting messages. if (debug) { if (GPS_info_char == "$") { // start of message message_started = true; received_char = 0; } else if (GPS_info_char == "*") { // end of message for (i = 0; i < received_char; i++) { Serial.write(GPS_info_buffer[i]); // writes the message to the PC once it has been completely received } Serial.println(); message_started = false; // ready for the new message } else if (message_started == true) { // the message is already started and I got a new character if (received_char <= GPS_INFO_BUFFER_SIZE) { // to avoid buffer overflow GPS_info_buffer = GPS_info_char; received_char++; } else { // resets everything (overflow happened) message_started = false; received_char = 0; } } } if (gps.encode(GPS_info_char)) { gps.f_get_position(&latitude, &longitude); altitud = gps.altitude() / 100; // Store coordinates into dedicated structure gpscoord coords = {altitud, longitude, latitude}; gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths); if (debug) { Serial.println(); Serial.println(); Serial.print("Latitud/Longitud: "); Serial.print(latitude, 5); Serial.print(", "); Serial.println(longitude, 5); Serial.println(); Serial.print("Fecha: "); Serial.print(day, DEC); Serial.print("/"); Serial.print(month, DEC); Serial.print("/"); Serial.print(year); Serial.print(" Hora: "); Serial.print(hour, DEC); Serial.print(":"); Serial.print(minute, DEC); Serial.print(":"); Serial.print(second, DEC); Serial.print("."); Serial.println(hundredths, DEC); Serial.print("Altitud (metros): "); Serial.println(gps.f_altitude()); Serial.print("Rumbo (grados): "); Serial.println(gps.f_course()); Serial.print("Velocidad(kmph): "); Serial.println(gps.f_speed_kmph()); Serial.print("Satelites: "); Serial.println(gps.satellites()); Serial.println(); } gps.stats(&chars, &sentences, &failed_checksum); if (debug) Serial.println("GPS turned off"); digitalWrite(GPS_PIN, LOW); //GPS turned off pos = ConvertGPSdata(&coords, sizeof(gpscoord)); //Send data return pos; } } } pos = "No Signal"; } //////////////////SETUP/////////////////// void setup() { if (debug) { Serial.begin(9600); while (!Serial) {}// wait for serial port to connect. Needed for native USB port only Serial.println("Serial Connected"); } //Serial1 pins 13-14 for 3.3V connection to GPS. Serial1.begin(9600); while (!Serial1) {} if (debug) { Serial.println("GPS Connected"); } pinMode(GPS_PIN, OUTPUT); //pin de interruptor del GPS if (!SigFox.begin()) { Serial.println("Shield error or not present!"); return; } // Enable debug led and disable automatic deep sleep if (debug) { SigFox.debug(); } else { SigFox.end(); // Send the module to the deepest sleep } } //////////////////////LOOP//////////////////////// void loop() { String position_data; position_data = GetGPSpositon(); SendSigfox(position_data); Wait(WAITING_TIME, false); }

Шаг 5. Отправка информации GPS через Sigfox

Мы хотел отправить информацию GPS с использованием данных типа float, но когда мы попытались, то всегда получали нулевые значения.

Поиск в Интернете привел на этот проект на GitHub - https://github.com/nicolsc/SmartEverything_SigFox_GPS от Николя Лискони. Он использует AT-команды для отправки любого типа данных и конвертирует "float" в "hex". Тем не менее у Arduino MKR FOX 1200 нет режима AT, и мы не смогли заставить её работать.

Было сделано несколько десятков тестов и, изменив код Николя, был найден способ отправить «строку», которая была проанализирована платформой Sigfox «float: 32», и ее можно было бы использовать напрямую без какого-либо преобразования.

Данные Sigfox ограничены 12 байтами. Данные, которые отправляются в сеть SigFox:

  • Широта, float: 32 типа (float:32type), 4 байта.
  • Долгота, float: 32 типа (float:32type), 4 байта.
  • Высота, float: 32 типа (float:32type), 4 байта.

Шаг 6. Конфигурация обратного вызова Sigfox

Конфигурация пользовательского обратного вызова Sigfox:

Lat::float:32lng::float:32 alt::float:32

Вы получите электронное письмо:

Чтобы легко видеть позицию, мы включили URL-адрес в Карты Google, используя полученную информацию:

И, наконец, результат работы нашего Arduino GPS-трекера:

На этом всё, желаю вам отличных проектов!

Данные сохраняются в электронную таблицу dataGPS.csv , формат которой соответствует требованиям сервиса Google My Maps .

    Язык программирования: Arduino (C++)

Видеоинструкция

Что потребуется

Как собрать

gps-tracker.ino // библиотека для работы с устройствами по SPI #include // библиотека для работы с SD-картой #include // библиотека для работы с GPS устройством #include // создаём объект класса GPS и передаём в него объект Serial1 GPS gps(Serial1) ; // пин светодиода #define LED_PIN A0 // пин кнопки #define BUTTON_PIN 13 // пин CS micro-sd карты #define CHIP_SELECT_PIN 9 // интервал времени записи данных на карту #define INTERVAL 5000 // задаём размер массива для времени, даты, широты и долготы #define MAX_SIZE_MASS 16 // массив для хранения текущего времени char time [ MAX_SIZE_MASS] ; // состояние записи bool stateRec = false ; // запоминает текущее время long startMillis = millis() ; void setup() { // открываем последовательный порт для мониторинга действий в программе Serial.begin (115200 ) ; // ждём, пока не откроется монитор последовательного порта // для того, чтобы отследить все события в программе // while (!Serial) { // } Serial.print ("Serial init OK\r \n " ) ; // открываем Serial-соединение с GPS-модулем Serial1.begin (115200 ) ; // устанавливаем светодиод в режим выхода pinMode(LED_PIN, OUTPUT) ; // устанавливаем кнопку в режим входа pinMode(BUTTON_PIN, INPUT_PULLUP) ; // выводим информацию об инициализации в Serial-порт Serial.println ("Initializing SD card..." ) ; // инициализируем SD-карту while (! SD.begin (CHIP_SELECT_PIN) ) { Serial.println ("Card failed, or not present" ) ; delay(1000 ) ; } // выводим информацию в Serial-порт Serial.println ("Card initialized" ) ; // создаём объект dataFile класса File для работы с файлами File dataFile = SD.open ("dataGPS.csv" , FILE_WRITE) ; // если файл существует if (dataFile) { // записываем название будущих данных на карту памяти dataFile.println ("Time, Coordinates, Speed" ) ; // закрываем файл dataFile.close () ; Serial.println ("Save OK" ) ; } else { Serial.println ("Error opening test.csv" ) ; } } void loop() { // Фиксируем нажатие кнопки if (! digitalRead(BUTTON_PIN) ) { // меняем состояние «запись» / «не запись» на карту памяти stateRec = ! stateRec; // меняем состояние светодиода индикации digitalWrite(LED_PIN, stateRec) ; } // если пришли данные с gps-модуля if (gps.available () ) { // считываем данные и парсим gps.readParsing () ; // проверяем состояние GPS-модуля switch (gps.getState () ) { // всё OK case GPS_OK: Serial.println ("GPS is OK" ) ; // если прошёл заданный интервал времени if (millis() - startMillis > INTERVAL && stateRec) { // сохраняем данные на карту памяти saveSD() ; // запоминаем текущее время startMillis = millis() ; } break ; // ошибка данных case GPS_ERROR_DATA: Serial.println ("GPS error data" ) ; break ; // нет соединение со спутниками case GPS_ERROR_SAT: Serial.println ("GPS no connect to satellites" ) ; break ; } } } // функция сохарение данных на карту памяти void saveSD() { File dataFile = SD.open ("dataGPS.csv" , FILE_WRITE) ; // если файл существует и открылся if (dataFile) { // считывает текущее время gps.getTime (time , MAX_SIZE_MASS) ; // записываем время на карту памяти dataFile.print ("\" " ) ; dataFile.print (time ) ; dataFile.print ("\" " ) ; dataFile.print ("," ) ; dataFile.print ("\" " ) ; // считываем и записывае координаты широты и долготы на карту памяти dataFile.print (gps.getLatitudeBase10 () , 6 ) ; dataFile.print ("," ) ; dataFile.print (gps.getLongitudeBase10 () , 6 ) ; dataFile.print ("\" " ) ; dataFile.print ("," ) ; dataFile.print (gps.getSpeedKm () ) ; dataFile.println ("km/h" ) ; dataFile.close () ; Serial.println ("Save OK" ) ; } else { Serial.println ("Error opening test.csv" ) ; } }

Добрый день (опционально вечер/ночь).

Сегодня будет обзор на GPS приемник и его применение на практике.


ПРЕДИСЛОВИЕ

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

Обзоров на этот GPS приемник было, из самых обширных, немного - штуки 4, один из них реально был хорош, остальные так, описывали в целом. Сильно много повторяться не буду.

Как обычно предупреждение:

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

Внешний вид

Размеры данного модуля не большие 35 х 24 мм, и он сможет найти свое место не только в носимой электронике, но и в RC - аппаратах.

В комплекте идет пассивная антенна:

При желании всегда можно заменить активной или изготовить самому, по этой методике:

На сегодняшний день модуль не является устаревшей моделью, и активно используется, + имеется поддержка производителя .

На рисунке ниже я показал, какие линии куда подключать, что бы GPS определился в компьютере:

Выглядит примерно так:

Затем устанавливаем приложение U-center, ссылку давал выше, и выбираем порт:

По умолчанию общаемся на 9600 бод.

Вот в целом работает, все что поймал в помещении:

Подключение модуля к Arduino

Подготовим программатор для прошивки:

Затем в Нано зашиваем этот скетч:

Дополнительная информация

// ArduinoISP // Copyright © 2008-2011 Randall Bohn // If you require a license, see // http://www.opensource.org/licenses/bsd-license.php // // This sketch turns the Arduino into a AVRISP using the following Arduino pins: // // Pin 10 is used to reset the target microcontroller. // // By default, the hardware SPI pins MISO, MOSI and SCK are used to communicate // with the target. On all Arduinos, these pins can be found // on the ICSP/SPI header: // // MISO °. . 5V (!) Avoid this pin on Due, Zero... // SCK . . MOSI // . . GND // // On some Arduinos (Uno,...), pins MOSI, MISO and SCK are the same pins as // digital pin 11, 12 and 13, respectively. That is why many tutorials instruct // you to hook up the target to these pins. If you find this wiring more // practical, have a define USE_OLD_STYLE_WIRING. This will work even when not // using an Uno. (On an Uno this is not needed). // // Alternatively you can use any other digital pin by configuring // software ("BitBanged") SPI and having appropriate defines for PIN_MOSI, // PIN_MISO and PIN_SCK. // // IMPORTANT: When using an Arduino that is not 5V tolerant (Due, Zero, ...) as // the programmer, make sure to not expose any of the programmer"s pins to 5V. // A simple way to accomplish this is to power the complete system (programmer // and target) at 3V3. // // Put an LED (with resistor) on the following pins: // 9: Heartbeat - shows the programmer is running // 8: Error - Lights up if something goes wrong (use red if that makes sense) // 7: Programming - In communication with the slave // #include "Arduino.h" #undef SERIAL #define PROG_FLICKER true // Configure SPI clock (in Hz). // E.g. for an ATtiny @ 128 kHz: the datasheet states that both the high and low // SPI clock pulse must be > 2 CPU cycles, so take 3 cycles i.e. divide target // f_cpu by 6: // #define SPI_CLOCK (128000/6) // // A clock slow enough for an ATtiny85 @ 1 MHz, is a reasonable default: #define SPI_CLOCK (1000000/6) // Select hardware or software SPI, depending on SPI clock. // Currently only for AVR, for other architectures (Due, Zero,...), hardware SPI // is probably too fast anyway. #if defined(ARDUINO_ARCH_AVR) #if SPI_CLOCK > (F_CPU / 128) #define USE_HARDWARE_SPI #endif #endif // Configure which pins to use: // The standard pin configuration. #ifndef ARDUINO_HOODLOADER2 #define RESET 10 // Use pin 10 to reset the target rather than SS #define LED_HB 9 #define LED_ERR 8 #define LED_PMODE 7 // Uncomment following line to use the old Uno style wiring // (using pin 11, 12 and 13 instead of the SPI header) on Leonardo, Due... // #define USE_OLD_STYLE_WIRING #ifdef USE_OLD_STYLE_WIRING #define PIN_MOSI 11 #define PIN_MISO 12 #define PIN_SCK 13 #endif // HOODLOADER2 means running sketches on the ATmega16U2 serial converter chips // on Uno or Mega boards. We must use pins that are broken out: #else #define RESET 4 #define LED_HB 7 #define LED_ERR 6 #define LED_PMODE 5 #endif // By default, use hardware SPI pins: #ifndef PIN_MOSI #define PIN_MOSI MOSI #endif #ifndef PIN_MISO #define PIN_MISO MISO #endif #ifndef PIN_SCK #define PIN_SCK SCK #endif // Force bitbanged SPI if not using the hardware SPI pins: #if (PIN_MISO != MISO) || (PIN_MOSI != MOSI) || (PIN_SCK != SCK) #undef USE_HARDWARE_SPI #endif // Configure the serial port to use. // // Prefer the USB virtual serial port (aka. native USB port), if the Arduino has one: // - it does not autoreset (except for the magic baud rate of 1200). // - it is more reliable because of USB handshaking. // // Leonardo and similar have an USB virtual serial port: "Serial". // Due and Zero have an USB virtual serial port: "SerialUSB". // // On the Due and Zero, "Serial" can be used too, provided you disable autoreset. // To use "Serial": #define SERIAL Serial #ifdef SERIAL_PORT_USBVIRTUAL #define SERIAL SERIAL_PORT_USBVIRTUAL #else #define SERIAL Serial #endif // Configure the baud rate: #define BAUDRATE 19200 // #define BAUDRATE 115200 // #define BAUDRATE 1000000 #define HWVER 2 #define SWMAJ 1 #define SWMIN 18 // STK Definitions #define STK_OK 0x10 #define STK_FAILED 0x11 #define STK_UNKNOWN 0x12 #define STK_INSYNC 0x14 #define STK_NOSYNC 0x15 #define CRC_EOP 0x20 //ok it is a space... void pulse(int pin, int times); #ifdef USE_HARDWARE_SPI #include "SPI.h" #else #define SPI_MODE0 0x00 class SPISettings { public: // clock is in Hz SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) : clock(clock) { (void) bitOrder; (void) dataMode; }; private: uint32_t clock; friend class BitBangedSPI; }; class BitBangedSPI { public: void begin() { digitalWrite(PIN_SCK, LOW); digitalWrite(PIN_MOSI, LOW); pinMode(PIN_SCK, OUTPUT); pinMode(PIN_MOSI, OUTPUT); pinMode(PIN_MISO, INPUT); } void beginTransaction(SPISettings settings) { pulseWidth = (500000 + settings.clock - 1) / settings.clock; if (pulseWidth == 0) pulseWidth = 1; } void end() {} uint8_t transfer (uint8_t b) { for (unsigned int i = 0; i < 8; ++i) { digitalWrite(PIN_MOSI, (b & 0x80) ? HIGH: LOW); digitalWrite(PIN_SCK, HIGH); delayMicroseconds(pulseWidth); b = (b << 1) | digitalRead(PIN_MISO); digitalWrite(PIN_SCK, LOW); // slow pulse delayMicroseconds(pulseWidth); } return b; } private: unsigned long pulseWidth; // in microseconds }; static BitBangedSPI SPI; #endif void setup() { SERIAL.begin(BAUDRATE); pinMode(LED_PMODE, OUTPUT); pulse(LED_PMODE, 2); pinMode(LED_ERR, OUTPUT); pulse(LED_ERR, 2); pinMode(LED_HB, OUTPUT); pulse(LED_HB, 2); } int error = 0; int pmode = 0; // address for reading and writing, set by "U" command unsigned int here; uint8_t buff; // global block storage #define beget16(addr) (*addr * 256 + *(addr+1)) typedef struct param { uint8_t devicecode; uint8_t revision; uint8_t progtype; uint8_t parmode; uint8_t polling; uint8_t selftimed; uint8_t lockbytes; uint8_t fusebytes; uint8_t flashpoll; uint16_t eeprompoll; uint16_t pagesize; uint16_t eepromsize; uint32_t flashsize; } parameter; parameter param; // this provides a heartbeat on pin 9, so you can tell the software is running. uint8_t hbval = 128; int8_t hbdelta = 8; void heartbeat() { static unsigned long last_time = 0; unsigned long now = millis(); if ((now - last_time) < 40) return; last_time = now; if (hbval > 192) hbdelta = -hbdelta; if (hbval < 32) hbdelta = -hbdelta; hbval += hbdelta; analogWrite(LED_HB, hbval); } static bool rst_active_high; void reset_target(bool reset) { digitalWrite(RESET, ((reset && rst_active_high) || (!reset && !rst_active_high)) ? HIGH: LOW); } void loop(void) { // is pmode active? if (pmode) { digitalWrite(LED_PMODE, HIGH); } else { digitalWrite(LED_PMODE, LOW); } // is there an error? if (error) { digitalWrite(LED_ERR, HIGH); } else { digitalWrite(LED_ERR, LOW); } // light the heartbeat LED heartbeat(); if (SERIAL.available()) { avrisp(); } } uint8_t getch() { while (!SERIAL.available()); return SERIAL.read(); } void fill(int n) { for (int x = 0; x < n; x++) { buff[x] = getch(); } } #define PTIME 30 void pulse(int pin, int times) { do { digitalWrite(pin, HIGH); delay(PTIME); digitalWrite(pin, LOW); delay(PTIME); } while (times--); } void prog_lamp(int state) { if (PROG_FLICKER) { digitalWrite(LED_PMODE, state); } } uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { SPI.transfer(a); SPI.transfer(b); SPI.transfer©; return SPI.transfer(d); } void empty_reply() { if (CRC_EOP == getch()) { SERIAL.print((char)STK_INSYNC); SERIAL.print((char)STK_OK); } else { error++; SERIAL.print((char)STK_NOSYNC); } } void breply(uint8_t b) { if (CRC_EOP == getch()) { SERIAL.print((char)STK_INSYNC); SERIAL.print((char)b); SERIAL.print((char)STK_OK); } else { error++; SERIAL.print((char)STK_NOSYNC); } } void get_version(uint8_t c) { switch © { case 0x80: breply(HWVER); break; case 0x81: breply(SWMAJ); break; case 0x82: breply(SWMIN); break; case 0x93: breply("S"); // serial programmer break; default: breply(0); } } void set_parameters() { // call this after reading parameter packet into buff param.devicecode = buff; param.revision = buff; param.progtype = buff; param.parmode = buff; param.polling = buff; param.selftimed = buff; param.lockbytes = buff; param.fusebytes = buff; param.flashpoll = buff; // ignore buff (= buff) // following are 16 bits (big endian) param.eeprompoll = beget16(&buff); param.pagesize = beget16(&buff); param.eepromsize = beget16(&buff); // 32 bits flashsize (big endian) param.flashsize = buff * 0x01000000 + buff * 0x00010000 + buff * 0x00000100 + buff; // AVR devices have active low reset, AT89Sx are active high rst_active_high = (param.devicecode >= 0xe0); } void start_pmode() { // Reset target before driving PIN_SCK or PIN_MOSI // SPI.begin() will configure SS as output, so SPI master mode is selected. // We have defined RESET as pin 10, which for many Arduinos is not the SS pin. // So we have to configure RESET as output here, // (reset_target() first sets the correct level) reset_target(true); pinMode(RESET, OUTPUT); SPI.begin(); SPI.beginTransaction(SPISettings(SPI_CLOCK, MSBFIRST, SPI_MODE0)); // See AVR datasheets, chapter "SERIAL_PRG Programming Algorithm": // Pulse RESET after PIN_SCK is low: digitalWrite(PIN_SCK, LOW); delay(20); // discharge PIN_SCK, value arbitrarily chosen reset_target(false); // Pulse must be minimum 2 target CPU clock cycles so 100 usec is ok for CPU // speeds above 20 KHz delayMicroseconds(100); reset_target(true); // Send the enable programming command: delay(50); // datasheet: must be > 20 msec spi_transaction(0xAC, 0x53, 0x00, 0x00); pmode = 1; } void end_pmode() { SPI.end(); // We"re about to take the target out of reset so configure SPI pins as input pinMode(PIN_MOSI, INPUT); pinMode(PIN_SCK, INPUT); reset_target(false); pinMode(RESET, INPUT); pmode = 0; } void universal() { uint8_t ch; fill(4); ch = spi_transaction(buff, buff, buff, buff); breply(ch); } void flash(uint8_t hilo, unsigned int addr, uint8_t data) { spi_transaction(0x40 + 8 * hilo, addr >> 8 & 0xFF, addr & 0xFF, data); } void commit(unsigned int addr) { if (PROG_FLICKER) { prog_lamp(LOW); } spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0); if (PROG_FLICKER) { delay(PTIME); prog_lamp(HIGH); } } unsigned int current_page() { if (param.pagesize == 32) { return here & 0xFFFFFFF0; } if (param.pagesize == 64) { return here & 0xFFFFFFE0; } if (param.pagesize == 128) { return here & 0xFFFFFFC0; } if (param.pagesize == 256) { return here & 0xFFFFFF80; } return here; } void write_flash(int length) { fill(length); if (CRC_EOP == getch()) { SERIAL.print((char) STK_INSYNC); SERIAL.print((char) write_flash_pages(length)); } else { error++; SERIAL.print((char) STK_NOSYNC); } } uint8_t write_flash_pages(int length) { int x = 0; unsigned int page = current_page(); while (x < length) { if (page != current_page()) { commit(page); page = current_page(); } flash(LOW, here, buff); flash(HIGH, here, buff); here++; } commit(page); return STK_OK; } #define EECHUNK (32) uint8_t write_eeprom(unsigned int length) { // here is a word address, get the byte address unsigned int start = here * 2; unsigned int remaining = length; if (length > param.eepromsize) { error++; return STK_FAILED; } while (remaining > EECHUNK) { write_eeprom_chunk(start, EECHUNK); start += EECHUNK; remaining -= EECHUNK; } write_eeprom_chunk(start, remaining); return STK_OK; } // write (length) bytes, (start) is a byte address uint8_t write_eeprom_chunk(unsigned int start, unsigned int length) { // this writes byte-by-byte, page writing may be faster (4 bytes at a time) fill(length); prog_lamp(LOW); for (unsigned int x = 0; x < length; x++) { unsigned int addr = start + x; spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]); delay(45); } prog_lamp(HIGH); return STK_OK; } void program_page() { char result = (char) STK_FAILED; unsigned int length = 256 * getch(); length += getch(); char memtype = getch(); // flash memory @here, (length) bytes if (memtype == "F") { write_flash(length); return; } if (memtype == "E") { result = (char)write_eeprom(length); if (CRC_EOP == getch()) { SERIAL.print((char) STK_INSYNC); SERIAL.print(result); } else { error++; SERIAL.print((char) STK_NOSYNC); } return; } SERIAL.print((char)STK_FAILED); return; } uint8_t flash_read(uint8_t hilo, unsigned int addr) { return spi_transaction(0x20 + hilo * 8, (addr >> 8) & 0xFF, addr & 0xFF, 0); } char flash_read_page(int length) { for (int x = 0; x < length; x += 2) { uint8_t low = flash_read(LOW, here); SERIAL.print((char) low); uint8_t high = flash_read(HIGH, here); SERIAL.print((char) high); here++; } return STK_OK; } char eeprom_read_page(int length) { // here again we have a word address int start = here * 2; for (int x = 0; x < length; x++) { int addr = start + x; uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF); SERIAL.print((char) ee); } return STK_OK; } void read_page() { char result = (char)STK_FAILED; int length = 256 * getch(); length += getch(); char memtype = getch(); if (CRC_EOP != getch()) { error++; SERIAL.print((char) STK_NOSYNC); return; } SERIAL.print((char) STK_INSYNC); if (memtype == "F") result = flash_read_page(length); if (memtype == "E") result = eeprom_read_page(length); SERIAL.print(result); } void read_signature() { if (CRC_EOP != getch()) { error++; SERIAL.print((char) STK_NOSYNC); return; } SERIAL.print((char) STK_INSYNC); uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00); SERIAL.print((char) high); uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00); SERIAL.print((char) middle); uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00); SERIAL.print((char) low); SERIAL.print((char) STK_OK); } ////////////////////////////////////////// ////////////////////////////////////////// //////////////////////////////////// //////////////////////////////////// void avrisp() { uint8_t ch = getch(); switch (ch) { case "0": // signon error = 0; empty_reply(); break; case "1": if (getch() == CRC_EOP) { SERIAL.print((char) STK_INSYNC); SERIAL.print("AVR ISP"); SERIAL.print((char) STK_OK); } else { error++; SERIAL.print((char) STK_NOSYNC); } break; case "A": get_version(getch()); break; case "B": fill(20); set_parameters(); empty_reply(); break; case "E": // extended parameters - ignore for now fill(5); empty_reply(); break; case "P": if (!pmode) start_pmode(); empty_reply(); break; case "U": // set address (word) here = getch(); here += 256 * getch(); empty_reply(); break; case 0x60: //STK_PROG_FLASH getch(); // low addr getch(); // high addr empty_reply(); break; case 0x61: //STK_PROG_DATA getch(); // data empty_reply(); break; case 0x64: //STK_PROG_PAGE program_page(); break; case 0x74: //STK_READ_PAGE "t" read_page(); break; case "V": //0x56 universal(); break; case "Q": //0x51 error = 0; end_pmode(); empty_reply(); break; case 0x75: //STK_READ_SIGN "u" read_signature(); break; // expecting a command, not CRC_EOP // this is how we can get back in sync case CRC_EOP: error++; SERIAL.print((char) STK_NOSYNC); break; // anything else we will return STK_UNKNOWN default: error++; if (CRC_EOP == getch()) SERIAL.print((char)STK_UNKNOWN); else SERIAL.print((char)STK_NOSYNC); } }

После этого выбираем Ваш контроллер Pro Mini, указываем программатор ArduinoISP и шьем контроллер, используя команду Скетч -> Загрузить через программатор и нажимаем кнопку Reset на Pro mini, пойдет прошивка контроллера (у меня проходит только со второй попытки, нужно набраться терпения):

Как выше говорил, я очень люблю ко всяким гаджетам подвязывать дисплеи, ну просто жуть как, поэтому данный «проект» мое желание не обошло стороной.

Что нам для всего этого потребуется:

В общем, собрал весь хлам, который валялся без дела:

1. SD card module, очень огромный, поэтому я старался как можно скорее избавится от него.

2. Дисплей на базе контроллера PCD8544, всем известный нокиа дисплей.

3. Карта памяти на 1Гб, с не популярным стандартом MiniSD, вообще был без идеи куда ее воткнуть, а хочется все пустить в дело, вот и пускай поработает на благо навигации.

4. Потребуется мозг, большой такой мозг Pro Mini на чипе 328P.

Как писал выше, будем шить через Arduino Nano с прошитым в нее загрузчиком.

Вообще я очень старался засунуть весь проект в нано, ну просто очень. Не получается, либо отказываемся от карты памяти, либо от дисплея.

5. Конечно же, сам модуль + антенна, как писал выше можно изготовить самому.

6. Ах да, чуть не забыл, потребуется еще корпус иначе, что за устройство без корпуса.

В качестве корпуса были закуплены, еще раз , но в серебряном виде, на пробу. Скажу так, мне абсолютно не понравился серебряный цвет, черный смотрится лучше.

Когда все комплектующие есть в наличии, можно все это подключить и запрограммировать.

Подключаем к Pro Mini по следующей схеме:

Дисплей:

RST - D6
CE - D7
DC - D5
DIN - D4
CLK - D3
VCC - 5V (опционально в моем случае, в остальных 3.3В)
Light - GND
GND - GND

Подсветка мне была не нужна, и я не стал ее подключать.

CS-D10
MOSI-D11
MISO-D12
SCK-D13
GND - GND
5V - VCC (опционально в моем случае, в некоторых при наличии преобразователя подключаем на 3.3В)

GPS модуль:

RX-D8
TX-D2
GND - GND
VCC-3.3 (3.3 это предел!)

Не забываем подключать антенну на модуль, питание я брал с Нано тк. была подключена для отладки, далее все будет переделано на аккумулятор.

Примерный вид:

Код прост и незамысловат, для использования Вам понадобится, пожалуй . Далее . Остальные являются встроенными. По коду, строка - time*0.000001+5, по сути я привел время в удобоваримый вид и добавил часовой пояс. Можно этого не делать и получать чистые результаты.

Ещё один нюанс по библиотеке дисплея заключается в следующем у дисплея, включая с нулевой строкой, всего влезет 6 строк. Что довольно мало, поэтому нужно сразу решать, какую информацию выводить, что-то придется выводить символами, экономя место. Дисплей перерисовывается каждую секунду, при этом обновляя и записывая информацию, поступающую со спутников.

При ошибке чтения файла или отсутствия доступа до карты SD будет выводиться сообщение SD- , в остальных случаях SD+ .

#include #include #include #include //CS-D10, MOSI-D11, MISO-D12, SCK-D13, GND - GND, 5V - VCC (опционально в моем случае, в некоторых при отсутствии преобразователя подключаем на 3.3В) File GPS_file; TinyGPS gps; SoftwareSerial gpsSerial(2, 8);//RX - 8 pin, TX - 2 pin static PCD8544 lcd; //RST - D6, CE - D7, DC - D5, DIN - D4, CLK - D3, VCC - 5V (опционально, при наличии преобразователя на 3.3В линии), Light - GND, GND - GND bool newdata = false; unsigned long start; long lat, lon; unsigned long time, date; void setup() { lcd.begin(84, 48); gpsSerial.begin(9600); Serial.begin(9600); pinMode(10, OUTPUT); if (!SD.begin(10)){ lcd.setCursor(0, 0); lcd.println("SD-"); return;} lcd.setCursor(0, 0); lcd.println("SD+"); GPS_file = SD.open("GPSLOG.txt", FILE_WRITE); if (GPS_file){ Serial.print("Writing to test.txt..."); GPS_file.print("LATITUDE"); GPS_file.print(","); GPS_file.print("LONGITUDE"); GPS_file.print(","); GPS_file.print("DATE"); GPS_file.print(","); GPS_file.print("TIME"); GPS_file.print(","); GPS_file.print("ALTITUDE"); GPS_file.println(); GPS_file.close(); Serial.println("done."); }else{ Serial.println("error opening test.txt"); } lcd.setCursor(0,3); lcd.print("ALT: "); lcd.setCursor(0,2); lcd.print("SPD: "); lcd.setCursor(0,4); lcd.print("LAT: "); lcd.setCursor(0,5); lcd.print("LON: "); } void loop() { if (millis() - start > 1000){ newdata = readgps(); if (newdata){ start = millis(); gps.get_position(&lat, &lon); gps.get_datetime(&date, &time); lcd.setCursor(50,1); lcd.print(date); lcd.setCursor(55,0); lcd.print(time*0.000001+5); lcd.setCursor(22, 4); lcd.print(lat); lcd.setCursor(22, 5); lcd.print(lon); lcd.setCursor(22, 2); lcd.print(gps.f_speed_kmph()); lcd.setCursor(22, 3); lcd.print(gps.f_altitude()); } } GPS_file = SD.open("GPSLOG.txt", FILE_WRITE); if(GPS_file){ GPS_file.print(lat); GPS_file.print(","); GPS_file.print(lon); GPS_file.print(","); GPS_file.print(date); GPS_file.print(","); GPS_file.print(time*0.000001+5); GPS_file.print(","); GPS_file.print(gps.f_altitude()); GPS_file.println(); GPS_file.close(); }else{ lcd.setCursor(0, 0); lcd.println("SD-"); } } bool readgps(){ while (gpsSerial.available()){ int b = gpsSerial.read(); if("\r" != b){ if (gps.encode(b)) return true;}} return false;}

После прошивки Вы увидите нечто подобное (в скетче вывод даты отредактирован к правому краю под временем):

С расположением элементов можно поиграться, был такой вариант, но понял, что усреднение координат выдает огромную погрешность и отказался.

В качестве элементов питания я использую LI-ion аккумулятор. Покупаю акб для экшн - камер оптом и использую их в своих поделках + ко всему всегда могут пригодиться для экшн - камеры, которой пользуюсь в походах. .

Используя макетную плату, собираем все воедино:

На корпус для карты памяти наклеил кусок изоленты, тк он соприкасается с контактами зарядника для батареи. Карту памяти прошиваем в FAT16.

Потом запускаем и проверяем, не забыв поставить выключатель:

Обработка результатов

Результаты представляются в виде текстового файла:

Разделитель колонок выставляем - запятая:

Далее можно загрузить все это дело в ПО Google Earth Pro, используя вкладку Файл -> Открыть , открываем наш файлик и выбираем столбцы, отвечающие за широту и долготу и получаем похожий трек (тк я был в одном месте, то получил россыпь точек):

Можно выбрать точку и отобразить все количество точек, которые ей соответсвуют:

Итог

В общем логер работает, писать трек можно, с последующим редактированием на карте. Так же в программном обеспечении от гугла, трек можно сохранить в более популярном формате, которые поддерживают другие карты.

Свое любопытство удовлетворил с лихвой.

Из минусов это маленькая антенна, порой холодный старт затягивается до 10 минут (зависит от того, насколько сильна облачность, время суток). Антенну конечно можно заменить, на самодельную, либо докупить, на али довольно много активных антенн.

Спасибо за потраченное время.

Обновление от 22.05.18

1. Заменил корпус и изготовил антенну из представленной мною ссылке. (Уменьшил время холодного старта, быстрее находит спутники, значительно быстрее.)

2. Вынес разъем дебага наружу (поигравшись, буду писать прошивку поинтереснее, выкладывать буду сюда же)

3. Для уменьшения занимаемого места, разобрал дисплей и подпаялся к нему.

Пока вид такой.

Планирую купить +129 Добавить в избранное Обзор понравился +170 +299