Introduction: Arduino Analogue 'ring' Meter on Colour TFT Display

Yet another Arduino project for the display of sensor readings etc.

The example sketch included in the instructable includes the meter drawing function to use in your own projects, the function is not in a library so could be adapted for use with other graphics libraries. The meter drawing function has been "parameterised" so the meter size, position, range, units and colour scheme can be easily configured to suit your own needs.

Part of the inspiration for the development of the graphic was to have a similar style to the forthcoming Adafruit IO "Internet of Things" website.

The display is a 2.2" 320 x 240 pixel TFT colour display with the ILI9341 driver chip, this is driven by an Arduino UNO.

Step 1: The Meter Graphics

The value displayed is shown as a bar graph that can be segmented or continuous. Larger values are shown as more segments being coloured in, thus the display gives an instant visual indication of a reading at a glance without having to read the numbers. The numerical value is shown in the center of the ring, a bit like the Google Nest display.

The colour of the ring segments can be set to change as the value increases, so this means a display showing temperatures can be set change from blue to red as the temperature increases. Another display for say a battery level could change from red for a low value, through yellow to green for a high value.

The meter position and size can be set as desired to make a meter arrangement that suits your taste. The sizes are set independently so more important information can be shown with a bigger graphic, or the display could cycle though several meters.

The unlit segments are dark grey (these segments look brighter in the images as I had to adjust the web cam settings to try to capture the display colours.)

The displays are best for values that change slowly with time such as temperature and humidity etc.

Step 2: Hardware Configuration

The hardware setup is common to some of my other Instructables, it consists of the UNO, the 2.2" TFT display based on the ILI9341 driver chip and a set of libraries that are enhanced versions of the Adafruit GFX and ILI9341 libraries.

The libraries attached have been enhanced to give a much faster performance on an UNO using direct port access, other boards could be used by commenting out a #define and changing the the SPI pins.

The UNO is connected to the ILI9241 2.2" TFT display like this:

    • UNO +5V to display pin 1 (VCC)
    • UNO +5V through a 56 Ohm resistor to display pin 8 (LED)
    • UNO 0V (GND) to display pin 2 (GND)
    • UNO digital pin 7 through a 1K2 resistor to display pin 4 (RESET), add a 1K8 resistor from display pin 4 to GND
    • UNO digital pin 9 through a 1K2 resistor to display pin 5 (DC/RS), add a 1K8 resistor from display pin 5 to GND
    • UNO digital pin 10 through a 1K2 resistor to display pin 3 (CS), add a 1K8 resistor from display pin 3 to GND
    • UNO digital pin 11 through a 1K2 resistor to display pin 6 (SDI/MOSI), add a 1K8 resistor from display pin 6 to GND
    • UNO digital pin 13 through a 1K2 resistor to display pin 7 (SCK), add a 1K8 resistor from display pin 7 to GND

    It is important to include the 1K8 resistors to GND with this 2.2" display as otherwise it will not work! The 1K2 and 1K8 resistors are a "potential divider", acting as a logic level shifter so that the logic level at the display is reduced from 5V to around 3V. Pin 9 of the display does not need to be connected up.

    I have included a couple of short (!) videos (rather poor quality...) showing the graphics speed using an UNO and hardware SPI. (These have had the long delay() intervals between each test screen removed from the sketch!)

    One video is the UTFT Demo running on a Mega board with a 16 bit parallel interface to the display. It is faster mostly because the 10,000 pixel plot test at the end has been changed so 30,000 16 bit random numbers do not need to be produced at the same time as plotting 10,000 pixels (generating 30,000 16 bit random values takes nearly 3 seconds so the UNO can really drive the display faster than it appears during that part of the test!)

    The "Sine wave" animation is limited mainly by the floating point maths involved and could be speeded up dramatically by using a simple Sine lookup table, that test would then be over in the blink of an eye!

    Step 3: The Meter Drawing Function

    Here is the function prototype:

    int ringMeter(value, vmin, vmax, x, y, r, "Units", scheme)

    The ringMeter function returns the x coordinate of the right hand side of the meter to aid placement of the next meter.

    value is the value to be displayed and plotted, integer values up to 4 digits are accommodated

    vmin is the minimum value to be plotted

    vmax is the maximum value to be plotted, thus vmin and vmax set the full meter range

    x and y are the coordinates of the top left corner of an imaginary box that contains the meter

    r in the outer radius of the ring in pixels, the minimum is about 52 before the text intrudes on the ring

    "Units" is the text string such as "Volts", "C" etc.

    scheme sets the colour scheme, there are some # define statements in the example that enumerate the settings available, others could be added:

    • #define RED2RED 0
    • #define GREEN2GREEN 1
    • #define BLUE2BLUE 2
    • #define BLUE2RED 3
    • #define GREEN2RED 4
    • #define RED2GREEN 5

    These different schemes set the colour change as the value grows from vmin to vmax, so for example in the following the colour scheme is change from Blue to Red as the value increases:

    ringMeter(reading,-10,50, xpos,ypos,radius,"degC",BLUE2RED);

    In this case a temperature reading is being plotted in the range -10 to +50 degrees C, as the value increases the segments turn from blue (cold!) to red (hot!) as shown in the picture.

    Step 4: Libraries and Sketch

    The ring meter sketch and the two libraries needed are in the attached zip file.

    Some fonts have been disabled in the "Load_fonts.h" file to save space in the compiled sketch. Fonts 2,4 and 6 are enabled.

    The "Adafruit_ILI9341_AS" library as provided here is optimised for the UNO and ATmega 328p microcontroller, so it is best to start with that device.

    To use with others such as the Mega the SPI pins in the sketch will need to be changed and also the #define F_AS_T line will need to be commented out in the "Adafruit_ILI9341_FAST.h" file found inside the "Adafruit_ILI9341_AS" library. When the line is commented out the ATmega328 specific code will not be used so the display updates will be 50% slower.

    Eventually I will add speed enhancing code for the Mega as that is likely to be the upgrade path for projects that use large font files!

    The libraries and sketch were really developed for my own use and hence may have a few rough edges... but it works for me! If you have problems then report them below and I will try to help... given time!

    Warning: This version of the "Adafruit_GFX_AS" has NOT been tested with the other display libraries (S6D02A1 and ST7735) in my other instructables. So please keep a copy of your old library in case this one has an incompatibility! I will be adding compatible hardware drivers to this instructable at some point...

    Lastly, there is a comment at line 121 in the sketch describing how to turn a continuous ring into a segmented one.


    Bodmer made it!(author)2015-04-04

    Following on from FabioB3's comment, I have run the Adafruit "graphicstest" sketch under the original Adafruit_GFX library and my enhanced version. The results are quite interesting:

    The speed has been increased to an average of 2.3 times faster. This is an equivalent boost to running a 16MHz UNO at 36MHz!

    Of particular note is the "line", triangle outline and circle outline drawing speed boost. This is because the Bresenham algorithm has been enhanced to take advantage of the way the display hardware has to be driven. The line drawing speed increase is the equivalent of running an UNO at 88MHz.

    See attached table of results.

    Test results.png
    Mery+YC made it!(author)2015-10-12

    Hi, Bodmer

    Congratulations again for your projects. The truth is that they are something that I always had in my mind. I wanted to ask for your help again, I'm interested in displaying data in the wattmeter display through input "A0", because in your sketch, the indication is simulated by a sinusoidal signal. It's posible?

    BODMER thank you very much, I hope your response as you have always done, congratulations !!!!

    Bodmer made it!(author)2015-10-13

    Try code like this:

    reading = analogRead(A0);

    Then change the calling function to, for example:

    ringMeter(reading, 0, 1023, xpos, ypos, radius, "W", GREEN2RED);

    Mery+YC made it!(author)2016-09-02

    Hi, Bodmer, All Good?

    Can you help me again? I am trying one of the examples to make a voltmeter with of your ring put and it would need to visualize a precision value in the center of the display (the information her provides a converter ADC 24Bits "LTC2400") I have the code to monitor the readings of the LTC2400 but only it does it across ARDUINO's serial monitor, but it wanted to visualize it in the own display. Can you help me?

    Mery+YC made it!(author)2015-10-14


    insanoff made it!(author)2017-06-12

    Worked from first try. Thank you for sharing your knowledge! I can now easily learn create gauges by modifying it.
    My setup:
    Arduino Pro Mini
    2.4" 240x320 TFT display

    KarthickR24 made it!(author)2017-06-06


    I am using standalone Atmega328p-AU (SMD, 32 pin,-MLF) with the tft LCD 2.2" display ( At first, I tried your program on UNO board and it works fine. But, my own board not using the hardware SPI to interface with display because hardware SPI is busy with other processes. Therefore I use following digital pins to interface with LCD and tried to invoke custom library, however, I failed several times and that is why I am here..

    My pin connections are following

    #define sclk 9 // equivalent to UNO SMD version pin map

    #define miso 8

    #define mosi 7

    #define cs 6

    #define dc 4

    #define rst 3

    Adafruit_ILI9341_AS tft = Adafruit_ILI9341_AS(cs, dc, mosi, sclk, rst, miso); // Invoke custom library


    undefined reference to `Adafruit_ILI9341_AS::Adafruit_ILI9341_AS(signed char, signed char, signed char, signed char, signed char, signed char)'

    collect2.exe: error: ld returned 1 exit status

    Please help me to find where I am wrong or How to modify the library to make it work.

    Thanks in advance for your efforts!

    preemax made it!(author)2016-09-02

    i made it ,

    lcd 3.95 - mega2560

    KazafY made it!(author)2015-07-23

    This is a great project that suit perfectly what I intended to do! However, the problem is that my display is not using the SPI connection. But the one with 8 data lines + 4 lines for the touchscreen...

    I have tried to modify the original library from Adafruit by implementing the functions from yours but no luck... any idea on how to get it works?

    Bodmer made it!(author)2015-07-24

    Can you provide a link to the display details, I may have a library version that supports that display.

    KazafY made it!(author)2015-07-24

    I appreciate your reply :) The display is exactly the same the one from this post:

    I think it is similar to the old version of adafruit TFT display. Also the library which I was using was modified from adafruit and forced it to use ILI9341 driver.

    Thank you again !

    (For the display pinout, you can find it here:

    Bodmer made it!(author)2015-07-26

    Try the libraries attached. I can't promise it will work though! These displays often have different drivers fitted to those advertised.
    TimC125 made it!(author)2016-05-25

    What do I do with these libraries? After I unzip them and add to the libraries folder I delete the original include GFX and ILI19341 lines in the Ring sketch and compile but I get errors. I can load and run the examples from the libraries though. Thanks a lot for the help.

    TimC125 made it!(author)2016-05-25

    Never mind. I got it working. Thanks for the great instructable. Attached is the updated sketch that works with the cheap eBay/Amazon 2.8 TFT shields.

    KazafY made it!(author)2015-07-26

    Thank your very much! It works like a charm! I have just run the ring meter program and it works properly. Also, the graphtest runs a little bit faster than the original libraries. (The UTFT demo has taken 11782ms to complete the sequence) Now lets see if I can make a speed meter for my bicycle :P

    Bodmer made it!(author)2015-07-26

    That was lucky ;-)

    GerardoM1 made it!(author)2016-03-17

    Hello, I bought this TFT:

    I would mount it on an Arduino Mega and recall the images uploaded to SD with a button ... can you help me?

    Thank you and congratulations for the job!



    Bodmer made it!(author)2016-04-09

    Try my library here:

    ih82lose made it!(author)2016-02-24

    Thank you for posting this project. I am excited about getting to use the display to view battery voltages on a pack containing three 12V batteries. I have been able to set it up to display the voltages using a voltage divider circuit for each battery, but I was hoping to get some help in getting the displayed value set to a float. Ideally, I would like xx.xx resolution in the voltage readings. I have attached the sketch. I am new to this, so any help would be greatly appreciated.
    Bodmer made it!(author)2016-03-14


    I added plotting floats for Mery YC, see Mery_YC.ino example attached to my reply below. You will need to use the library here.

    Mery+YC made it!(author)2015-12-07

    Hi BODMER,

    I want to thank you for sharing your knowledge with others. can you help me ? I need to show the numerical values within the rings to two decimal places "x.xx" for example. We appreciate it greatly.Best Regards.

    Bodmer made it!(author)2015-12-08

    Locate this line:

    dtostrf(value, len, 0, buf);

    This is a C function converts a number to a string. Change the 0 to 2 as in this line:

    dtostrf(value, len, 2, buf);

    This will then put 2 decimal places in the string. More information on the dtostrf() can be found with a Google search.

    Mery+YC made it!(author)2015-12-09

    Hi, BODMER,

    Thank you very much for the quick answer. I made the modification that you have shown me in the sketch but always indicate the two digits "00" and do not vary. What can be?

    Bodmer made it!(author)2015-12-09

    That's because the function to draw the ring meter accepts an integer value. You will need to modify it to accept a float type, or scale the value turning it into a float type within the function...

    Mery+YC made it!(author)2015-12-10

    Hi, BODMER, thanks for your response. You can help? I do not understand programming.Thanks a lot..

    Bodmer made it!(author)2015-12-10

    OK, what are you trying to display?

    For example, are you getting an ADC reading and scaling it to a value that will have 2 decimal palces? If so what is the scale factor?

    Mery+YC made it!(author)2015-12-14

    Hi BODMER, voltage need to show two decimal places. The scale will be up 35Vd.c (0Vdc to 35Vd.c). We will use the analog input A0. If you need more information, please do not hesitate to ask. Thanks a lot BODMER.

    Mery+YC made it!(author)2015-12-15

    The resolution may be 0,01 but is possible 0,05, BODMER. Thanks

    Bodmer made it!(author)2015-12-15

    OK, in the main loop call the function with a line like:

    ringMeter(reading, 0, 1023, xpos, ypos, radius, "V", BLUE2BLUE);

    Where the reading is the analogue input value, this will be in the range 0 - 1023.

    In the ringMeter(...) function you need to modify some lines at the end to convert the value to a floating point number like this, where the lines I have changed are in bold text.

    float voltage = value/29.2286; // Convert to a float number in range 0- 35
    // Print value, if the meter is large then use big font 6, othewise use 4
    if (r > 84) {
    tft.setTextPadding(5*27 + 15); // Allow for 3 digits each 27 pixels wide
    tft.drawFloat(voltage, 2, x, y, 6); // Value in middle
    else {
    tft.setTextPadding(5*14 + 7); // Allow for 3 digits each 14 pixels wide
    tft.drawFloat(voltage, 2, x, y, 4); // Value in middle
    Mery+YC made it!(author)2015-12-16

    Hi BODMER, when I modify the SKETCH with this changes, It indicates "'class Adafruit_ILI9341_AS' has no member named 'setTextDatum' when it is verified.

    THANKS A LOT ;-).

    Mery+YC made it!(author)2015-12-16

    I can send you my sketch in some form so you can see. So you can see what I want to do. You think?. Thank you.

    Bodmer made it!(author)2015-12-16

    Sure, I think you can send it via a personal message, or post it here by using the "Add images" button and uploading the sketch file.

    Mery+YC made it!(author)2015-12-17

    Hi, BODMER,this is my sketch. It is a Electronic Dummy Load project.Thanks a lot for your support ;-)

    Bodmer made it!(author)2015-12-21


    Updated sketch is attached. This must be used with the library here. Use the Download Zip button on that web page. Save it in your library folder and edit name to TFT_ILI934

    Inside that library folder modify the User_Setup.h file to comment out all fonts except 1, 2, 4. The pins are already setup correctly.

    This new library has extra functions to center the text and numbers and to blank out old values. These new functions are used in the updated sketch.

    Mery+YC made it!(author)2015-12-22

    Hi, BODMER, as always so attentive and eager to help others. I want to give thanks once again as you've always helped me what you have requested. Thanks for sharing your knowledge and time spent with us all. I would like to contribute in any way to your work time and so I would ask you to tell me, that way I can contribute or help. HAPPY 2016 in the company of your family !!!

    Bodmer made it!(author)2015-12-23

    Glad to help, good luck with your project.

    Mery+YC made it!(author)2015-12-17

    Hi, BODMER,this is my sketch. It is a Electronic Dummy Load project.Thanks a lot for your support ;-)

    Mery+YC made it!(author)2015-12-17

    forgive me for many sends.... :-(

    Mery+YC made it!(author)2015-12-17

    Hi BODMER, this is my code "Electronic Dummy Load" project. Thanks a lot for your support.

    Mery+YC made it!(author)2015-12-17

    Hi BODMER, this is my code "Electronic Dummy Load" project. Thanks a lot for your support.

    Bodmer made it!(author)2015-12-16

    Ah, yes. I am using a later version of the library with a new function, sorry!

    Incidentally you might like to try that library. You can find it here.

    Mery+YC made it!(author)2015-12-17

    Thanks a lot BODMER

    RobertoV1 made it!(author)2015-11-24

    How you made working parallel display with mega 2560?

    RobertoV1 made it!(author)2015-11-08

    Thank you a lot!

    for (int i=0; i <= 255; i++){



    This finally made my display (1.4" tft, il9341) work!

    MikeD15 made it!(author)2015-10-05

    Would this work with a ILI9163C (128x128) 1.44" Display? If so, how would I go about modifying it to do so? Great work by the way.

    Bodmer made it!(author)2015-10-06

    The ILI9163C will not work with this code, the library would not configure the display properly. It may be possible to adapt the library but I do not have a display with that driver chip, so unfortunately I cannot help you.

    MikeD15 made it!(author)2015-10-07

    Thank you for your reply. I've now ordered a 2.2" ILI9341 based display and also a 2.4" touch screen with a 7781 controller.

    Dr_Acula made it!(author)2015-07-31

    I made it!

    Merged the wireless mesh code I wrote, this Instructable and also your instructable with the terminal display.

    Thanks again for making these displays so easy to work with :)

    Bodmer made it!(author)2015-07-31

    Great! Thanks for the feedback. I like your project, very neat.

    PhillipC2 made it!(author)2015-06-02

    Also, check out the work that this guy has done with the TFT and GFX libraries: