Arduino 通过OLED显示GPS接收信息

  • 内容
  • ....
  • 相关

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

OLED显示GPS数据
OLED显示GPS数据

当GPS未接入或未收到卫星信号时,屏幕显示一些等待信息,而当GPS完成接入并定位成功后,OLED屏幕将立即更新并显示卫星数量、经纬度、时间等信息。

OLED屏

本项目使用的是0.96寸OLED屏,四针 I2C 接口,支持 3.3V 和 5V 供电。 Arduino Uno的 SCL 和 SDA 接口默认在A5和A4。详见下图

OLED 0.96显示模块
OLED 0.96显示模块

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

ATGM332D 北斗定位模块

 ATGM332D  北斗定位模块
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(".");
  }
}