Commit 7f7cc24b authored by Bodmer's avatar Bodmer

Add new animated dial example

See Sprite "Animated_dial" example.
parent bdf2c9ba
This diff is collapsed.
......@@ -5,10 +5,6 @@
// graphics are written to the Sprite rather than the TFT.
***************************************************************************************/
// pushRotated support - Bitwise truncation of fixed point integer value V scaled by S
//#define truncateFP(V,S) ((V + (V < 0 ? -1<<(S-1) : 0))>>S)
#define truncateFP(V,S) ((V + (V < 0 ? -1<<(S-1) : 1<<(S-1)))>>S)
class TFT_eSprite : public TFT_eSPI {
public:
......@@ -94,18 +90,22 @@ class TFT_eSprite : public TFT_eSPI {
// Push a rotated copy of Sprite to TFT with optional transparent colour
bool pushRotated(int16_t angle, int32_t transp = -1); // Using fixed point maths
bool pushRotatedHP(int16_t angle, int32_t transp = -1); // Using higher precision floating point maths
// Push a rotated copy of Sprite to another different Sprite with optional transparent colour
bool pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp = -1); // Using fixed point maths
bool pushRotatedHP(TFT_eSprite *spr, int16_t angle, int32_t transp = -1); // Using higher precision floating point maths
// Set and get the pivot point for this Sprite
// Set and get the pivot point for this Sprite
void setPivot(int16_t x, int16_t y);
int16_t getPivotX(void),
getPivotY(void);
// Get the bounding box for a rotated copy of this Sprite
void getRotatedBounds(float sina, float cosa, int16_t w, int16_t h, int16_t xp, int16_t yp,
int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y);
// Get the TFT bounding box for a rotated copy of this Sprite
bool getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y);
// Get the destination Sprite bounding box for a rotated copy of this Sprite
bool getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y,
int16_t *max_x, int16_t *max_y);
// Bounding box support function
void getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp,
int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y);
// Read the colour of a pixel at x,y and return value in 565 format
uint16_t readPixel(int32_t x0, int32_t y0);
......@@ -162,6 +162,8 @@ class TFT_eSprite : public TFT_eSPI {
int16_t _xpivot; // x pivot point coordinate
int16_t _ypivot; // y pivot point coordinate
int32_t _sinra;
int32_t _cosra;
bool _created; // A Sprite has been created and memory reserved
bool _gFont = false;
......
/***************************************************
Arduino TFT graphics library targeted at ESP8266
and ESP32 based boards.
Arduino TFT graphics library targeted at 32 bit
processors such as ESP32, ESP8266 and STM32.
This is a standalone library that contains the
hardware driver, the graphics functions and the
......@@ -10,7 +10,7 @@
size.
Created by Bodmer 2/12/16
Last update by Bodmer 27/12/19
Last update by Bodmer 20/03/20
****************************************************/
......@@ -20,7 +20,7 @@
#include "Processors/TFT_eSPI_ESP32.c"
#elif defined (ESP8266)
#include "Processors/TFT_eSPI_ESP8266.c"
#elif defined (STM32) //(STM32F7xx) //(_VARIANT_ARDUINO_STM32_) stm32_def.h
#elif defined (STM32) // (_VARIANT_ARDUINO_STM32_) stm32_def.h
#include "Processors/TFT_eSPI_STM32.c"
#else
#include "Processors/TFT_eSPI_Generic.c"
......
......@@ -16,7 +16,7 @@
#ifndef _TFT_eSPIH_
#define _TFT_eSPIH_
#define TFT_ESPI_VERSION "2.1.6"
#define TFT_ESPI_VERSION "2.1.7"
/***************************************************************************************
** Section 1: Load required header files
......
// This example draws an animated dial with a rotating needle.
// The dial is a jpeg image, the needle is created using a rotated
// Sprite. The example operates by reading blocks of pixels from the
// TFT, thus the TFT setup must support reading from the TFT CGRAM.
// The sketch operates by creating a copy of the screen block where
// the needle will be drawn, the needle is then drawn on the screen.
// When the needle moves, the original copy of the sreen area is
// pushed to the screen to over-write the needle graphic. A copy
// of the screen where the new position will be drawn is then made
// before drawing the needle in the new postion. This technique
// allows the needle to move over other screen graphics.
// The sketch calculates the size of the buffer memory required and
// reserves the memory for the TFT block copy.
// Created by Bodmer 17/3/20 as an example to the TFT_eSPI library:
// https://github.com/Bodmer/TFT_eSPI
#define NEEDLE_LENGTH 35 // Visible length
#define NEEDLE_WIDTH 5 // Width of needle - make it an odd number
#define NEEDLE_RADIUS 90 // Radius at tip
#define NEEDLE_COLOR1 TFT_MAROON // Needle periphery colour
#define NEEDLE_COLOR2 TFT_RED // Needle centre colour
#define DIAL_CENTRE_X 120
#define DIAL_CENTRE_Y 120
// Font attached to this sketch
#include "NotoSansBold36.h"
#define AA_FONT_LARGE NotoSansBold36
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite needle = TFT_eSprite(&tft); // Sprite object for needle
TFT_eSprite spr = TFT_eSprite(&tft); // Sprite for meter reading
// Jpeg image array attached to this sketch
#include "dial.h"
// Include the jpeg decoder library
#include <TJpg_Decoder.h>
uint16_t* tft_buffer;
bool buffer_loaded = false;
uint16_t spr_width = 0;
// =======================================================================================
// This function will be called during decoding of the jpeg file
// =======================================================================================
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
// Stop further decoding as image is running off bottom of screen
if ( y >= tft.height() ) return 0;
// This function will clip the image block rendering automatically at the TFT boundaries
tft.pushImage(x, y, w, h, bitmap);
// Return 1 to decode next block
return 1;
}
// =======================================================================================
// Setup
// =======================================================================================
void setup() {
Serial.begin(115200); // Debug only
// The byte order can be swapped (set true for TFT_eSPI)
TJpgDec.setSwapBytes(true);
// The jpeg decoder must be given the exact name of the rendering function above
TJpgDec.setCallback(tft_output);
tft.begin();
tft.setRotation(0);
tft.fillScreen(TFT_BLACK);
// Draw the dial
TJpgDec.drawJpg(0, 0, dial, sizeof(dial));
tft.drawCircle(DIAL_CENTRE_X, DIAL_CENTRE_Y, NEEDLE_RADIUS-NEEDLE_LENGTH, TFT_DARKGREY);
// Load the font and create the Sprite for reporting the value
spr.loadFont(AA_FONT_LARGE);
spr_width = spr.textWidth("188");
spr.createSprite(spr_width, spr.fontHeight());
uint16_t bg_color = tft.readPixel(120, 120); // Get colour from dial centre
spr.fillSprite(bg_color);
spr.setTextColor(TFT_WHITE, bg_color);
spr.setTextDatum(MC_DATUM);
spr.setTextPadding(spr_width);
spr.drawNumber(0, spr_width/2, 0);
spr.pushSprite(DIAL_CENTRE_X - spr_width / 2, DIAL_CENTRE_Y - spr.fontHeight() / 2);
// Plot the label text
tft.setTextColor(TFT_WHITE, bg_color);
tft.setTextDatum(MC_DATUM);
tft.drawString("(degrees)", DIAL_CENTRE_X, DIAL_CENTRE_Y + 46, 2);
// Define where the needle pivot point is on the TFT before
// creating the needle so boundary calculation is correct
tft.setPivot(DIAL_CENTRE_X, DIAL_CENTRE_Y);
// Create the needle Sprite
createNeedle();
// Reset needle position to 0
plotNeedle(0, 0);
delay(2000);
}
// =======================================================================================
// Loop
// =======================================================================================
void loop() {
uint16_t angle = random(241); // random speed in range 0 to 240
// Plot needle at random angle in range 0 to 240, speed 40ms per increment
plotNeedle(angle, 30);
// Pause at new position
delay(2500);
}
// =======================================================================================
// Create the needle Sprite
// =======================================================================================
void createNeedle(void)
{
needle.setColorDepth(16);
needle.createSprite(NEEDLE_WIDTH, NEEDLE_LENGTH); // create the needle Sprite
needle.fillSprite(TFT_BLACK); // Fill with black
// Define needle pivot point relative to top left corner of Sprite
uint16_t piv_x = NEEDLE_WIDTH / 2; // pivot x in Sprite (middle)
uint16_t piv_y = NEEDLE_RADIUS; // pivot y in Sprite
needle.setPivot(piv_x, piv_y); // Set pivot point in this Sprite
// Draw the red needle in the Sprite
needle.fillRect(0, 0, NEEDLE_WIDTH, NEEDLE_LENGTH, TFT_MAROON);
needle.fillRect(1, 1, NEEDLE_WIDTH-2, NEEDLE_LENGTH-2, TFT_RED);
// Bounding box parameters to be populated
int16_t min_x;
int16_t min_y;
int16_t max_x;
int16_t max_y;
// Work out the worst case area that must be grabbed from the TFT,
// this is at a 45 degree rotation
needle.getRotatedBounds(45, &min_x, &min_y, &max_x, &max_y);
// Calculate the size and allocate the buffer for the grabbed TFT area
tft_buffer = (uint16_t*) malloc( ((max_x - min_x) + 2) * ((max_y - min_y) + 2) * 2 );
}
// =======================================================================================
// Move the needle to a new position
// =======================================================================================
void plotNeedle(int16_t angle, uint16_t ms_delay)
{
static int16_t old_angle = -120; // Starts at -120 degrees
// Trig values for the rotation
int32_t sinra;
int32_t cosra;
// Bounding box parameters
static int16_t min_x;
static int16_t min_y;
static int16_t max_x;
static int16_t max_y;
if (angle < 0) angle = 0; // Limit angle to emulate needle end stops
if (angle > 240) angle = 240;
angle -= 120; // Starts at -120 degrees
// Move the needle until new angle reached
while (angle != old_angle || !buffer_loaded) {
if (old_angle < angle) old_angle++;
else old_angle--;
// Only plot needle at even values to improve plotting performance
if ( (old_angle & 1) == 0)
{
if (buffer_loaded) {
// Paste back the original needle free image area
tft.pushRect(min_x, min_y, 1 + max_x - min_x, 1 + max_y - min_y, tft_buffer);
}
if ( needle.getRotatedBounds(old_angle, &min_x, &min_y, &max_x, &max_y) )
{
// Grab a copy of the area before needle is drawn
tft.readRect(min_x, min_y, 1 + max_x - min_x, 1 + max_y - min_y, tft_buffer);
buffer_loaded = true;
}
// Draw the needle in the new postion, black in needle image is transparent
needle.pushRotated(old_angle, TFT_BLACK);
// Wait before next update
delay(ms_delay);
}
// Update the number at the centre of the dial
spr.drawNumber(old_angle+120, spr_width/2, 0);
spr.pushSprite(120 - spr_width / 2, 120 - spr.fontHeight() / 2);
// Slow needle down slightly as it approaches the new position
if (abs(old_angle - angle) < 10) ms_delay += ms_delay / 5;
}
}
// =======================================================================================
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "TFT_eSPI",
"version": "2.1.6",
"version": "2.1.7",
"keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140",
"description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32",
"repository":
......
name=TFT_eSPI
version=2.1.6
version=2.1.7
author=Bodmer
maintainer=Bodmer
sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment