◯やりたいこと
GPSモジュールを使ってOLEDを表示器にしたGPS受信器を作ってみる。GPSモジュールとの通信はUART、OLEDとの通信はI2Cとなるので、2つの異なった通信の同時利用に関するノウハウを得たい。
◯やったこと
最初はATtinyで簡単にできないかなと考えたのですが、SoftwareSerial(UART)とWire(I2C)ライブラリの同時起動が可能かどうかの不安があったのと、そもそもGPSモジュールをいじった事がなかったのでデバック作業が複雑化してしまう事を懸念して、ハードウェアシリアルを持つESP8266(今回はESP01)を使って実験して見る事にしました。
・回路設計
回路自体は簡単です。ESPのUARTにGPSを、I2CにOLEDを接続するだけです。UARTはESP01の場合 TX - D1, RX - D3に指定されていますし、I2CはWireライブラリ指定時に任意のピンを割り当てれば大丈夫です。今回は配線の都合で SDA - D2, SCK - D0の組み合わせにしています。
またPCとの通信用と電源供給を兼ねてUSB-UART変換モジュールも組み込みます。秋月電子で購入した超小型のモジュールを使用しています。
・製作
さっそくミニブレッドボードに作ってみました。
はみ出し、アンバランスはご勘弁。あくまで動作ノウハウ取得用の実験機の製作です。
GPSモジュールはケース化した時の設置方法が決まっていないためスルーホール用のジャンパ線を利用して取り付けます。
ショート防止用のセロテープはご愛嬌。
それぞれ接続して受信器が完成です。
・スケッチ作成
すったもんだしながら自分なりにスケッチを作ってみました。
動作には Adafruit_SSD1306.h と TinyGPS++.h の2つのモジュールのインストールが必要です。
// Standerd Library #include <Arduino.h> #include <Wire.h> #include <time.h> // Installed library /* OLED (SSD1306) */ #include <Adafruit_SSD1306.h> /* GPS (NEO-6M) */ #include <TinyGPS++.h> // http://arduiniana.org/libraries/tinygpsplus/ // Unique Value /* UART */ #define TX 1 // D1 #define RX 3 // D3 HardwareSerial hs(0); // UART 0 /* I2C */ #define I2C_SDA 2 // D2 #define I2C_SCK 0 // D0 #define I2C_CLK 50000 // fSCL=100KHz /* OLED */ #define OLED_ADR 0x3C // I2C ADDRESS #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); /* GPS */ TinyGPSPlus gps; void setup() { // シリアル設定 hs.begin(9600); // I2C設定 Wire.begin (I2C_SDA, I2C_SCK); // set I2C pins, default clock is 100kHz Wire.setClock(I2C_CLK); // set I2C clock(fSCL) // OLED(SSD1306) 開始 display.begin(SSD1306_SWITCHCAPVCC, OLED_ADR); // OLED画面初期表示 display.clearDisplay(); display.setTextColor(WHITE); display.setTextSize(2); display.setCursor( 0, 0); display.println("SSD1306"); display.setTextSize(1); display.setCursor( 0, 19); display.println("OLED Start."); display.display(); } void loop() { // 初期設定 char t[17]; String s; // 受信データ表示 if(get_nmea()) { // 表示初期化 display.clearDisplay(); // 日付,時刻表示 display.setTextSize(1); display.setCursor( 0, 4); sprintf(t,"%04d/%02d/%02d %02d:%02d%:02d", gps.date.year(), gps.date.month(), gps.date.day(), (gps.time.hour()+9)%24,gps.time.minute(),gps.time.second()); display.println(t); // GPS詳細データ表示 display.setTextSize(1); display.setCursor( 0, 16); s = "Lat: "+String(gps.location.lat(),6); display.println(s); s = "Lng: "+String(gps.location.lng(),6); display.println(s); s = "Spd: "+String(gps.speed.kmph(),0)+" km/h"; display.println(s); s = "Alt: "+String(gps.altitude.meters(),0)+" m"; display.println(s); display.println(); s = "Satellite "+String(gps.satellites.value()); display.println(s); } // データ未受信 else { display.fillRect( 0, 0,128, 16,BLACK); display.setTextSize(2); display.setCursor( 0, 0); display.print("No DATA"); } display.display(); } // GPSデータ受信 boolean get_nmea() { boolean flg_nmea = false; for (unsigned long start = millis(); millis() - start < 1000;) { while (hs.available()) { if (gps.encode(hs.read())) flg_nmea = true;; } } return flg_nmea; }
当初GPSモジュールとESPのUART通信がうまくいかず結構はまりましたが、UARTをHardwareSerialの0番としてガッチリ指定して使用したところうまく通信してくれました。通常使いのSerial.read()ではうまくいかないようです。
その他の部分はそれ程問題なく動作してくれました。
・動作
出来上がったところでさっそく電源を入れてみます。
無事動作。写真はスタート時点でまだGPS情報が受信できていませんが時間情報は受信しているようです。しばらく置いておくと衛星情報を受信し始め、モジュールのLEDが点滅を始めると座標データが表示されます。
モジュールからの出力はPC用のUARTモジュールにも接続しているので、PCでも専用ソフトでの表示が可能です。
◯やってみて
とりあえず第一段階の目的、動作ノウハウ取得は完了です。ESP8266で動作確認が取れましたので、wroomを使ったSDカードへの座標ロギングやWiFiでのデータ交換等いろいろ拡張していきたいと思います。いたずらでATtiny85でもできないかやってみるつもりです。