風邪っぽい感じが抜けないので、お出かけせずに、
引き続きGPSをArduinoに繋いで、LCD表示する
ことにしてみる。
GPSからのシリアル入力を受けて、文字処理して、
LCDに表示するという流れで行う作戦。
文字処理が色々厄介なので、サンプルを探すと、
http://baticadila.dip.jp/arduino_105.html
このページの下のほうにあるスケッチがイイカンジ
なので、これを参考にして、LCD表示するような
スケッチに作り変えてみる。
それにしても、普段C言語で文字処理とか
やらないので、文字列←→数値、の変換処理で
思わぬ苦戦。スマートな方法が思いつかなかった
ので、とりあえず力技でねじ伏せた。
表示してみた結果がこれ。
GPSモジュールのLVTTL出力は3.3Vなんだけど、
Arduinoのシュミットトリが入力の弁別は
2.5V付近にあるはずなので、一応HIGH/LOW
の判別は可能だった。
デジタル11番でソフトウェアシリアルで受けて、
LCDとハードウェアシリアルに出力。
左上は、UTCに9時間を足した時刻(日本標準時)
で表示してみた。その下に「(UTC)」って書いて
あるのは、9時間足さずに表示してたときの名残。
(バグとも言う)
閏秒に関わる誤差の補正は組み込んでないし、
60進数を加味して補正するのは面倒なので、
これであきらめる。
右側上は緯度で、下は経度。「N」は北緯で
「E」は東経。
ちなみに、シリアル出力には「$GPGGA」の
センテンスから拾ってて、この$GPGGAは行の
内容丸ごとシリアルに出力。そこから眺めると、
どうやら補足している衛星数は、7~8個みたい。
ちなみに、$GPGGAのセンテンスは、1秒置きに
出力されてくるみたい。
緯度、経度の数値を眺めてみると、どうやら、
数m程度の誤差内に収まっている感じなんだけど、
なんか引っかかることが数点。
電源を入れなおすたびに数メートルほど飛ぶ
のは、優先している衛星がコロコロ変わる
からなのかなぁ?まぁ、せいぜい数m以内
なんだけど。特に北緯の散らばりが大きそう。
それと、一旦位置を補足すると、そこから
1~2m程度動かしてみても、数値が変化しない
みたい。なんでだろう?
表示されている数値は、「分」の1/10000まで
なので、計算では18cmくらいの単位で表示
出来るはずなんだけど、この微妙な移動を
検知できてないみたい。
数値がコロコロ変化してもイイから、もう少し
細かい移動を拾ってくれることを期待して
いたんだけどな。
とりあえず、今時点で動かしている、Arduino用
のスケッチを晒しちゃう。
#include <SoftwareSerial.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <LiquidCrystal.h>
/* I/O pins for aitendo lcd shield */
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
SoftwareSerial sw_serial(11, 13); // GPS on D11
/* print out on lcd */
void print_lcd(char *buf1) {
char *str1;
char tmp0[100];
unsigned long time;
int i,j;
unsigned long k,t;
/* utc time */
str1 = strtok(buf1,","); /* skip reading */
str1 = strtok(NULL,","); /* utc time */
strncpy(tmp0, str1, 6);
tmp0[6] = '\0';
time = atol(tmp0);
if ((time + 90000L) > 235959) {
time += (- 240000L + 90000L);
} else {
time += 90000L;
}
t = time;
for (i = 0; i < 6; i++) {
k = 1L;
for (j = 0; j < (5-i); j++) {
k *= 10L;
}
tmp0[i] = (char) (time / k);
time -= ((long)tmp0[i]) * k;
tmp0[i] += '0';
}
if (str1 != NULL) {
lcd.setCursor(0,1);
lcd.print("(UTC)");
lcd.setCursor(0,0);
lcd.print(tmp0);
}
/* latitude */
str1 = strtok(NULL,",");
if (str1 != NULL) {
lcd.setCursor(7,0);
lcd.print(str1);
}
/* hemisphere */
str1 = strtok(NULL,",");
if (str1 != NULL) {
lcd.setCursor(6,0);
lcd.print(str1);
}
/* longitude */
str1 = strtok(NULL,",");
if (str1 != NULL) {
lcd.setCursor(6,1);
lcd.print(str1);
}
/* east/west */
str1 = strtok(NULL,",");
if (str1 != NULL) {
lcd.setCursor(5,1);
lcd.print(str1);
}
}
void setup() {
/* setup LCD */
// analogWrite(10,127); // back light brightness
lcd.begin(16, 2);
lcd.clear();
lcd.cursor(); // display cursor on
Serial.begin(19200);
Serial.println("start gps display");
sw_serial.begin(4800);
}
void loop() {
char buf1[256];
int cnt1 = 0;
char c;
char *str1;
do {
while ( sw_serial.available() == 0 ) {
}
c = sw_serial.read();
buf1[cnt1] = c;
cnt1 ++;
if (cnt1 > 253) {
c = 0x0a; //'\n'
buf1[cnt1] = c;
cnt1 ++;
}
} while ( c != 0x0a ); //'\n'
buf1[cnt1] = 0;
//Serial.println(buf1);
if (strncmp("$GPGGA",buf1,6) == 0) {
/* if '$GPGGA' is inputted */
Serial.println(buf1);
print_lcd(buf1);
}
}
(後日修正:
include文とfor文の不等号記号が、うまく変換
されずに、行の後部が削除されてしまっていた
ので、全角文字に変換しました。計6行分)
モバブーのUSB電源使ってあちこち移動しながら、
数値の変化を見ようと思ったんだけど、スマホ
とかの充電に使うモバブーって、Arduino程度の
消費電力だと、「充電終了」って判断されるのか、
10秒くらいで電源切れちゃってイマイチなので、
USB出力できる5V電源を考え直す。
http://d.hatena.ne.jp/OkibiWorksLabo/20100620/USB_BattBox
どうやら、100円ショップの5V昇圧タイプ電源が、
安くてお手軽かもしれないな。