LoginSignup
0
2

More than 5 years have passed since last update.

ArduinoでのGPSモジュール(GMS7-CR6)からの日時取得

Last updated at Posted at 2017-03-08

はじめに

RandyHoo(@RandyHoo_)と申します。
ニキシー管時計を作ったりしてる組み込みプログラマです。
NixieClock.jpg
ニキシー管時計を作ってるときにハマった箇所なので展開します。

今回解説するコードはGitHubにて公開しています。

実装・解説

今回使用したGPSモジュールは、GMS7-CR6です。

Nixcie_Clock.ino
#include <SoftwareSerial.h>
#include <string.h>
#include <stdlib.h>
#include <MsTimer2.h>
#include <Wire.h>

int CalenderArray[6] = {}; //0:Year1桁目, 1:Year2桁目, 2:Month1桁目, 3:Month2桁目, 4:Day1桁目, 5:Day2桁目

int ClockArray[6] = {}; //0:Hour1桁目, 1:Hour2桁目, 2:Min1桁目, 3:Min2桁目, 4:Sec1桁目, 5:Sec2桁目
boolean data_get_flag = false; //GPSデータ取得確認用フラグ

void loop() {
  data_get_flag = GPSDataCatch();//初期値設定用のデータ取得
}
GPSDataCatch.ino
int GPSDataCatch(){
  String year_1; //現在の年1桁目
  String year_2; //現在の年2桁目
  String month_1; //現在の月1桁目
  String month_2; //現在の月2桁目
  String day_1; //現在の日1桁目
  String day_2; //現在の日2桁目
  String hour_1; //現在の時1桁目
  String hour_2; //現在の時2桁目
  String min_1; //現在の分1桁目
  String min_2; //現在の分2桁目
  String sec_1; //現在の秒1桁目
  String sec_2; //現在の秒2桁目

  char GPS_Rx_buf[256]; //受信用バッファ(255文字分)
  char GPS_Rx_count; //受信データカウンタ

  String want_frame = "$GPRMC"; //データを取り出したいフレーム
  String WantStatus = "A"; //ステータス判別用

  char data_read_count = 0; //データ読み出しカウンタ
  int data_get_flag = false; //データ取得結果

GPSから受信したデータを解析していきます。
文字変換を行うため、String型で扱います。

GPSDataCatch.ino
  //Ackフレームを受信するまでループを回す
  do {
    if ( sGps.available() ) {
      GPS_Rx_buf[ GPS_Rx_count ] = sGps.read();
      GPS_Rx_count++;
    }
    //バッファが溢れそうなら
    if ( GPS_Rx_count > 250 ) {
      break;
    }
  } while ( GPS_Rx_buf[ GPS_Rx_count - 1 ] != 0x0A );
  GPS_Rx_buf[ GPS_Rx_count ] = '\0'; //一番最後の要素に改行を入れる
  String buf_str = GPS_Rx_buf; //Stringで処理するために変換

データは「,」で区切られているので、「,」の位置を取得し、必要なデータだけを取得していきます。
日時が取得できなかった場合にはこの関数の戻り値でfalseを返します。

GPSDataCatch.ino
  //欲しいデータかどうか調べる
 //LogSample : $GPRMC,142152.000,A,3247.4679,N,12957.0161,E,0.00,36.32,250116,,,A*5A
  if ( want_frame == buf_str.substring( 0, 6 ) && WantStatus == buf_str.substring( 18, 19 ) ) {
    data_read_count = buf_str.indexOf( ",", data_read_count ); //1つ目の区切り文字を探す
    data_read_count++; //不要データなので次のデータへ

    data_read_count = buf_str.indexOf( ",", data_read_count ); //2つ目の区切り文字を探す(時刻)
    data_read_count++; //時計・カレンダーでは文字列位置を直指定するので次のデータへ

時刻はUTC(協定世界時)で取得するので、日本時間に修正します。
また、10以下の数字を「0X」表示するために変換処理を噛ませています。

GPSDataCatch.ino
    String UTC_time = buf_str.substring( 7, 9 ); //時刻修正処理の為にHourを抜き出す
    int JP_time = atoi( UTC_time.c_str() ) + 9; //日本時間に修正
    //変換した際に24時以上になった場合
    if ( JP_time > 23 ) {
      JP_time -= 24;
    }
    String JP_time_str = String( JP_time ); //日本時間に差し換えるためにStringに変換
    //時刻が1桁だった場合
    if ( JP_time < 10) {
      String change_double_digit_calc = JP_time_str.substring( 0, 1 ); //1桁目を保持
      JP_time_str = "00"; //JP_time_strのデータ長を2に増設する
      char hoge_cddc = *change_double_digit_calc.c_str(); //1桁目に0を差し込むためにchar型に変換
      JP_time_str.setCharAt( 0, '0' ); //1桁目を0に差し替える
      JP_time_str.setCharAt( 1, hoge_cddc ); //2桁目に1桁目を差し込む
      String JP_time_str = String( JP_time ); //もう一度Stringに変換
    }

    String JP_time_first_digit = JP_time_str.substring( 0, 1 ); //1桁目を取り出す
    char hoge_1 = *JP_time_first_digit.c_str(); //char型に変換
    String JP_time_second_digit = JP_time_str.substring( 1, 2 ); //2桁目を取り出す
    char hoge_2 = *JP_time_second_digit.c_str(); //char型に変換
    buf_str.setCharAt( 7, hoge_1 ); //1桁目を差し替える
    buf_str.setCharAt( 8, hoge_2 ); //2桁目を差し替える

日時が取得出来たのでそれぞれint型に変換して配列に入れていきます。

GPSDataCatch.ino
    //時1桁目を取得
    hour_1 = buf_str.substring( 7, 8 );
    ClockArray[0] = hour_1.toInt();
    //時2桁目を取得
    hour_2 = buf_str.substring( 8, 9 );
    ClockArray[1] = hour_2.toInt();
    //分1桁目を取得
    min_1 = buf_str.substring( 9, 10 );
    ClockArray[2] = min_1.toInt();
    //分2桁目を取得
    min_2 = buf_str.substring( 10, 11 );
    ClockArray[3] = min_2.toInt();
    //秒1桁目を取得
    sec_1 = buf_str.substring( 11, 12 );
    ClockArray[4] = sec_1.toInt();
    //秒2桁目を取得
    sec_2 = buf_str.substring( 12, 13 );
    ClockArray[5] = sec_2.toInt();

    //3~9つ目までの区切り文字をスキップする
    for (int i = 0; i < 7; i++) {
      data_read_count = buf_str.indexOf( ",", data_read_count ); //3つ目の区切り文字を探す
      data_read_count++; //不要データなので次のデータへ
    }

    //日1桁目を取得
    day_1 = buf_str.substring( data_read_count, data_read_count + 1 );
    CalenderArray[4] = day_1.toInt();
    data_read_count++;
    //日2桁目を取得
    day_2 = buf_str.substring( data_read_count, data_read_count + 1 );
    CalenderArray[5] = day_2.toInt();
    data_read_count++;
    //月1桁目を取得
    month_1 = buf_str.substring( data_read_count, data_read_count + 1 );
    CalenderArray[2] = month_1.toInt();
    data_read_count++;
    //月2桁目を取得
    month_2 = buf_str.substring( data_read_count, data_read_count + 1 );
    CalenderArray[3] = month_2.toInt();
    data_read_count++;
    //年1桁目を取得
    year_1 = buf_str.substring( data_read_count, data_read_count + 1 );
    CalenderArray[0] = year_1.toInt();
    data_read_count++;
    //年2桁目を取得
    year_2 = buf_str.substring( data_read_count, data_read_count + 1 );
    CalenderArray[1] = year_2.toInt();

以上です。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2