以前、GPS高度計の記事を書きましたが、その後に少し改良?しました。
以前の記事はこちら ↓
jnz-tech.hatenablog.com
jnz-tech.hatenablog.com
何を変えたかというと、次の3点です。
これらによって、ものすごく回路がシンプルになりました。
GPSアンテナ一体型ユニットは、秋月電子の「GPS受信機 シリアル出力タイプ(先バラ) みちびき2機(194/195)対応 1PPS出力付 GT-502MGG-N」を利用しました(名前が長い)。
akizukidenshi.com
これはGPSアンテナ内部にシリアル変換回路が入っているため、そのままシリアル通信(UART)で読むことができます。これで以前の記事に書いたシリアル出力の基板が不要になりました。また、このモジュールの電源電圧は3~5Vになっています。OLEDディスプレイも3.3V駆動なので、ESP32を使うことで、以前の記事で使っていたレベル変換モジュールも不要になりました。
ということで、回路はいたってシンプル。
単にESP32に繋ぐだけです。
プログラムの方の変更点は、以下の3点
- 以前は Arduino 用にソフトウェアシリアルを利用していましたが、ESP32には無いのでUART2を用いた(51行目など)
- GPSモジュールからのNMEAフォーマットのヘッダ部分が若干変わっていたのでを修正(12行目あたりのGPGGA→GNGGA)
- 時間表示の追加(145行目あたり)と、それに伴ったレイアウト変更(捕捉衛星数表示をニコちゃんマークの右下にするとか)
#include <TinyGPSPlus.h> #include <U8g2lib.h> #include <Wire.h> // GPS baud static const uint32_t GPSBaud = 9600; // The TinyGPSPlus object TinyGPSPlus gps; // Tiny GPS Custom object TinyGPSCustom gps_tim (gps, "GNGGA", 1); // 時刻 TinyGPSCustom gps_alt (gps, "GNGGA", 9); // 高度 TinyGPSCustom gps_sat (gps, "GNGGA", 7); // 衛星数 TinyGPSCustom gps_qlt (gps, "GNGGA", 6); // 測位モード TinyGPSCustom gps_spd (gps, "GNRMC", 7); // 速度(ノット) TinyGPSCustom gps_dir (gps, "GNRMC", 8); // 方位 // 方位の定義。16番目は WAIT static const char *c_dir[17] = { " N ", "N-N-E ", " N-E ", "E-N-E ", " E ", "E-S-E ", " S-E ", "S-S-E ", " S ", "S-S-W ", " S-W ", "W-S-W ", " W ", "W-N-W ", " N-W ", "N-N-W ", "WAIT "}; // 前回方位保管用 float f_olddir=999; // 前回分保管用 int i_oldmin=999; // OLE object U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 22, /* data=*/ 21, /* reset=*/ U8X8_PIN_NONE); void setup() { Serial.begin(9600); Serial2.begin(GPSBaud); // TX=16,RX=17 がデフォルト // LCD初期化 delay(1000); u8g2.begin(); u8g2.setPowerSave(0); u8g2.setFlipMode(0); } void loop() { // 変数宣言 float f_alt; float f_spd; float f_dir; int i_dir; int i_qlt; int i_hour; int i_min; char hour[5]; char min[5]; char buf[100]; // 時刻の取得とJSTへの変換 strcpy (buf, gps_tim.value()); strncpy (hour, buf, 2); strncpy (min, buf+2, 2); i_hour = atoi(hour); i_hour = i_hour + 9; if (i_hour > 23){ i_hour = i_hour - 24; } i_min = atoi(min); // 更新があったときのみ表示を変更する if (i_min != i_oldmin || gps_alt.isUpdated() || gps_sat.isUpdated() || gps_qlt.isUpdated() || gps_spd.isUpdated() || gps_dir.isUpdated()) { // 標高を数値に変換 f_alt=atof(gps_alt.value()); // 速度を数値に変更してkm/h換算 f_spd=atof(gps_spd.value()) * 1.852; // 速度が 8km/h 以上で方位を更新する if (f_spd >= 8.0) { // 方位を元に配列引数を算出 f_dir=atof(gps_dir.value()); } else { f_dir=f_olddir; } // 方位を元に方位文字配列引数を算出 if (f_dir < 360) { float f_tmp=f_dir + 11.25; if (f_tmp >= 360.0) { f_tmp -= 360.0; } i_dir=(int)(f_tmp/22.5); } else { i_dir = 16; } // 方位を保存 f_olddir = f_dir; // LCDに表示 u8g2.clearBuffer(); // 速度表示 u8g2.setFont(u8g2_font_6x13_mr); u8g2.setCursor(3,15); dtostrf(f_spd, 4, 0, buf); u8g2.print(F("Spd : ")); u8g2.print(buf); u8g2.print(" km/h"); // 方位表示 u8g2.setFont(u8g2_font_6x13_mr); u8g2.setCursor(3,30); if (f_dir > 360) { u8g2.print(F("Dir : WAIT")); } else { dtostrf(f_dir, 4, 0, buf); u8g2.print(F("Dir : ")); u8g2.print(buf); u8g2.print(" deg "); u8g2.setCursor(95,30); u8g2.print(c_dir[i_dir]); } // 高度表示 u8g2.setFont(u8g2_font_6x13_mr); u8g2.setCursor(3,45); dtostrf(f_alt, 4, 0, buf); u8g2.print(F("Alt : ")); u8g2.print(buf); u8g2.print(" m "); // 時間表示 u8g2.setFont(u8g2_font_6x13_mr); u8g2.setCursor(3,60); sprintf(buf, "%02d:%02d", i_hour, i_min); u8g2.print(F("JST : "));u8g2.print(buf); i_oldmin = i_min; // 衛星数表示 u8g2.setFont(u8g2_font_5x8_mr); u8g2.setCursor(115,63); sprintf(buf, "%02s", gps_sat.value()); u8g2.print(buf); // 測位方式表示 i_qlt = atoi(gps_qlt.value()); u8g2.setFont(u8g2_font_emoticons21_tr); u8g2.drawGlyph(93,60,0x24-i_qlt*2); // 画面出力 u8g2.sendBuffer(); } // delay付きのGPS受信 smartDelay(1000); } // delay付きのGPS受信 static void smartDelay(unsigned long ms) { unsigned long start = millis(); do { while (Serial2.available()) gps.encode(Serial2.read()); } while (millis() - start < ms); }
表示はこんな感じになりました。
なかなかいい感じ♪
上の写真のケースについては、次回に書こうと思います。