macsbug

GPS CLOCK with M5STACK

with 2 comments

M5STACK と GPS Module で GPS時計 を作りました                                       2017.12.26


日時、時刻を アナログ と デジタル で表示し 切り替えは3つの ボタンで選択します。

動作:
GPS 情報   : 左のボタンを押し 受信すると 右上の丸が 赤から緑。数値は白から緑。
アナログ時計:中央ボタンを押し 受信すると 右上の丸が 赤から緑になります。
デジタル時計: 右ボタンを押し 受信すると 右上の丸が 赤から緑。数値は白から緑。


準備:

No  Nomen  Link、説明   Price
1  M5STACK BASIC  M5Stack Store ( $33.25 )  3767円
2  M5STACK GPS Module (NEO-M8N−0-10)  M5Stack Store ( $37.91 )  4295円
3  M5STACK Battery Module  M5Stack Store ( $15.11 )  1712円
4  28dBi Gain GPS Antenna  importjewelrylover($2.52)   322円
 —————————————-  ————————-   ——
5  M5STACK ライブラリー  GitHub:M5STACK
6  Free_Fonts:M5STACKライブラリーの中にある。  .inoフォルダの中へ入れる
7  TineGPS++ ライブラリー  TinyGPS++
8  jpg 画像:55×55 pixels程度。(apple mark)  SD に入れる。

.


GPS Module:価格は高いですが 初めてですので 純正品を使用しました。

GPS Module:付属品:1.5mm ケーブル Battery Module
GPS Antenna

.
_ GPS Module のカバーが無く 綺麗でないです。そこで 部品が入っていた
_ 小さな透明なケースがあり サイズがピッタリでしたので 被せました。
.


.
GPS Module:GPSのチップは NEO-M8N-0-10 が使用されています。
配線:M5STACK と GPS Module ( NEO-M8N-0-10 )
_ ESP32 UART2 GPIO-16 ( U2RXD ) — GPS TXD ( NEO-M8N-0-10 ) 。
_ ハードウエアーシリアルの設定:例:HardwareSerial ss(2); 



追記:2018.01.13
小型の GPS アンテナ を取り付けました。ケースの中に入り綺麗に仕上がります。
_ ケース内部に取り付ける事が可能で、受信は正常に受ける事ができました。
_ 小型ですので感覚的に受信感度が少ないかなとも思いましたが最初の
_ 受信時間も数分間で同じでした。
_ 名称:GPS Module with Active Ceramic Antenna IPEX Interface 1575MHz
_ 販売:ebay:chip_partner:価格:$2.30 ( 256円 ):輸送期間 = 26日。
_ サイズ:20mm x 6mm x 6mm:ワイヤーの長さ:20mm
_ ケースの中の高さは 6.4mm ですので入ります。


感想:
M5STACK の利点 (強み) は サンプルやライブラリーの充実にあります。
単独で使用するか 今回の様に 合体して多くの機能を直ぐ作る事ができます。
特に 表示操作では SD内のjpg 画像 を DISPLAY へ表示する命令があります。
例: M5.Lcd.drawJpgFile(SD, “/apple_marks/apple_50.jpg”);
_  SD の中にある apple_50.jpg を LCD へ DRAW します。
_  M5STACK のライブラリーは 強力な開発環境です。 


疑問と課題 ( Questions and tasks ):
_ ESP32 M5STACK と 画像のバイト配列:
_ これまで画像をスケッチ内に保存するには xx.c という バイト配列のデーター
_ に変換し 変数名で使用していました。
_ M5STACK は バイト配列を表示すると 色づれ があり使用できません。
_ 色が反転している訳でも無いです。TFT Display と Display library は 何か細工
_ されている様に思えてしまいます。
_ 対策は SD から jpg を読み込む事ですが バイト配列も使用したい。
_ それと 画像データーを変数名で扱うには どうしたら良いのか解らず課題です。


.
スケッチ:GPS CLOCK with M5STACK : 2017.12.26 : macsbug
M5STACK Library にある「GPS/FullExample」と「Display/TFT_Clock」を
合体し作成しました。表示は GPS受信 と 日時、時刻を アナログとデジタル。
切り替えは A,B,C ボタンで選択します。
「time_set」は 場所に応じて設定します。日本の場合は JST に合わせます。
アナログ時計の左上は 55×55ピクセル程度の jpg画像を SD に入れて起きます。
SD に画像が無い場合は 何も表示せず動作します。

// GPS CLOCK WITH M5STACK : 2017.12.26 : macsbug
#include <M5Stack.h>
#include "Free_Fonts.h"
#include <TinyGPS++.h>
TinyGPSPlus gps;
HardwareSerial gs(2);           // ESP32 UART2 GPIO-16 ( RXD2 ) --- GPS TXD
//=========================================================================
int time_set = 9;       // Set to the time of your country. : JST = +9 hour
float    sx = 0,sy = 1,mx = 1,my = 0,hx = -1,hy = 0;
float    sdeg=0, mdeg=0, hdeg=0;
uint16_t osx=120,osy=120,omx=120,omy=120,ohx=120,ohy=120;
uint16_t x0=0, x1=0, yy0=0, yy1=0;
uint32_t targetTime = 0;                   // for next 1 second timeout
static uint8_t conv2d(const char* p);
uint8_t  hh=conv2d(__TIME__);              // Get H, M, S from compile time
uint8_t  mm=conv2d(__TIME__+3), ss=conv2d(__TIME__+6);
boolean  initial = 1;
static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
unsigned long distanceKmToLondon = (unsigned long)
         TinyGPSPlus::distanceBetween(
         gps.location.lat(),gps.location.lng(),LONDON_LAT,LONDON_LON)/1000;
double   courseToLondon = TinyGPSPlus::courseTo(
         gps.location.lat(),gps.location.lng(),LONDON_LAT,LONDON_LON);
const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);
int      ym, dm, dd;                      // year,month,day
String   ym_, dm_, dd_, hh_, mm_, ss_;    // year,month,day,hour,min,sec
char     f1, f2, f3, b1, b2, b3;          // digital:year,month,day buffer
String   L1[11]={"0000/00/00","00:00:00","000.00" // old gps,time,date,,
            ,"000.00","000.00","000.00","000.00"
            ,"000.00","000.00","000.00"};
String   L2[11]={"0000/00/00","00:00:00","000.00" // new gps,time,date,,
            ,"000.00","000.00","000.00","000.00"
            ,"000.00","000.00","000.00"};
String   mode_ = "gps";                   // gps,digital,analog
//=========================================================================
void setup(){
  Serial.begin(115200);
  M5.begin();
  gs.begin(9600);                   //static const uint32_t GPSBaud = 9600;
  M5.Lcd.fillScreen(BLACK);                                // DISPLAY CLEAR
  pinMode(BUTTON_A_PIN, INPUT_PULLUP);                     // Set A button
  pinMode(BUTTON_B_PIN, INPUT_PULLUP);                     // Set B button
  pinMode(BUTTON_C_PIN, INPUT_PULLUP);                     // Set C button
}
//=========================================================================
void loop(){ 
  if ( M5.BtnA.wasPressed()){ mode_ = "gps"    ; gps_setup()    ;}
  if ( M5.BtnB.wasPressed()){ mode_ = "analog" ; analog_setup() ;}
  if ( M5.BtnC.wasPressed()){ mode_ = "digital"; digital_setup();}
   
  // gps mode -------------------------------------------------------------
if ( mode_ == "gps" ){                                     // GPS MODE
  if ( initial == 1 ){ gps_setup();}                       // INITIAL SET
  time_date_read();                                        // READ DATA 

  L2[0] = String(gps.date.year()) + "/" + dm_ + "/" + dd_; // DATE
  L2[1] = hh_ + ":" + mm_ + ":" + ss_;                     // TIME
  L2[2] = String(gps.location.lat(),6);                    // LAT
  L2[3] = String(gps.location.lng(),6);                    // LNG
  L2[4] = String(gps.speed.kmph())          + " km/sec";   // SPEED
  L2[5] = String(gps.speed.mps())           + " m/sec";    // SPEED
  L2[6] = String(gps.speed.value())         + " Raw deg";  // CRS
  L2[7] = String(gps.course.deg())          + " deg";      // CRS
  L2[8] = String(gps.altitude.kilometers()) + " km";       // ALT
  L2[9] = String(gps.altitude.meters())     + " m";        // ALT

  M5.Lcd.setFreeFont(FM12); 
  for ( int i = 0; i < 11; i++ ){                          // DISPLAY
    M5.Lcd.setTextColor(BLACK, BLACK);
    M5.Lcd.drawString( L1[i], 100, 0 + ( 24 * i ));        // ERASE
    M5.Lcd.setTextColor( WHITE, BLACK);
    if (gps.location.lat() > 0){ M5.Lcd.setTextColor(GREEN,BLACK);} // RX
    M5.Lcd.drawString( L2[i], 100, 0 + ( 24 * i ));        // DRAW
    L1[i] = L2[i];                                         // SAVE
  } 

  smartDelay(1000);
 }
 
// analog mode  -----------------------------------------------------------
 if ( mode_ == "analog" ){                                 // ANALOG MODE
  time_date_read();                                        // READ DATA  
  sdeg = ss*6;                     // 0-59 -> 0-354   Pre-compute
  mdeg = mm*6+sdeg*0.01666667;     // 0-59 -> 0-360 - includes seconds
  hdeg = hh*30+mdeg*0.0833333;     // 0-11 -> 0-360 - inc min and seconds
  hx = cos((hdeg-90)*0.0174532925); hy = sin((hdeg-90)*0.0174532925);
  mx = cos((mdeg-90)*0.0174532925); my = sin((mdeg-90)*0.0174532925);
  sx = cos((sdeg-90)*0.0174532925); sy = sin((sdeg-90)*0.0174532925);

  M5.Lcd.drawLine(ohx, ohy, 160, 121, TFT_BLACK);          // ERASE HOUR
  M5.Lcd.drawLine(omx, omy, 160, 121, TFT_BLACK);          // ERASE MIN
  M5.Lcd.drawLine(osx, osy, 160, 121, TFT_BLACK);          // ERASE SEC
  ohx = hx*62+161; ohy = hy*62+121;                        // NEW   HOUR
  omx = mx*84+160; omy = my*84+121;                        // NEW   MIN
  osx = sx*90+161; osy = sy*90+121;                        // NEW   MIN
  M5.Lcd.drawLine(ohx, ohy, 160, 121, TFT_WHITE);          // DRAW  HOUR
  M5.Lcd.drawLine(omx, omy, 160, 121, TFT_WHITE);          // DRAW  MIN 
  M5.Lcd.drawLine(osx, osy, 160, 121, TFT_RED  );          // DRAW  SEC
  M5.Lcd.fillCircle(160, 121, 3, TFT_RED);                 // DOT   CENTER
  smartDelay(1000); 
 }
 
// digital mode  ----------------------------------------------------------
 if ( mode_ == "digital" ){                                // DIGITAL MODE
  time_date_read();                                        // READ DATA                   
  L2[0] = String(gps.date.year()) + "/" + dm_ + "/" + dd_; // OLD DATA
  L2[1] = hh_ + ":" + mm_ + ":" + ss_;                     // NEW DATA
  
  M5.Lcd.setFreeFont(FMB24);                               // FONT
  for ( int i = 0; i < 2; i++ ){                           // DISPLAY
    M5.Lcd.setTextColor(TFT_BLACK, TFT_BLACK);             // BLACK
    M5.Lcd.drawString(L1[i], 20, 60 + ( 80 * i ));         // ERASE
    M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);             // WHITE
    if (gps.location.lat() > 0){M5.Lcd.setTextColor(GREEN,BLACK);} // RX
    M5.Lcd.drawString(L2[i], 20, 60 + ( 80 * i ));         // DRAW
    L1[i] = L2[i];                                         // SAVE
  }
 smartDelay(1000); 
 }
 M5.update();
}                                                          // END OF MAIN
//=========================================================================
static void smartDelay(unsigned long ms){
  unsigned long start = millis();
  do{ while (gs.available())
      gps.encode(gs.read());
  } while (millis() - start < ms);
  if (millis() > 5000 && gps.charsProcessed() < 10){none_gps();}
}
//=========================================================================
static uint8_t conv2d(const char* p){
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9'){v = *p - '0';}
  return 10 * v + *++p - '0';
}
//=========================================================================
void gps_setup(){                                          // GPS  SETUP
  M5.Lcd.fillScreen(TFT_BLACK);                            // CLEAR DISPLAY
  M5.Lcd.setFreeFont(FM12);                                // FONT
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);               // GPS  TITLE
  String L[11] = {"DATE","TIME","LAT","LNG","SPEED"        // GPS  TITLE
                    ,"SPEED","CRS","CRS","ALT","ALT"};     // GPS  TITLE
  for ( int i = 0; i < 11; i++ ){
    M5.Lcd.setCursor (     5, 0 + ( 24 * i ));
    M5.Lcd.drawString(L[i],5, 0 + ( 24 * i ));             // DRAW TITLE
  } 
  initial = 0;
}
//=========================================================================
void analog_setup(){                                       // ANALOG SETUP
  M5.Lcd.fillScreen(TFT_BLACK);                            // CLEAR DISPLAY
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
  M5.Lcd.fillCircle( 160, 120, 118, TFT_GREEN);            // CLOCK FACE
  M5.Lcd.fillCircle( 160, 120, 110, TFT_BLACK);            // LOCK FACE
  for(int i = 0; i<360; i+= 30) {                          // 12 LINES
    sx = cos((i-90)*0.0174532925);
    sy = sin((i-90)*0.0174532925);
    x0 = sx*114 + 160; yy0 = sy*114 + 120;
    x1 = sx*100 + 160; yy1 = sy*100 + 120;
    M5.Lcd.drawLine(x0, yy0, x1, yy1, TFT_GREEN);          // DRAW 12 LINES
  }
  for(int i = 0; i<360; i+= 6) {                           // 60 DOTS
    sx = cos((i-90)*0.0174532925);
    sy = sin((i-90)*0.0174532925);
    x0 = sx*102 + 160; yy0 = sy*102 + 120;
    M5.Lcd.drawPixel(x0, yy0, TFT_WHITE);                  // MINUTE
    if(i== 0 || i==180)M5.Lcd.fillCircle(x0,yy0,2,WHITE);  // DOTS
    if(i==90 || i==270)M5.Lcd.fillCircle(x0,yy0,2,WHITE);  // DOTS
  }
  M5.Lcd.fillCircle(160, 121, 3, TFT_RED);                 // DOTS CENTER
  M5.Lcd.drawJpgFile(SD, "/apple_marks/apple_50.jpg");     // apple ICON
  targetTime = millis() + 1000; 
}
//=========================================================================
void digital_setup(){
  M5.Lcd.fillScreen(TFT_BLACK); return;
}
//=========================================================================
void time_date_read(){                           // READ YY.MM.DD, HH,MM,SS
  if (gps.location.lat() > 0){ M5.Lcd.fillCircle(315,5,5,GREEN);} // Rx
  if (gps.location.lat() < 1){ M5.Lcd.fillCircle(315,5,5,RED  );} // not Rx
  ym = gps.date.year();  ym_ = String(ym);
  dm = gps.date.month(); dm_ = String(dm); if (dm < 10){ dm_="0"+dm_;}
  dd = gps.date.day();   dd_ = String(dd); if (dd < 10){ dd_="0"+dd_;}
  ss = gps.time.second();ss_ = String(ss); if (ss < 10){ ss_="0"+ss_;}
  mm = gps.time.minute();mm_ = String(mm); if (mm < 10){ mm_="0"+mm_;}
  hh = gps.time.hour();
  if ( hh < 15 ){ hh = hh + time_set;}     goto t;         // JST ***
  if ( hh > 14 ){ hh = hh - time_set - 6;} goto t;         // JST ***
t:hh_ = String(hh); if (hh < 10){ hh_ = "0" + hh_;}        // ADD ZERO
}
//=========================================================================
void none_gps(){                                           // NONE GPS
  M5.Lcd.setFreeFont(FMB24);                               // FONT
  M5.Lcd.setTextColor(RED, BLACK);
  M5.Lcd.drawString("No GPS data received:", 20, 50);      // MESSAGE
  M5.Lcd.drawString("check wiring", 20, 130);              // MESSAGE
}
//=========================================================================


Written by macsbug

12月 26, 2017 @ 2:37 pm

カテゴリー: ESP32, M5STACK

2件のフィードバック

Subscribe to comments with RSS.

  1. はじめまして!
    macsbug様のGPSCLOCKを使わせてもらっている者です
    質問なんですがAM0~AM9になるとなぜかUTC時刻になってしまうのですが
    これは仕様でしょうか?
    よろしくお願いします。

    もこたん

    6月 17, 2020 at 12:11 am

    • もこたんさん、サイトの訪問をありがとうございます。
      スケッチは UTC24時間に対し 時刻変換が正しく行われていないかも知れません。
      日本時間に変換する場合 UTC/協定世界時とJST/日本標準時の変換と時差の計算が必要で時差は9時間です。
      時刻は 12進法か24進法です。例として 25時はありません。
      そのまま9時間変換すると 時刻が切り替わる 0 ,12,24 等の切り替わりで 正しい値を示さなくなります。
      この点を考慮して 正しい時刻変換を行う必要があります。
      質問に対し これらを考慮した スケッチの検証が必要ですが 他の工作中で時間がとれません。
      ご自身で変換するスケッチを記載するか、GPS時には必ず必要な方法ですので ネットで検索すれば計算方法があるかと思います。

      macsbug

      6月 17, 2020 at 5:33 pm


コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。