acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

Anti-aliased_Clock.ino (5751B)

      1 // Sketch to draw an analogue clock on the screen
      2 // This uses anti-aliased drawing functions that are built into TFT_eSPI
      3 
      4 // Anti-aliased lines can be drawn with sub-pixel resolution and permit lines to be
      5 // drawn with less jaggedness.
      6 
      7 // Based on a sketch by DavyLandman:
      8 // https://github.com/Bodmer/TFT_eSPI/issues/905
      9 
     10 
     11 #define WIFI_SSID      "Your_SSID"
     12 #define WIFI_PASSWORD  "Your_Password"
     13 
     14 #include <Arduino.h>
     15 #include <TFT_eSPI.h> // Master copy here: https://github.com/Bodmer/TFT_eSPI
     16 #include <SPI.h>
     17 
     18 #include "NotoSansBold15.h"
     19 
     20 TFT_eSPI tft = TFT_eSPI();  // Invoke library, pins defined in User_Setup.h
     21 TFT_eSprite face = TFT_eSprite(&tft);
     22 
     23 #define CLOCK_X_POS 10
     24 #define CLOCK_Y_POS 10
     25 
     26 #define CLOCK_FG   TFT_SKYBLUE
     27 #define CLOCK_BG   TFT_NAVY
     28 #define SECCOND_FG TFT_RED
     29 #define LABEL_FG   TFT_GOLD
     30 
     31 #define CLOCK_R       127.0f / 2.0f // Clock face radius (float type)
     32 #define H_HAND_LENGTH CLOCK_R/2.0f
     33 #define M_HAND_LENGTH CLOCK_R/1.4f
     34 #define S_HAND_LENGTH CLOCK_R/1.3f
     35 
     36 #define FACE_W CLOCK_R * 2 + 1
     37 #define FACE_H CLOCK_R * 2 + 1
     38 
     39 // Calculate 1 second increment angles. Hours and minute hand angles
     40 // change every second so we see smooth sub-pixel movement
     41 #define SECOND_ANGLE 360.0 / 60.0
     42 #define MINUTE_ANGLE SECOND_ANGLE / 60.0
     43 #define HOUR_ANGLE   MINUTE_ANGLE / 12.0
     44 
     45 // Sprite width and height
     46 #define FACE_W CLOCK_R * 2 + 1
     47 #define FACE_H CLOCK_R * 2 + 1
     48 
     49 // Time h:m:s
     50 uint8_t h = 0, m = 0, s = 0;
     51 
     52 float time_secs = h * 3600 + m * 60 + s;
     53 
     54 // Load header after time_secs global variable has been created so it is in scope
     55 #include "NTP_Time.h" // Attached to this sketch, see that tab for library needs
     56 
     57 // Time for next tick
     58 uint32_t targetTime = 0;
     59 
     60 // =========================================================================
     61 // Setup
     62 // =========================================================================
     63 void setup() {
     64   Serial.begin(115200);
     65   Serial.println("Booting...");
     66 
     67   // Initialise the screen
     68   tft.init();
     69 
     70   // Ideally set orientation for good viewing angle range because
     71   // the anti-aliasing effectiveness varies with screen viewing angle
     72   // Usually this is when screen ribbon connector is at the bottom
     73   tft.setRotation(0);
     74   tft.fillScreen(TFT_BLACK);
     75 
     76   // Create the clock face sprite
     77   //face.setColorDepth(8); // 8 bit will work, but reduces effectiveness of anti-aliasing
     78   face.createSprite(FACE_W, FACE_H);
     79 
     80   // Only 1 font used in the sprite, so can remain loaded
     81   face.loadFont(NotoSansBold15);
     82 
     83   // Draw the whole clock - NTP time not available yet
     84   renderFace(time_secs);
     85 
     86   targetTime = millis() + 100;
     87 }
     88 
     89 // =========================================================================
     90 // Loop
     91 // =========================================================================
     92 void loop() {
     93   // Update time periodically
     94   if (targetTime < millis()) {
     95 
     96     // Update next tick time in 100 milliseconds for smooth movement
     97     targetTime = millis() + 100;
     98 
     99     // Increment time by 100 milliseconds
    100     time_secs += 0.100;
    101 
    102     // Midnight roll-over
    103     if (time_secs >= (60 * 60 * 24)) time_secs = 0;
    104 
    105     // All graphics are drawn in sprite to stop flicker
    106     renderFace(time_secs);
    107 
    108     // Request time from NTP server and synchronise the local clock
    109     // (clock may pause since this may take >100ms)
    110     syncTime();
    111   }
    112 }
    113 
    114 // =========================================================================
    115 // Draw the clock face in the sprite
    116 // =========================================================================
    117 static void renderFace(float t) {
    118   float h_angle = t * HOUR_ANGLE;
    119   float m_angle = t * MINUTE_ANGLE;
    120   float s_angle = t * SECOND_ANGLE;
    121 
    122   // The face is completely redrawn - this can be done quickly
    123   face.fillSprite(TFT_BLACK);
    124 
    125   // Draw the face circle
    126   face.fillSmoothCircle( CLOCK_R, CLOCK_R, CLOCK_R, CLOCK_BG );
    127 
    128   // Set text datum to middle centre and the colour
    129   face.setTextDatum(MC_DATUM);
    130 
    131   // The background colour will be read during the character rendering
    132   face.setTextColor(CLOCK_FG, CLOCK_BG);
    133 
    134   // Text offset adjustment
    135   constexpr uint32_t dialOffset = CLOCK_R - 10;
    136 
    137   float xp = 0.0, yp = 0.0; // Use float pixel position for smooth AA motion
    138 
    139   // Draw digits around clock perimeter
    140   for (uint32_t h = 1; h <= 12; h++) {
    141     getCoord(CLOCK_R, CLOCK_R, &xp, &yp, dialOffset, h * 360.0 / 12);
    142     face.drawNumber(h, xp, 2 + yp);
    143   }
    144 
    145   // Add text (could be digital time...)
    146   face.setTextColor(LABEL_FG, CLOCK_BG);
    147   face.drawString("TFT_eSPI", CLOCK_R, CLOCK_R * 0.75);
    148 
    149   // Draw minute hand
    150   getCoord(CLOCK_R, CLOCK_R, &xp, &yp, M_HAND_LENGTH, m_angle);
    151   face.drawWideLine(CLOCK_R, CLOCK_R, xp, yp, 6.0f, CLOCK_FG);
    152   face.drawWideLine(CLOCK_R, CLOCK_R, xp, yp, 2.0f, CLOCK_BG);
    153 
    154   // Draw hour hand
    155   getCoord(CLOCK_R, CLOCK_R, &xp, &yp, H_HAND_LENGTH, h_angle);
    156   face.drawWideLine(CLOCK_R, CLOCK_R, xp, yp, 6.0f, CLOCK_FG);
    157   face.drawWideLine(CLOCK_R, CLOCK_R, xp, yp, 2.0f, CLOCK_BG);
    158 
    159   // Draw the central pivot circle
    160   face.fillSmoothCircle(CLOCK_R, CLOCK_R, 4, CLOCK_FG);
    161 
    162   // Draw cecond hand
    163   getCoord(CLOCK_R, CLOCK_R, &xp, &yp, S_HAND_LENGTH, s_angle);
    164   face.drawWedgeLine(CLOCK_R, CLOCK_R, xp, yp, 2.5, 1.0, SECCOND_FG);
    165   face.pushSprite(5, 5, TFT_TRANSPARENT);
    166 }
    167 
    168 // =========================================================================
    169 // Get coordinates of end of a line, pivot at x,y, length r, angle a
    170 // =========================================================================
    171 // Coordinates are returned to caller via the xp and yp pointers
    172 #define DEG2RAD 0.0174532925
    173 void getCoord(int16_t x, int16_t y, float *xp, float *yp, int16_t r, float a)
    174 {
    175   float sx1 = cos( (a - 90) * DEG2RAD);
    176   float sy1 = sin( (a - 90) * DEG2RAD);
    177   *xp =  sx1 * r + x;
    178   *yp =  sy1 * r + y;
    179 }