少し前に、Ali-ExpressでATGM336H(GPS+BDS)モジュールなるものを見つけたので買っておいた。532円だった。GPSモジュールがこの値段なら、かなり安いような気がする。
ATGM336Hは複数の衛星測位システム(GNSS)に対応しており、アメリカの「GPS」だけでなく、日本の「みちびき」や中国の「北斗(BeiDou)」など、世界中の主要な衛星信号を補足可能です。 [1, 2, 3]
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <TinyGPS++.h>
// --- LovyanGFXのRP2040-ZERO用カスタム設定 ---
class LGFX : public lgfx::LGFX_Device {
lgfx::Panel_ST7789 _panel_instance;
lgfx::Bus_SPI _bus_instance;
public:
LGFX(void) {
{ // SPIバスの設定
auto cfg = _bus_instance.config();
cfg.spi_host = 0; // SPI0を使用
cfg.spi_mode = 0;
cfg.freq_write = 40000000; // 40MHz
cfg.freq_read = 16000000;
cfg.pin_sclk = 2; // GP2
cfg.pin_mosi = 3; // GP3
cfg.pin_miso = -1;
cfg.pin_dc = 5; // GP5
_bus_instance.config(cfg);
_panel_instance.setBus(&_bus_instance);
}
{ // パネルの設定
auto cfg = _panel_instance.config();
cfg.pin_cs = 6; // GP6
cfg.pin_rst = 4; // GP4
cfg.pin_busy = -1;
cfg.panel_width = 240;
cfg.panel_height = 320;
cfg.offset_x = 0;
cfg.offset_y = 0;
cfg.offset_rotation = 0;
cfg.dummy_read_pixel = 8;
cfg.readable = true;
cfg.invert = true; // 色が反転する場合はfalseにする
cfg.rgb_order = false;
_panel_instance.config(cfg);
}
setPanel(&_panel_instance);
}
};
LGFX lcd;
TinyGPSPlus gps;
// 各衛星システムの捕捉(可視)数保持用変数
int sats_gps = 0;
int sats_qzss = 0; // みちびき
int sats_beidou = 0;
int sats_glonass = 0;
int sats_galileo = 0;
String nmea_buffer = "";
// NMEA文字列から特定のカンマ位置のデータを切り出す関数
String getArgument(String data, char separator, int index) {
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
// 生のNMEAデータを解析してシステム別の衛星数を抽出
void parseNMEA(char c) {
if (c == '\n' || c == '\r') {
if (nmea_buffer.startsWith("$") && nmea_buffer.indexOf("GSV") > 0) {
// GSV文の4番目の要素(インデックス3)がそのシステムの可視衛星数
String sats_str = getArgument(nmea_buffer, ',', 3);
int count = sats_str.toInt();
if (nmea_buffer.startsWith("$GP")) sats_gps = count;
else if (nmea_buffer.startsWith("$QZ")) sats_qzss = count;
else if (nmea_buffer.startsWith("$BD") || nmea_buffer.startsWith("$GB")) sats_beidou = count;
else if (nmea_buffer.startsWith("$GL")) sats_glonass = count;
else if (nmea_buffer.startsWith("$GA")) sats_galileo = count;
}
nmea_buffer = "";
} else if (nmea_buffer.length() < 100) {
nmea_buffer += c;
}
}
void setup() {
// LovyanGFX初期化
lcd.init();
lcd.setRotation(1); // 横向き(320x240)
lcd.fillScreen(TFT_BLACK);
// GPSシリアル初期化 (UART0: GP0=TX, GP1=RX)
Serial1.setTX(0);
Serial1.setRX(1);
Serial1.begin(9600);
// 固定タイトルの描画
lcd.setFont(&fonts::lgfxJapanGothic_20);
lcd.setTextSize(1);
lcd.setTextColor(TFT_CYAN);
lcd.drawString("=== GNSS MONITOR ===", 10, 0);
}
void loop() {
// GPSからデータを受信
while (Serial1.available() > 0) {
char c = Serial1.read();
gps.encode(c); // TinyGPS++で位置・高度をパース
parseNMEA(c); // 自前関数でシステム別衛星数をパース
}
// 1秒ごとに画面を更新
static unsigned long last_display_time = 0;
if (millis() - last_display_time > 1000) {
last_display_time = millis();
update_display();
}
}
void update_display() {
lcd.startWrite(); // 描画処理の最適化開始
// 1. 位置情報の表示 (背景色をTFT_BLACKに指定して上書き時のチラつき防止)
if (gps.location.isValid()) {
lcd.setTextColor(TFT_WHITE, TFT_BLACK);
lcd.setCursor(10, 25); lcd.printf("緯度:%11.6f ", gps.location.lat());
lcd.setCursor(10, 50); lcd.printf("経度: %11.6f ", gps.location.lng());
} else {
lcd.setTextColor(TFT_YELLOW, TFT_BLACK);
lcd.setCursor(10, 25); lcd.print("緯度:Searching... ");
lcd.setCursor(10, 50); lcd.print("緯度: Searching... ");
}
// 2. 高度の表示
if (gps.altitude.isValid()) {
lcd.setTextColor(TFT_WHITE, TFT_BLACK);
lcd.setCursor(10, 75); lcd.printf("高度: %7.1f m ", gps.altitude.meters());
} else {
lcd.setTextColor(TFT_YELLOW, TFT_BLACK);
lcd.setCursor(10, 75); lcd.print("高度: Searching... ");
}
// 区切り線
lcd.drawFastHLine(10, 105, 300, TFT_DARKGREY);
// 3. 各システムごとの補足衛星数表示
lcd.setTextColor(TFT_GREEN, TFT_BLACK);
lcd.setCursor(10, 110); lcd.print("Satellites in View:");
lcd.setTextColor(TFT_WHITE, TFT_BLACK);
// %2d を使うことで桁数が変わっても表示位置がズレたりゴミが残ったりしません
lcd.setCursor(20, 135); lcd.printf("GPS : %2d ", sats_gps);
lcd.setCursor(20, 155); lcd.printf("みちびき : %2d ", sats_qzss);
lcd.setCursor(20, 175); lcd.printf("BeiDou : %2d ", sats_beidou);
//lcd.setCursor(20, 195); lcd.printf("GLONASS : %2d ", sats_glonass);
//lcd.setCursor(20, 215); lcd.printf("Galileo : %2d ", sats_galileo);
lcd.setCursor(20, 200);
lcd.printf("有効衛星数: %2d ", gps.satellites.value());
lcd.endWrite(); // 描画処理の最適化終了
}