Creating a moving needle for a 1.28" TFT gauge

I'm in the process of creating a gauge using a 1.28" TFT and an R3 UNO.
So far I've managed to follow the documentation here: Waveshare.com and create the background for my gauge.

The issue I have is that when the needle is moving it changes the background graphics, and I don't know how to revert back to my background without redoing the background after each movement of the needle.

Is there a way to copy colors from the TFT's screen?
If there is then my idea is to just copy the colors from the line where the needle is going to be before drawing the needle and then when it moves to just paste the colors back.


On approach is redraw the previous needle path in background color, then draw the new needle position. However, as you can see, that will create a problem for any scale markings that the needle overwrites. You can avoid that by making the needle shorter.

it's common practice to redraw the entire screen.

should limit the frequency to someting the eye can perceive, so less than 50 Hz

Won't that "flicker" though ?
It's a small area to do, I guess, but still.

may be moot. i just got a tft display working morning and it seems that it takes 50 msec to update the display.

How "instant" is the needle? For example, is it sufficient for the needle to update only once a second?

TFT_eSPI has built in widgets like this.

TFT_eSPI/examples/GUI Widgets at master · Bodmer/TFT_eSPI (github.com)

outbackhut, updating the display every 1 sec is acceptable for this use-case, but it takes the TFT a few good seconds to draw the background.

gcjr, how do you do it in 50 msec?
cedarlakeinstruments, I'll give it a try

Does the graphics library you are using have an "xor" drawing mode? If so, using that mode, the line can be un-drawn by simply drawing it again, restoring the original background. The side-effect of using xor mode is that when the line overlaps with other objects, you get some pixels with unexpected colours.

PaulRB
IDK
How do I check?

Who are you responding to? Please either use the reply button under the post made by the person you want to respond to, or quote a few of their words by selecting the words and clicking Quote. If you use the reply button at the bottom of the page, it's not clear who you are responding to.

If you want to respond to more than one post, you can use the reply button at the bottom of the page and then in the text of your post, put their name by typing @ followed by the first few letters of their name. A list should appear which you can select the full name. Example: @eranla

@cedarlakeinstruments , I couldn't get this code to work on my UNO.
@ gcjr I tried doing what you suggested, even though I think my screen won't handle it (as it takes too long to load an image) but just for the fun I tried playing with loading an image and got stuck there as well.

I'm trying to upload this image, which is 134X38 pixel:
0

I'm using the image2LCD tool that is found on the same link I shared in my first post:

I also tried using the tool on this website, but couldn't get any better results.
https://javl.github.io/image2cpp/

When I try the code as I understand it should look like:

Paint_DrawImage(gImage, 30, 100, 134, 38);

I'm getting the below result:

Continue on the next post (I'm limited to upload only 3 pictures)

...Continue from the above post.

When I use this code:

Paint_DrawImage(gImage, 30, 100, 67, 38);

I'm getting a much smaller image, and the width to height ratio is all wrong, but at least something logical is shown:


Also, see how the blue changed to green.

Any ideas how to properly load an image?

Could you please post the full code in code tags?

I'd..

Redraw the needle in background color.
Redraw the scale marks and text. (should be quick)
Redraw needle in needle color, in new position.
Set a timeObj for a bit to skip drawing, while it does other things.

-jim lee

My bad. I didn't notice that you said you were using an Uno. TFT_eSPI won't run on an Uno. I think it requires more RAM than that.

Redrawing the entire display, for a color display, takes a long time (16 or 24 bits per pixel).
With your particular image, probably the following sequence:

Using the previous needle position:
redraw the needle in the main background color
redraw the needle portion that covers the center circle
redraw the arc of white near the edge of the center circle
redraw any portion of the scale that the needle overwrites (may need a table of angles where the needle intersects the numbers)

then draw the new needle

Sounds like a long, slow procedure, but the slow part is actually sending data to the display.

@outbackhut , for showing the picture on the screen, I'm just using the function that came with the library.

/******************************************************************************
  function: Display image
  parameter:
    image            锛欼mage start address
    xStart           : X starting coordinates
    yStart           : Y starting coordinates
    xEnd             锛欼mage width
    yEnd             : Image height
******************************************************************************/
void Paint_DrawImage(const unsigned char *image, UWORD xStart, UWORD yStart, UWORD W_Image, UWORD H_Image)
{
  int i, j;
  for (j = 0; j < H_Image; j++) {
    for (i = 0; i < W_Image; i++) {
      if (xStart + i < LCD_WIDTH  &&  yStart + j < LCD_HEIGHT) //Exceeded part does not display
        Paint_SetPixel(xStart + i, yStart + j, (pgm_read_byte(image + j * W_Image * 2 + i * 2 + 1)) << 8 | (pgm_read_byte(image + j * W_Image * 2 + i * 2)));
      //Using arrays is a property of sequential storage, accessing the original array by algorithm
      //j*W_Image*2          Y offset
      //i*2                  X offset
      //pgm_read_byte()
    }
  }

}

and here is a sample of how the picture code is decoded (not the complete decode as it is super long)

#include "image.h"
const unsigned char gImage[5092] = { /* 0X08,0X08,0X86,0X00,0X26,0X00, */
0X07,0X07,0X07,0X07,0X07,0X0B,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,
0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,
0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,
0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,
0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,
0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,
0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X0B,0X07,0X0B,0X07,0X07,0X07,0X07,0X07,0X0B,

How much space do you have left on your Uno after uploading all of this?

FWIW, this is what typical gauges look like with LVGL running on top of TFT_eSPI on an ESP32.
Center is RPM, right is temperature.

display

Working on the graphics some more, I'm guessing now that it will be MUCH easier to implement it by simply creating 50-100 pictures (frames) and just animating them.
With the loading time of the UNO this approach is just not possible so I'll try working with @cedarlakeinstruments library and switch to ESP32.