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 |
Animated_dial.ino (7794B)
1 // This example draws an animated dial with a rotating needle. 2 3 // The dial is a jpeg image, the needle is created using a rotated 4 // Sprite. The example operates by reading blocks of pixels from the 5 // TFT, thus the TFT setup must support reading from the TFT CGRAM. 6 7 // The sketch operates by creating a copy of the screen block where 8 // the needle will be drawn, the needle is then drawn on the screen. 9 // When the needle moves, the original copy of the screen area is 10 // pushed to the screen to over-write the needle graphic. A copy 11 // of the screen where the new position will be drawn is then made 12 // before drawing the needle in the new position. This technique 13 // allows the needle to move over other screen graphics. 14 15 // The sketch calculates the size of the buffer memory required and 16 // reserves the memory for the TFT block copy. 17 18 // Created by Bodmer 17/3/20 as an example to the TFT_eSPI library: 19 // https://github.com/Bodmer/TFT_eSPI 20 21 #define NEEDLE_LENGTH 35 // Visible length 22 #define NEEDLE_WIDTH 5 // Width of needle - make it an odd number 23 #define NEEDLE_RADIUS 90 // Radius at tip 24 #define NEEDLE_COLOR1 TFT_MAROON // Needle periphery colour 25 #define NEEDLE_COLOR2 TFT_RED // Needle centre colour 26 #define DIAL_CENTRE_X 120 27 #define DIAL_CENTRE_Y 120 28 29 // Font attached to this sketch 30 #include "NotoSansBold36.h" 31 #define AA_FONT_LARGE NotoSansBold36 32 33 #include <TFT_eSPI.h> 34 TFT_eSPI tft = TFT_eSPI(); 35 TFT_eSprite needle = TFT_eSprite(&tft); // Sprite object for needle 36 TFT_eSprite spr = TFT_eSprite(&tft); // Sprite for meter reading 37 38 // Jpeg image array attached to this sketch 39 #include "dial.h" 40 41 // Include the jpeg decoder library 42 #include <TJpg_Decoder.h> 43 44 uint16_t* tft_buffer; 45 bool buffer_loaded = false; 46 uint16_t spr_width = 0; 47 uint16_t bg_color =0; 48 // ======================================================================================= 49 // This function will be called during decoding of the jpeg file 50 // ======================================================================================= 51 bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 52 { 53 // Stop further decoding as image is running off bottom of screen 54 if ( y >= tft.height() ) return 0; 55 56 // This function will clip the image block rendering automatically at the TFT boundaries 57 tft.pushImage(x, y, w, h, bitmap); 58 59 // Return 1 to decode next block 60 return 1; 61 } 62 63 // ======================================================================================= 64 // Setup 65 // ======================================================================================= 66 void setup() { 67 Serial.begin(115200); // Debug only 68 69 // The byte order can be swapped (set true for TFT_eSPI) 70 TJpgDec.setSwapBytes(true); 71 72 // The jpeg decoder must be given the exact name of the rendering function above 73 TJpgDec.setCallback(tft_output); 74 75 tft.begin(); 76 tft.setRotation(0); 77 tft.fillScreen(TFT_BLACK); 78 79 // Draw the dial 80 TJpgDec.drawJpg(0, 0, dial, sizeof(dial)); 81 tft.drawCircle(DIAL_CENTRE_X, DIAL_CENTRE_Y, NEEDLE_RADIUS-NEEDLE_LENGTH, TFT_DARKGREY); 82 83 // Load the font and create the Sprite for reporting the value 84 spr.loadFont(AA_FONT_LARGE); 85 spr_width = spr.textWidth("777"); // 7 is widest numeral in this font 86 spr.createSprite(spr_width, spr.fontHeight()); 87 bg_color = tft.readPixel(120, 120); // Get colour from dial centre 88 spr.fillSprite(bg_color); 89 spr.setTextColor(TFT_WHITE, bg_color, true); 90 spr.setTextDatum(MC_DATUM); 91 spr.setTextPadding(spr_width); 92 spr.drawNumber(0, spr_width/2, spr.fontHeight()/2); 93 spr.pushSprite(DIAL_CENTRE_X - spr_width / 2, DIAL_CENTRE_Y - spr.fontHeight() / 2); 94 95 // Plot the label text 96 tft.setTextColor(TFT_WHITE, bg_color); 97 tft.setTextDatum(MC_DATUM); 98 tft.drawString("(degrees)", DIAL_CENTRE_X, DIAL_CENTRE_Y + 48, 2); 99 100 // Define where the needle pivot point is on the TFT before 101 // creating the needle so boundary calculation is correct 102 tft.setPivot(DIAL_CENTRE_X, DIAL_CENTRE_Y); 103 104 // Create the needle Sprite 105 createNeedle(); 106 107 // Reset needle position to 0 108 plotNeedle(0, 0); 109 110 delay(2000); 111 } 112 113 // ======================================================================================= 114 // Loop 115 // ======================================================================================= 116 void loop() { 117 uint16_t angle = random(241); // random speed in range 0 to 240 118 119 // Plot needle at random angle in range 0 to 240, speed 40ms per increment 120 plotNeedle(angle, 30); 121 122 // Pause at new position 123 delay(2500); 124 } 125 126 // ======================================================================================= 127 // Create the needle Sprite 128 // ======================================================================================= 129 void createNeedle(void) 130 { 131 needle.setColorDepth(16); 132 needle.createSprite(NEEDLE_WIDTH, NEEDLE_LENGTH); // create the needle Sprite 133 134 needle.fillSprite(TFT_BLACK); // Fill with black 135 136 // Define needle pivot point relative to top left corner of Sprite 137 uint16_t piv_x = NEEDLE_WIDTH / 2; // pivot x in Sprite (middle) 138 uint16_t piv_y = NEEDLE_RADIUS; // pivot y in Sprite 139 needle.setPivot(piv_x, piv_y); // Set pivot point in this Sprite 140 141 // Draw the red needle in the Sprite 142 needle.fillRect(0, 0, NEEDLE_WIDTH, NEEDLE_LENGTH, TFT_MAROON); 143 needle.fillRect(1, 1, NEEDLE_WIDTH-2, NEEDLE_LENGTH-2, TFT_RED); 144 145 // Bounding box parameters to be populated 146 int16_t min_x; 147 int16_t min_y; 148 int16_t max_x; 149 int16_t max_y; 150 151 // Work out the worst case area that must be grabbed from the TFT, 152 // this is at a 45 degree rotation 153 needle.getRotatedBounds(45, &min_x, &min_y, &max_x, &max_y); 154 155 // Calculate the size and allocate the buffer for the grabbed TFT area 156 tft_buffer = (uint16_t*) malloc( ((max_x - min_x) + 2) * ((max_y - min_y) + 2) * 2 ); 157 } 158 159 // ======================================================================================= 160 // Move the needle to a new position 161 // ======================================================================================= 162 void plotNeedle(int16_t angle, uint16_t ms_delay) 163 { 164 static int16_t old_angle = -120; // Starts at -120 degrees 165 166 // Bounding box parameters 167 static int16_t min_x; 168 static int16_t min_y; 169 static int16_t max_x; 170 static int16_t max_y; 171 172 if (angle < 0) angle = 0; // Limit angle to emulate needle end stops 173 if (angle > 240) angle = 240; 174 175 angle -= 120; // Starts at -120 degrees 176 177 // Move the needle until new angle reached 178 while (angle != old_angle || !buffer_loaded) { 179 180 if (old_angle < angle) old_angle++; 181 else old_angle--; 182 183 // Only plot needle at even values to improve plotting performance 184 if ( (old_angle & 1) == 0) 185 { 186 if (buffer_loaded) { 187 // Paste back the original needle free image area 188 tft.pushRect(min_x, min_y, 1 + max_x - min_x, 1 + max_y - min_y, tft_buffer); 189 } 190 191 if ( needle.getRotatedBounds(old_angle, &min_x, &min_y, &max_x, &max_y) ) 192 { 193 // Grab a copy of the area before needle is drawn 194 tft.readRect(min_x, min_y, 1 + max_x - min_x, 1 + max_y - min_y, tft_buffer); 195 buffer_loaded = true; 196 } 197 198 // Draw the needle in the new position, black in needle image is transparent 199 needle.pushRotated(old_angle, TFT_BLACK); 200 201 // Wait before next update 202 delay(ms_delay); 203 } 204 205 // Update the number at the centre of the dial 206 spr.setTextColor(TFT_WHITE, bg_color, true); 207 spr.drawNumber(old_angle+120, spr_width/2, spr.fontHeight()/2); 208 spr.pushSprite(120 - spr_width / 2, 120 - spr.fontHeight() / 2); 209 210 // Slow needle down slightly as it approaches the new position 211 if (abs(old_angle - angle) < 10) ms_delay += ms_delay / 5; 212 } 213 } 214 215 // =======================================================================================