Friday 4 September 2020

GPS clock, colour 2.4" TFT display

Note: all files and sketches on M0IFA.me

What a struggle! These TFT displays are awkward to use. Especially when you want to display a clock face and hands that move round, or for that matter to write text/numbers on the display and update them. To move a hand you must delete the previous line you have drawn and draw a new one. BUT, you cannot let the second hand, as it moves round, delete the minute or hour hand as it passes by...

Same for the time. When the hours, minutes or seconds change you have to write a black box over the original number and then the new time. Fortunately the simple Adafruit font does this by allowing you to define both the font colour and the background colour. The negative side of using the simple font is that it is very blocky and only small sizes can be used.

MY CLOCK

This is my display. This TFT has 5V operation and I am running it quite happily on the Arduino Mega at 5V.

The display is complete after I added a calculation of
day of the week and the Maidenhead Locator.

The TFT has an ILI9341 controller chip. This is supported by the Adafruit_GFX.h library with the driver Adafruit_ILI9341.h. This graphic library is not very extensive, but does have to simple things I needed, filled rectangles, circles, horizontal and vertical lines, sloping lines, print of numbers and text.

The interesting code for the clock hands is this:

 - x, y = centre of hands

 - r = radius of clock

 - ch, h etc are the colours and hour, min, sec values

Typical usage may be

dispHands(110, 110, 100, WHITE, hrs, WHITE, mns, RED, sec);

This is the function:

// HANDS

// display hands x, y, r, ch, h, cm, m, cs, s

void dispHands(int16_t x, int16_t y, int16_t r, uint16_t ch, uint8_t h, uint16_t cm, uint8_t m,  uint16_t cs, uint8_t s) {

 uint16_t rh, rm, rs; // hand lengths

 static uint8_t xh, xm, xs; // prev hms data


  // hand lengths, % of radius

  rh = r * 60/100;

  rm = r * 80/100;

  rs = r * 90/100;


  // proportional move of hour hand

  h = h * 5 + m / 12.0; // 60 min / 12 hours, plus minutes / 12


  // if hms change erase old hand

  if (h != xh) {

  tft.drawLine(x, y, x + rh * sin((6.282 * xh / 60.0)), y - rh * cos((6.282 * xh /60.0)), BLACK);}

  if (m != xm) {

  tft.drawLine(x, y, x + rm * sin((6.282 * xm / 60.0)), y - rm * cos((6.282 * xm / 60.0)), BLACK);}

  if (s != xs) {

  tft.drawLine(x, y, x + rs * sin((6.282 * xs / 60.0)), y - rs * cos((6.282 * xs / 60.0)), BLACK);}


  // then draw current times

  tft.drawLine(x, y, x + rh * sin((6.282 * h / 60.0)), y - rh * cos((6.282 * h / 60.0)), ch);

  tft.drawLine(x, y, x + rm * sin((6.282 * m / 60.0)), y - rm * cos((6.282 * m / 60.0)), cm);

  tft.drawLine(x, y, x + rs * sin((6.282 * s / 60.0)), y - rs * cos((6.282 * s / 60.0)), cs);


  // remember current time

  xh = h;

  xm = m;

  xs = s;

}

Just to run though it

1. Three static variables for hour, minute & second are created in the function, these are remembered between calls. They store the "previous" values.
2. The length of the hands is set as 60, 80, 90% or the radius.
3. Hours are converted to 60ths and intermediate minutes added, so the hour hand slowly goes round with the minutes
4. A check is made to see if anything has been updated, if so the old hand is erased (written over in BLACK colour)
5. The new hands are written. All of them MUST be written as an erase of the secondhand as it passes over the minute of hour hand will "black" it out!
6. Finally the current values are stored for the next call.

All the date & time and display functions have been written in a "Tft.h" header file, here. And the sketch code TFT_ADA_MEGA.ino is here. Name started off as "TFT using Adafruit" library, but it stuck.

TIME
So where does the time come from? GPS of course, and this is relatively easy to do using a GPS module and the TinyGPS library. See the sketch for the code.

Here it is running on an Arduino Mega
Display: CLK 13, MOSI 11, RES 8, DC 9, [CS 10, MISO 12 not used]
GPS: RX 18, TX 19

UNO or NANO
The clock will work equally well using an UNO or NANO. But here you will have to implement the serial port for the GPS in software using the SoftwareSerial library, part of the Arduino IDE installation. The sketch is TFT_ADA_NANO, shown working on the UNO as I don't have a spare Nano around at the moment...


The display has a bit of a lag as the UNO (and NANO) are slower than the MEGA that I originally used.

QSO

The project has obvious use in the Amateur Radio shack for logging QSOs and checking the timing of transmissions - including for example FT8 which must start +/- 1 sec from the 15 seconds boundaries.


1 comment:

Bill said...

Hello

I used your code for running my analog clock using a 2.8" ili9341 tft display. It works great and I thank you for the code. However, I found the precision for calculating the hour hand can be improved.

Your code:
h = h * 5 + m / 12.0;
tft.drawLine(x, y, x + rh * sin((6.282 * h / 60.0)), y - rh * cos((6.282 * h / 60.0)), ch);


My code:
H = h * 60 + m; (H is a uint16_t)
tft.drawLine(x, y, x + rh * sin((6.282 * H / 720.0)), y - rh * cos((6.282 * H / 720.0)), ch);

Explanation:
Dividing m(a uint8_t) by 12 results in a quantized value for the hour hand position for all minute times non-divisible by 12.