GPSモジュールを使ったDigital Clockの製作、



 18"TFT-LCD(ST7735)に時刻・日付・曜日を表示しました。

 18"TFT-LCD(ST7735)で、GPSモジュールの時刻・日付を利用した Digital Clockを製作しました。



 以前、ESP32とGPSモジュールを使い表示にLED-MatrixPanelを使用した時計を作成しました。 (当ホームページのESP32の項目を参照)

 今回は、Arduino NANOとGPSモジュールを使い、表示に18"128x160 RGB TFT-LCD(ST7735)を使いました。

このTFT-LCDは、廉価なので購入しましたが、テキストの消去に手間取りました。テキストを表示して、次のテキストを表示すると 重ねて表示されます。
ヘッダーファイルのTFT.hは、テキストのみを消去する関数がありません。
調べたところ、次の2つの方法しかないようです。

①前のテキストを消すために、同じテキスト・同じ位置で背景と同じ色のテキストを書いて前のテキストを消し、それから新たなテキストを表示する

②前のテキストが入るような背景色の四角形で塗りつぶしてから、新たなテキストを表示する。

 ほかに良い方法があればよいのですが、今のところこの方法しか見つかりませんでした。今回は②の方法を使いました。

以下にその概要を記します。



  完成した時計(動画)


 GPSモジュールからデータを受信して、時間・日付・曜日を表示しています。
時・分・秒をLCDの上部に表示し、下に年・月・日・曜日を表示しています。 時・分・秒、年、日付の表示が変わるごとに、fillRect()を使って前の表示を削除しています。






  使用した部品


1.Arduino NANO




2.GPSモジュール(GY-GPS 8M V3)



3.TFT-LCD(18"128x160 RGB TFT-LCD(ST7735)



4.降圧電源モジュール(ASM1117-3.3
 このモジュールは、5Vを3.3Vにステップダウンします。

これを使用した理由は、Arduino NANOの3.3VをGPSモジュールとTFT-LCDの両方で使用すると、電流容量が大きく LCDのチラツキが生じるため、LCDの電源は、5VからASM1117で3.3Vにステップダウンして使うようにしました。



5.ケースは、3Dプリンターで作成しました。




  配線図


配線図です。(画像をコピーしてペイント等で拡大表示してください。)






 Arduino IDEで使用するヘッダーファイルの取得


「ツール」、「ライブラリを管理…」から次のライブラリをインストールします。
*TinyGPS++.hは、TinyGPSPlus by Mikal Hert

*Adafruit_GFX.hは、Adafruit GFX Library

*Adafruit_ST7735.hは、Adafruit ST7735 and ST7789 LLibrary

*TimeLib.hは、次のgithubからインストールします。
  https://github.com/PaulStoffregen/Time




  スケッチ


 参考として以下に、スケッチプログラムを掲載しておきます。
 秒、分、時刻の消去は、GPSから受信したgps.time.second()、gps.time.minute()、gps.time.hour()の値が変更されたときに、 fillRectで前のテキストを消去するようにしました.
 電源を入れた初期段階では、LCDに表示される日付のテキストが重なって表示される 場合があるので、日付の消去は、day()とyear()が変更されたときにfillRectで前のテキストを消去するようにしました。

//Arduino GPS Clock LCD_Adafruit
#include <TinyGPS++.h>
#include <TimeLib.h>
#include <SoftwareSerial.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

TinyGPSPlus gps;
#define GPS_BAUDRATE 9600
#define time_offset 32400
SoftwareSerial mySerial(3, 2); //RX,TX

#define CS    10
#define DC     9
#define RST    8
Adafruit_ST7735 tft = Adafruit_ST7735(CS, DC, RST);

char Timeh[]  = "00";
char Timem[]  = "00";
char Times[]  = "00";
char DateY[]  = "2000";
char Date[]  = "00/00";
byte Second, Minute, Hour, Day, Month;
byte last_second, last_minute, last_hour, last_day, last_month;
int Year, last_year;

int xoff=6;
int yoff=20;

void setup() {
  //Serial.begin(115200);
  mySerial.begin(GPS_BAUDRATE);
  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(ST77XX_BLACK);
  tft.setRotation(1);
  tft.setTextWrap(false);
}  

void loop() 
{
  while (mySerial.available() > 0)
  {
    if (gps.encode(mySerial.read()))
    {
      if (gps.time.isValid())
      {
        Second = gps.time.second();
        Minute = gps.time.minute();
        Hour   = gps.time.hour();
      }

      if (gps.date.isValid())
      {
        Day   = gps.date.day();
        Month = gps.date.month();
        Year  = gps.date.year();
      }

      if(last_second != Second)
      {
        tft.fillRect(118+xoff, 12+yoff, 146+xoff, 40+yoff, ST7735_BLACK); //Clear Times
        
        last_second = Second;
      
        if(last_minute != Minute)
        {
          tft.fillRect(67+xoff, -2+yoff, 117+xoff, 32+yoff, ST7735_BLACK); //Clear Timem
          last_minute = Minute;
        }

        if(last_hour != Hour)
        {
          tft.fillRect(-2+xoff, -2+yoff, 56+xoff, 32+yoff, ST7735_BLACK); //Clear Timeh
          last_hour = Hour;
        }
      
        setTime(Hour, Minute, Second, Day, Month, Year);
        adjustTime(time_offset);
      
        // update time
        Times[0] = second() / 10 + '0';
        Times[1] = second() % 10 + '0';
        Timem[0]  = minute() / 10 + '0';
        Timem[1] = minute() % 10 + '0';
        Timeh[0]  = hour()   / 10 + '0';
        Timeh[1]  = hour()   % 10 + '0';
            
        // update date array
        DateY[2] = (year()  / 10) % 10 + '0';
        DateY[3] =  year()  % 10 + '0';
        Date[0]  = month() / 10 + '0';
        Date[1] =  month() % 10 + '0';
        Date[3]  =  day()   / 10 + '0';
        Date[4]  =  day()   % 10 + '0';

        if(last_day == 0 || last_day != day())
        {
          tft.fillRect(22+xoff, 78+yoff, 150+xoff, 100+yoff, ST7735_BLACK);//Clear Date(week)
          last_day = day();
        }

        if(last_year == 0 || last_year != year())
        {
          tft.fillRect(-2+xoff, 40+yoff, 50+xoff, 62+yoff, ST7735_BLACK);//Clear Year
          last_year = year();  
        }
        
        tft.setTextColor(ST7735_YELLOW);
        tft.setTextSize(4);
        tft.setCursor(xoff, yoff);
        tft.println(Timeh);
        tft.setCursor(47+xoff, yoff);
        tft.println(":");

        tft.setCursor(69+xoff, yoff);
        tft.println(Timem);

        tft.setTextSize(2);
	      tft.setCursor(120+xoff, 14+yoff);
	      tft.println(Times);

        tft.setCursor(24+xoff, 80+yoff);
        tft.println(Date);

	      tft.setTextColor(ST7735_GREEN);
        tft.setCursor(xoff, 50+yoff);
        tft.println(DateY);
    
        print_wday(weekday());
      }  
      
    }
  }

  if (millis() > 5000 && gps.charsProcessed() < 10)
  {  
    tft.setTextSize(2);
    tft.setTextColor(ST7735_RED);
    tft.setCursor(6, 72);
    tft.println("No GPSdata");
  }
}

void print_wday(byte wday)
{
  tft.setCursor(87+xoff, 80+yoff);
  switch(wday)
  {
    case 1:  tft.println("(SUN)");   break;
    case 2:  tft.println("(MON)");   break;
    case 3:  tft.println("(TUE)");   break;
    case 4:  tft.println("(WED)");   break;
    case 5:  tft.println("(THU)");   break;
    case 6:  tft.println("(FRI)");   break;
    default: tft.println("(SAT)");
  }  
}