Arduino 通过OLED显示GPS接收信息
该项目基于Arduino UNO, 使用 I2C 协议的0.96寸OLED显示器显示串口GPS模块的经纬度和时间等信息。

当GPS未接入或未收到卫星信号时,屏幕显示一些等待信息,而当GPS完成接入并定位成功后,OLED屏幕将立即更新并显示卫星数量、经纬度、时间等信息。
OLED屏
本项目使用的是0.96寸OLED屏,四针 I2C 接口,支持 3.3V 和 5V 供电。 Arduino Uno的 SCL 和 SDA 接口默认在A5和A4。详见下图

该屏幕分辨率为12864,屏幕长边有128个LED,短边64个LED,定位时长边为X,短边为Y。单片机通过控制不同X和Y的坐标,实现不同显示功能。用于Arduino时显示库文件有 Adafruit_SSD1306 和 U8g2,本项目用到的显示库为U8g2。
ATGM332D 北斗定位模块

硬件特性:
模块供电3.3-5V
具备SMA 天线接口和IPEX 天线接口
板载E2PROM 可设置保存波特率等信息
板载XH414 充电电子,加速热启动搜星
支持A-GNSS
冷启动捕获灵敏度:-148dBm
跟踪灵敏度:-162dBm
定位精度:2.5 米(CEP50,开阔地)
首次定位时间:32 秒(也有可能是几分钟,要看具体环境而定)
低功耗:连续运行<25mA
内置天线检测及天线短路保护功能
板子尺寸24mm x 16.5mm
该模块同时支持GPS、北斗卫星系统,板载了一个蓝色LED,当LED 保持一定频率闪烁时证明定位成功,这时使用串口就可以查看原始接收数据了,模块的波特率默认是9600。本项目中会引用GPS支持库 NeoGPS。
该模块在树莓派上的使用测试,请移步:树莓派串口GPS测试
OLED显示GPS数据
项目中,我使用的库文件可能是最适合的GPS库和OLED显示库。用于GPS信号处理的是 NeoGPS ,用于OLED显示的是 U8g2 图形库,U8x8版本,因为只需要简单的显示文本, U8X8 会更快。还使用到了软串口库 Altsoftserial ,它和NeoGPS配合得很好。
安装这些库文件都很简单,可以通过Arduino IDE的“项目”—>”加载库”—>”管理库”菜单进行搜索安装,如国内网络原因导致下载失败,可到Github搜索下载zip文件后,通过 “项目”—>”加载库”—>”添加一个.zip库…”菜单进行支持库的安装。可参阅: 在Arduino项目中使用PS2游戏控制器 文中的操作完成。
有一点需要注意, 本项目支持查看跟踪到的卫星数(TKD),可用卫星数(AVL) 和 当前时间 (TME) ,要实现这几个参数的显示需要对对应的配置文件 NMEAGPS_cfg.h 进行一些小修改。具体操作也就是将原来被注释掉的语句去掉注释而已。找到需要修改的配置文件: C:\Users\#YourUserName#\Documents\Arduino\libraries\NeoGPS\src\NMEAGPS_cfg.h, 实际路径可通过Arduino IDE 的“文件”—>“首选项”中查看。 取消以下三条语句的注释(删除前面的//):
//#define NMEAGPS_PARSE_GSV //#define NMEAGPS_PARSE_SATELLITES //#define NMEAGPS_PARSE_SATELLITE_INFO
线路的连接很简单, 首先OLED至UNO的连接如下:
UNO -> OLED
5v -> VCC
GND -> GND
A4 -> SDA
A5 -> SCL
GPS至UNO的连接如下:
UNO -> GPS
3.3V -> VCC
GND -> GND
D8 -> RX
D9 -> TX (可不接)
可用代码
#include <NMEAGPS.h> #include "U8x8lib.h" //------------------- // The GPSport.h include file tries to choose a default serial port // for the GPS device. If you know which serial port you want to use, // edit the GPSport.h file.FOR UNO D8-RX,D9-TX #include <GPSport.h> //------------------- // This object parses received characters // into the gps.fix() data structure static NMEAGPS gps; //------------------------------------------------------------ // Define a set of GPS fix information. It will // hold on to the various pieces as they are received from // an RMC sentence. It can be used anywhere in your sketch. static gps_fix fix; // the OLED used U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); uint32_t timer; bool screencleared = false; void setup() { gpsPort.begin( 9600 ); u8x8.begin(); u8x8.setFont(u8x8_font_chroma48medium8_r); // Start up screen on OLED u8x8.fillDisplay(); delay(1000); for (uint8_t r = 0; r < u8x8.getRows(); r++ ) { u8x8.clearLine(r); delay(100); } delay(100); u8x8.println("GPS"); delay(500); u8x8.println("Signal"); delay(500); u8x8.print("Waiting"); timer = millis(); } //---------------------------------------------------------------- // This function gets called about once per second, during the GPS // quiet time. static void doSomeWork() { // timer = millis(); // reset the timer //---------------------------------------------------------------- // This section is run before a fix is made to show sat info (Available, Tracked, Time) // Count how satellites are being received for each GNSS int totalSatellites, trackedSatellites; totalSatellites = gps.sat_count; for (uint8_t i = 0; i < totalSatellites; i++) { if (gps.satellites[i].tracked) { trackedSatellites++; } } u8x8.inverse(); u8x8.drawString(0, 6, "TKD"); u8x8.drawString(5, 6, "AVL"); u8x8.drawString(10, 6, "TME"); u8x8.noInverse(); enum {BufSizeTracked = 3}; //Space for 2 characters + NULL char trackedchar[BufSizeTracked]; snprintf (trackedchar, BufSizeTracked, "%d", trackedSatellites); u8x8.drawString(0, 7, " "); u8x8.drawString(0, 7, trackedchar); enum {BufSizeTotal = 3}; char availchar[BufSizeTotal]; snprintf (availchar, BufSizeTotal, "%d", totalSatellites); u8x8.drawString(5, 7, " "); u8x8.drawString(5, 7, availchar); if (fix.valid.time) { enum {BufSizeTime = 3}; int hour = fix.dateTime.hours + 8;//中国时区设置需要+8 int minute = fix.dateTime.minutes; char hourchar[BufSizeTime]; char minutechar[BufSizeTime]; snprintf (hourchar, BufSizeTime, "%d", hour); snprintf (minutechar, BufSizeTime, "%d", minute); if ( hour < 10 ) { snprintf (hourchar, BufSizeTime, "%02d", hour); } if ( minute < 10 ) { snprintf (minutechar, BufSizeTime, "%02d", minute); } u8x8.drawString(10, 7, hourchar); u8x8.drawString(12, 7, ":"); u8x8.drawString(13, 7, minutechar); } //---------------------------------------------------------------- // Once the location is found the top part of the screen is cleared and the fix data is shown if (fix.valid.location) { if (!screencleared) // do once { int r; for ( int r = 0; r < 5; r++ ) { u8x8.clearLine(r); } screencleared = true; } u8x8.inverse(); u8x8.drawString(0, 0, "FIX"); u8x8.drawString(0, 2, "LAT"); u8x8.drawString(0, 4, "LNG"); u8x8.noInverse(); enum {BufSize = 3}; // Space for 2 digits char satchar2[BufSize]; snprintf (satchar2, BufSize, "%d", fix.satellites); u8x8.drawString(4, 0, " "); u8x8.drawString(4, 0, satchar2); char latchar[10]; // Buffer big enough for 9-character float dtostrf(fix.latitude(), 3, 7, latchar); // Leave room for large numbers u8x8.drawString(4, 2, latchar); char longchar[10]; dtostrf(fix.longitude(), 3, 7, longchar); u8x8.drawString(4, 4, longchar); } } // This is the main GPS parsing loop. static void GPSloop() { while (gps.available( gpsPort )) { fix = gps.read(); doSomeWork(); } } void loop() { GPSloop(); // until we get a fix, print a dot every 5 seconds if (millis() - timer > 5000 && !screencleared) { timer = millis(); // reset the timer u8x8.print("."); } }