なんでも作っちゃう、かも。

Arduino/Make/フィジカルコンピューティング/電子工作あたりで活動しています。スタバの空きカップを使ったスタバカップアンプなど製作。最近はもっぱらArduinoと3Dプリンタの自作に興味があります。

Arduinoで遊ぼう - GPSを使った高精度な時計

Posted by arms22 on 2010年03月13日 12  0

Arduino+GPS時計
GPS衛星から発信される信号には、衛星に搭載された原子時計の時刻情報が入っている。GPS受信機はこの時刻情報をもとにGPS受信機に搭載されている時計の時刻を校正することで、高精度な時刻情報を得ている。この時刻情報を使って高精度なGPS時計を作った。

GPS受信機をArduinoに接続し、1秒周期で送られてくる時刻情報をLCDに表示している。赤く光っている部品がGPS受信機「LS20031」。このGPS時計は電池一本で何年も動かすことはできないし、屋内ではGPS衛星からの信号を受信することもできない。GPS受信機から送られてくる時刻情報は確かに正確だが、Arduino間の通信時間やArduinoの処理時間などでLCDに表示される時間は数100ms秒遅れる。


Arduinoと接続する



Arduino+GPS時計の回路図

キャラクタLCDとArduinoは次のように接続する。
RS→アナログ0番
R/W→GND
E→アナログ1番
DB4→アナログ2番
DB5→アナログ3番
DB6→アナログ4番
DB7→アナログ5番
GPS受信機とArduinoは次のように接続する。
VCC→3.3V
RX→(未接続)
TX→デジタル2番
GND→GND

Arduino+GPS時計
バックライトLEDのアノード端子は基板上のJ3をショートさせてVCCと接続し、カソード端子は110Ω(R9)抵抗をかいしてGNDに接続している。


ライブラリのインストール


GPS受信機からはNMEAフォーマットと呼ばれるテキスト形式のデータが送られてくる。
$GPGGA,125333.000,3444.4637,N,13532.4905,E,1,5,1.41,32.7,M,34.4,M,,*62
$GPRMC,125333.000,A,3444.4637,N,13532.4905,E,0.09,1.94,110310,,,A*63

NMEAフォーマットは人が理解するには都合が良いが、マイコンのプログラムで扱うには都合が悪い。そこでNMEAパーサー「TinyGPS」ライブラリを使ってNMEAフォーマットをプログラムで扱いやすい形に変換する。
次のURLからライブラリをダウンロードし、Arduinoのライブラリフォルダにコピーする。

TinyGPS | Arduiniana
http://arduiniana.org/libraries/tinygps/

GPS受信機との通信にソフトウェアシリアルを使うので、次のライブラリもダウンロードする。

NewSoftSerial | Arduiniana
http://arduiniana.org/libraries/newsoftserial/


サンプルスケッチ


#include <NewSoftSerial.h>
#include <TinyGPS.h>
#include <LiquidCrystal.h>

// NMEAパーサー TinyGPS
TinyGPS gps;

// ソフトウェアシリアル(RX=2, TX=3)
NewSoftSerial nss(2, 3);

// LCD(RS=14, E=15, DB4=16, DB5=17, DB6=18, DB7=19)
LiquidCrystal lcd(14, 15, 16, 17, 18, 19); // analog 0, 1, 2, 3, 4, 5

void setup()
{
  // LCD初期化(16文字、2行)
  lcd.begin(16,2);
  // PCとのシリアル通信初期化
  Serial.begin(115200);
  // 最初のメッセージ表示
  lcd.print("No GPS Signal.");
  // ソフトウェアシリアル初期化(9600bps)
  nss.begin(9600);
}

void loop()
{
  int year;
  byte month, day, hour, minute, second, hundredths;
  bool newdata = false;

  // GPS受信機から送られたデータがある間
  while(nss.available()){
    char c = nss.read();
    // シリアルモニタに受信した文字を送る
    Serial.print(c);
    // encode()で1文字ずつ解析
    if(gps.encode(c)){
      newdata = true;
    }
  }

  if(newdata){
    // 画面をクリア
    lcd.clear();

    // 日付、時間を取得
    gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths);

    // 1行目、1文字目にカーソルを移動
    lcd.setCursor(0, 0);
    lcd.print(static_cast<int>(year));
    lcd.print("/");
    lcd.print(static_cast<int>(month));
    lcd.print("/");
    lcd.print(static_cast<int>(day));

    // 2行目、3文字目にカーソルを移動
    lcd.setCursor(2, 1);
    // GPSの時間はUTC(協定世界時)なので+9時間してJSTにする
    lcd.print(static_cast<int>((hour + 9) % 24));
    lcd.print(":");
    lcd.print(static_cast<int>(minute));
    lcd.print(":");
    lcd.print(static_cast<int>(second));
    lcd.print(".");
    lcd.print(static_cast<int>(hundredths));
  }
}



Arduinoをはじめよう (Make:PROJECTS)
Massimo Banzi
オライリージャパン
売り上げランキング: 3176




Ads by Google

12 Comments

鹿煎餅 says..."No title"
LS20031の転送速度を調べたいと考えています。
転送速度を調べるため、以下のスケッチを作成しました。
#include <SoftwareSerial.h>
#include <TinyGPS.h>

// NMEAパーサー TinyGPS
TinyGPS gps;

// ソフトウェアシリアル(RX=1, TX=0)
SoftwareSerial nss(1, 0);

void setup()
{
// ソフトウェアシリアル初期化(57600bps)
nss.begin(38400);//この値を手動で変更し、書き込む
pinMode(12,OUTPUT);
}

void loop()
{
if(nss.available()){
digitalWrite (12, HIGH);
}
}
動作の概要として、
(1)シリアル通信が出来たら12番ピンにつけたLEDが点灯する
(2)上記が行われるまで、nss.begin(38400)の値を変更し、プログラムを書き換える
というものです。
ただ、転送速度を115200,57600等に変更してもLEDは点灯しませんでした。
つきましては
(1)LS20031の転送速度を調査された手順 または
(2)上記スケッチの問題点
をご回答いただければ幸いです。

開発環境は以下のとおりです
(1)IDE Ver1.0.3
(2)ARDUINO LEONARDO
(3)Mac OS Ver 10.8.2

以上、よろしくお願い致します。
2013.02.03 11:48 | URL | #xfWPEvlw [edit]
鹿煎餅 says..."No title"
[追記]
配線は
LS20031 ARDUINO
3番ピン---1番ピン
としています。
2013.02.03 12:13 | URL | #xfWPEvlw [edit]
arms22 says..."Re: No title"
単純にボーレートが知りたい場合は、
ソフトウェアシリアルで受信したデータを、
そのままPC側に出力すれば、判断できると思います。

if(nss.available()){
Serial.write( nss.read() );
}
2013.02.03 19:38 | URL | #- [edit]
鹿煎餅 says..."No title"
お返事ありがとうございます。
LS20013を直接PCと接続したろころ、57600bpsで通信ができることを確認しました(ターミナルでGPSのデータを受信していることを確認しました)。
ただ、LEONARDOでは受信出来ないようでした。
スケッチを以下に記します。
#include <SoftwareSerial.h>

// ソフトウェアシリアル(RX=1, TX=0)
SoftwareSerial nss(1, 0);

void setup()
{
// ソフトウェアシリアル初期化(57600bps)
nss.begin(57600);
pinMode(12,OUTPUT);
}

void loop()
{
if(nss.available()>0){
digitalWrite (12, HIGH);
}
else{
digitalWrite (12, LOW);
}
}
シリアル通信ができている場合に12番ピンがHIGHになるようにしていますが、接続しているLEDが点灯しません。
この状態でデータの送信先をPCにつなぎ替えると正常に受信しているので、LS20031からデータの送信は行われているようです。
なお、LS20031との接続は
LS20031 ARDUINO
3番ピン---1番ピン
としています。

もし、何か思いつかれることがありましたら、お時間あるときでかまいませんので、お返事頂ければとおもいます。
2013.02.03 20:23 | URL | #xfWPEvlw [edit]
arms22 says..."No title"
Leonardoの場合、ソフトウェアシリアルの受信ポートに使えるポートに制限があります。下記のポートを受信ポートに使用してみてください。
RX: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).

http://arduino.cc/en/Reference/SoftwareSerial
2013.02.03 22:00 | URL | #- [edit]
鹿煎餅 says..."No title"
何度も返信頂き、ありがとうございます。
上記返信先のリンクにありますサンプルを打ち込みましたところ、無事に動作しました。
休日に夜遅くまで対応頂き、ありがとうございました。
2013.02.04 00:34 | URL | #xfWPEvlw [edit]
鹿煎餅 says..."TinyGPSに関して"
TinyGPSのencodeに関して質問をさせて頂きたいと思います。
LeonardoとLS20031をソフトウェアシリアルで接続し、TinyGPSで時刻を抽出する様にしたいと考えています。
現在、LeonardoとLS20031の接続は9600bpsで接続できていることを確認している(LS20031からLeonardoへ送信される内容と、Leonardoからハードウェアシリアルで出力される内容が一致している)のですが、TinyGPSのencode関数でNGと判断されてしまいます。
そこで
(1)導入の際、ソフトウェアに対して設定の変更等実施されたでしょうか
(2)以下のスケッチで相違点等あればご指摘いただけないでしょうか

本来なら作者のHPで質問すれば良いのですが、英語が苦手であり、また、使用された実績があるため、こちらで質問させて頂きました。

お手数をおかけしますが、お時間ある時にご回答いただければと思います。

スケッチを以下に記します。
#include <SoftwareSerial.h>
#include <TimerOne.h>
#include <TinyGPS.h>

// ソフトウェアシリアル(RX=10, TX=11)
TinyGPS gps;

SoftwareSerial ss(10, 11);

void setup() {
Serial.begin(9600);
ss.begin(9600);
pinMode(13,OUTPUT);

digitalWrite(13,LOW);
}

void loop() {
if (ss.available()) {
char c = ss.read();
Serial.print(c);
if(gps.encode(c)){
digitalWrite(13,HIGH);//テスト用
}
}
}


また、LE20031からの出力を以下に記します。
$GPRMC,055003.399,V,,,,,0.00,107.33,160213,,,N*4C
$GPGGA,055003.599,,,,,0,0,,,M,,M,,*4E
$GPRMC,055003.599,V,,,,,0.00,107.33,160213,,,N*4A
$GPGGA,055003.799,,,,,0,0,,,M,,M,,*4C
$GPRMC,055003.799,V,,,,,0.00,107.33,160213,,,N*48
$GPGGA,055003.999,,,,,0,0,,,M,,M,,*42
2013.02.16 15:09 | URL | #xfWPEvlw [edit]
鹿煎餅 says..."TinyGPSに関して(解決しました)"
お世話になります。上記で質問させて頂いた点ですが、衛星を補足していなかったことが原因であることがわかりました。
ご迷惑をおかけしました。
2013.02.16 18:17 | URL | #- [edit]
arms22 says..."Re: TinyGPSに関して(解決しました)"
そうですね、衛生を補足するまでNGが返ってきますね。
GPSのLEDが周期的に点滅しはじめたら、衛生を補足しているはずですよ。
2013.02.17 14:06 | URL | #- [edit]
to-tempoor says..."抵抗値に関して"
初めまして。電子工作初心者です。
接続図を見て分からないところが二点だけあります。
一点目は抵抗に関してです。
LCDの1番ピンから5番ピンに抵抗値がつながっていますが、これは何Ωの抵抗ですか?
それと、LCDからも抵抗につながっていますが、この抵抗は可変抵抗で、中間電圧を採る形の接続でしょうか?
二点目はプログラムに関してです。
同じように接続図を見ると、
LiquidCrystal lcd(14, 15, 16, 17, 18, 19);
のところは、
LiquidCrystal lcd(4, 6, 11, 12, 13, 14);
ではないでしょうか?LCDに19番ピンってありませんよね・・・?
2015.10.26 04:02 | URL | #- [edit]
to-tempoor says..."上記の訂正"
連投してしまってすみません。先ほど投稿した質問文のうち、以下の部分を訂正します。
それと、LCDからも抵抗につながっていますが、この抵抗は可変抵抗で、中間電圧を採る形の接続でしょうか?
>>それと、LCDの3番ピンからも抵抗につながっていますが、この抵抗は可変抵抗で、中間電圧を採る形の接続でしょうか?
どなたか分かる方回答お願いいたします。
2015.10.26 04:05 | URL | #- [edit]
arms22 says...""
R1は可変抵抗でLCDのコントラストを調整するためのものです。
可変抵抗の中点?をLCDの3番に接続してつかいます。

>LiquidCrystal lcd(14, 15, 16, 17, 18, 19);

ここで指定している番号はArduinoのピン番号になります。
Analogピンをデジタルピンとして利用しています。
A0〜A5の別名が14,15,16,17,18,19と思ってください。
2015.10.31 23:09 | URL | #j7sy4omY [edit]

Leave a reply






管理者にだけ表示を許可する

該当の記事は見つかりませんでした。