Bodmer / TFT_eFEX

A support library for TFT_eSPI that adds commonly used extra functions
Other
84 stars 27 forks source link

Graph and meters #3

Closed sorriso93 closed 5 years ago

sorriso93 commented 5 years ago

I know you are already planning this but just to inform you some code is already available maybe you can easily integrate it (I tested it and it is almost ok with your library).

Found on github various code maybe you can improve it many thanks

ringmeter below

`/* An example showing 'ring' analogue meters on a 2.2" ILI9341 TFT 240x320 colour screen

The meter graphic function works best with slowly changing values without large rapid changes such as environmental parameters (temperature etc)

This example uses the hardware SPI and a board based on the ATmega328 such as an UNO. If using a Mega or outher micocontroller then comment out the following line:

define F_AS_T

in the "Adafruit_ILI9341_FAST.h" found within the Adafruit_ILI9341_AS library folder. Change pins for other Arduinos to the hardware SPI pins.

Needs Fonts 2, and 4 (also Font 6 if using a large size meter)

Alan Senior 18/3/2015 */

// These are the connections from the UNO to the display

define sclk 13 // Don't change

define mosi 11 // Don't change

define cs 10 // If cs and dc pin allocations are changed then

define dc 9 // comment out #define F_AS_T line in "Adafruit_ILI9341_FAST.h"

// (which is inside "Adafriit_ILI9341_AS" library)

define rst 7 // Can alternatively connect this to the Arduino reset

// Meter colour schemes

define RED2RED 0

define GREEN2GREEN 1

define BLUE2BLUE 2

define BLUE2RED 3

define GREEN2RED 4

define RED2GREEN 5

include // Core graphics library

include // Fast hardware-specific library

include

define ILI9341_GREY 0x2104 // Dark grey 16 bit colour

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

uint32_t runTime = -99999; // time for next update

int reading = 0; // Value to be displayed int d = 0; // Variable used for the sinewave test waveform

void setup(void) { tft.init();

tft.setRotation(3);

tft.fillScreen(ILI9341_BLACK); }

void loop() { if (millis() - runTime >= 2000L) { // Execute every 2s runTime = millis();

// Test with a slowly changing value from a Sine function
d += 5; if (d >= 360) d = 0;

// Set the the position, gap between meters, and inner radius of the meters
int xpos = 0, ypos = 5, gap = 4, radius = 52;

// Draw meter and get back x position of next meter

// Test with Sine wave function, normally reading will be from a sensor
reading = 250 + 250 * sineWave(d+0);
xpos = gap + ringMeter(reading, 0, 500, xpos, ypos, radius, "mA", GREEN2RED); // Draw analogue meter

reading = 20 + 30 * sineWave(d+60);
xpos = gap + ringMeter(reading, -10, 50, xpos, ypos, radius, "degC", BLUE2RED); // Draw analogue meter

reading = 50 + 50 * sineWave(d + 120);
ringMeter(reading, 0, 100, xpos, ypos, radius, "%RH", BLUE2BLUE); // Draw analogue meter

// Draw two more larger meters
xpos = 20, ypos = 115, gap = 24, radius = 64;

reading = 1000 + 150 * sineWave(d + 90);
xpos = gap + ringMeter(reading, 850, 1150, xpos, ypos, radius, "mb", BLUE2RED); // Draw analogue meter

reading = 15 + 15 * sineWave(d + 150);
xpos = gap + ringMeter(reading, 0, 30, xpos, ypos, radius, "Volts", GREEN2GREEN); // Draw analogue meter

// Draw a large meter
xpos = 40, ypos = 5, gap = 15, radius = 120;
reading = 175;
// Comment out above meters, then uncomment the next line to show large meter
//ringMeter(reading,0,200, xpos,ypos,radius," Watts",GREEN2RED); // Draw analogue meter

} }

// ######################################################################### // Draw the meter on the screen, returns x coord of righthand side // ######################################################################### int ringMeter(int value, int vmin, int vmax, int x, int y, int r, char *units, byte scheme) { // Minimum value of r is about 52 before value text intrudes on ring // drawing the text first is an option

x += r; y += r; // Calculate coords of centre of ring

int w = r / 4; // Width of outer ring is 1/4 of radius

int angle = 150; // Half the sweep angle of meter (300 degrees)

int text_colour = 0; // To hold the text colour

int v = map(value, vmin, vmax, -angle, angle); // Map the value to an angle v

byte seg = 5; // Segments are 5 degrees wide = 60 segments for 300 degrees byte inc = 5; // Draw segments every 5 degrees, increase to 10 for segmented ring

// Draw colour blocks every inc degrees for (int i = -angle; i < angle; i += inc) {

// Choose colour from scheme
int colour = 0;
switch (scheme) {
  case 0: colour = ILI9341_RED; break; // Fixed colour
  case 1: colour = ILI9341_GREEN; break; // Fixed colour
  case 2: colour = ILI9341_BLUE; break; // Fixed colour
  case 3: colour = rainbow(map(i, -angle, angle, 0, 127)); break; // Full spectrum blue to red
  case 4: colour = rainbow(map(i, -angle, angle, 63, 127)); break; // Green to red (high temperature etc)
  case 5: colour = rainbow(map(i, -angle, angle, 127, 63)); break; // Red to green (low battery etc)
  default: colour = ILI9341_BLUE; break; // Fixed colour
}

// Calculate pair of coordinates for segment start
float sx = cos((i - 90) * 0.0174532925);
float sy = sin((i - 90) * 0.0174532925);
uint16_t x0 = sx * (r - w) + x;
uint16_t y0 = sy * (r - w) + y;
uint16_t x1 = sx * r + x;
uint16_t y1 = sy * r + y;

// Calculate pair of coordinates for segment end
float sx2 = cos((i + seg - 90) * 0.0174532925);
float sy2 = sin((i + seg - 90) * 0.0174532925);
int x2 = sx2 * (r - w) + x;
int y2 = sy2 * (r - w) + y;
int x3 = sx2 * r + x;
int y3 = sy2 * r + y;

if (i < v) { // Fill in coloured segments with 2 triangles
  tft.fillTriangle(x0, y0, x1, y1, x2, y2, colour);
  tft.fillTriangle(x1, y1, x2, y2, x3, y3, colour);
  text_colour = colour; // Save the last colour drawn
}
else // Fill in blank segments
{
  tft.fillTriangle(x0, y0, x1, y1, x2, y2, ILI9341_GREY);
  tft.fillTriangle(x1, y1, x2, y2, x3, y3, ILI9341_GREY);
}

}

// Convert value to a string char buf[10]; byte len = 4; if (value > 999) len = 5; dtostrf(value, len, 0, buf);

// Set the text colour to default tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); // Uncomment next line to set the text colour to the last segment value! // tft.setTextColor(text_colour, ILI9341_BLACK);

// Print value, if the meter is large then use big font 6, othewise use 4 if (r > 84) tft.drawCentreString(buf, x - 5, y - 20, 6); // Value in middle else tft.drawCentreString(buf, x - 5, y - 20, 4); // Value in middle

// Print units, if the meter is large then use big font 4, othewise use 2 tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); if (r > 84) tft.drawCentreString(units, x, y + 30, 4); // Units display else tft.drawCentreString(units, x, y + 5, 2); // Units display

// Calculate and return right hand side x coordinate return x + r; }

// ######################################################################### // Return a 16 bit rainbow colour // ######################################################################### unsigned int rainbow(byte value) { // Value is expected to be in range 0-127 // The value is converted to a spectrum colour from 0 = blue through to 127 = red

byte red = 0; // Red is the top 5 bits of a 16 bit colour value byte green = 0;// Green is the middle 6 bits byte blue = 0; // Blue is the bottom 5 bits

byte quadrant = value / 32;

if (quadrant == 0) { blue = 31; green = 2 (value % 32); red = 0; } if (quadrant == 1) { blue = 31 - (value % 32); green = 63; red = 0; } if (quadrant == 2) { blue = 0; green = 63; red = value % 32; } if (quadrant == 3) { blue = 0; green = 63 - 2 (value % 32); red = 31; } return (red << 11) + (green << 5) + blue; }

// ######################################################################### // Return a value in range -1 to +1 for a given phase angle in degrees // ######################################################################### float sineWave(int phase) { return sin(phase * 0.0174532925); }`

barchart H and V

` void DrawBarChartV(TFT_eSPI & d, long int x , long int y , long int w, long int h , long int loval , long int hival , long int inc , long int curval , int dig , int dec, unsigned int barcolor, unsigned int voidcolor, unsigned int bordercolor, unsigned int textcolor, unsigned int backcolor, String label, boolean & redraw) {

double stepval, range; double my, level; double i, data; // draw the border, scale, and label once // avoid doing this on every update to minimize flicker if (redraw == true) { redraw = false;

d.drawRect(x - 1, y - h - 1, w + 2, h + 2, bordercolor);
d.setTextColor(textcolor, backcolor);
//d.setTextSize(2);
d.setCursor(x , y + 10);
d.println(label);
// step val basically scales the hival and low val to the height
// deducting a small value to eliminate round off errors
// this val may need to be adjusted
stepval = ( inc) * (double (h) / (double (hival - loval))) - .001;
for (i = 0; i <= h; i += stepval) 
{
  my =  y - h + i;
  d.drawFastHLine(x + w + 1, my,  5, textcolor);
  // draw lables
  //  d.setTextSize(1);
  d.setTextColor(textcolor, backcolor);
  d.setCursor(x + w + 12, my - 3 );
  data = hival - ( i * (inc / stepval));
  d.println(Format(data, dig, dec));
}

} // compute level of bar graph that is scaled to the height and the hi and low vals // this is needed to accompdate for +/- range level = (h * (((curval - loval) / (hival - loval)))); // draw the bar graph // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update d.fillRect(x, y - h, w, h - level, voidcolor); d.fillRect(x, y - level, w, level, barcolor); // write the current value d.setTextColor(textcolor, backcolor); //d.setTextSize(2); d.setCursor(x , y - h - 15); //23 d.println(Format(curval, dig, dec)); }

/* This method will draw a horizontal bar graph for single input it has a rather large arguement list and is as follows

&d = display object name x = position of bar graph (upper left of bar) y = position of bar (upper left of bar (add some vale to leave room for label) w = width of bar graph (does not need to be the same as the max scale) h = height of bar graph loval = lower value of the scale (can be negative) hival = upper value of the scale inc = scale division between loval and hival curval = date to graph (must be between loval and hival) dig = format control to set number of digits to display (not includeing the decimal) dec = format control to set number of decimals to display (not includeing the decimal) barcolor = color of bar graph voidcolor = color of bar graph background bordercolor = color of the border of the graph textcolor = color of the text back color = color of the bar graph's background label = bottom lable text for the graph redraw = flag to redraw display only on first pass (to reduce flickering) */

void DrawBarChartH(TFT_eSPI & d, long int x , long int y , long int w, long int h , long int loval , long int hival , long int inc , long int curval , int dig , int dec, unsigned int barcolor, unsigned int voidcolor, unsigned int bordercolor, unsigned int textcolor, unsigned int backcolor, String label, boolean & redraw) { double stepval, range; double mx, level; double i, data;

// draw the border, scale, and label once // avoid doing this on every update to minimize flicker // draw the border and scale if (redraw == true) { redraw = false; d.drawRect(x , y , w, h, bordercolor); d.setTextColor(textcolor, backcolor); // d.setTextSize(2); d.setCursor(x , y - 20); d.println(label); // step val basically scales the hival and low val to the width stepval = inc (double (w) / (double (hival - loval))) - .00001; // draw the text for (i = 0; i <= w; i += stepval) { d.drawFastVLine(i + x , y + h + 1, 5, textcolor); // draw lables // d.setTextSize(1); d.setTextColor(textcolor, backcolor); d.setCursor(i + x , y + h + 10); // addling a small value to eliminate round off errors // this val may need to be adjusted data = ( i (inc / stepval)) + loval + 0.00001; d.println(Format(data, dig, dec)); } } // compute level of bar graph that is scaled to the width and the hi and low vals // this is needed to accompdate for +/- range capability // draw the bar graph // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update level = (w * (((curval - loval) / (hival - loval)))); d.fillRect(x + level + 1, y + 1, w - level - 2, h - 2, voidcolor); d.fillRect(x + 1, y + 1 , level - 1, h - 2, barcolor); // write the current value d.setTextColor(textcolor, backcolor); // d.setTextSize(2); d.setCursor(x + w + 10 , y + 5); d.println(Format(curval, dig, dec)); }

/*

function to draw a cartesian coordinate system and plot whatever data you want just pass x and y and the graph will be drawn

huge arguement list &d name of your display object x = x data point y = y datapont gx = x graph location (lower left) gy = y graph location (lower left) w = width of graph h = height of graph xlo = lower bound of x axis xhi = upper bound of x asis xinc = division of x axis (distance not count) ylo = lower bound of y axis yhi = upper bound of y asis yinc = division of y axis (distance not count) title = title of graph xlabel = x asis label ylabel = y asis label &redraw = flag to redraw graph on first call only color = plotted trace colour */

void Graph(TFT_eSPI &d, long int x, long int y, long int gx, long int gy, long int w, long int h, long int xlo, long int xhi, long int xinc, long int ylo, long int yhi, long int yinc, String title, String xlabel, String ylabel, unsigned int gcolor, unsigned int acolor, unsigned int pcolor, unsigned int tcolor, unsigned int bcolor, boolean &redraw) { //if (redraw1==true){redraw=true;} double ydiv, xdiv; // initialize old x and old y in order to draw the first point of the graph // but save the transformed value // note my transform funcition is the same as the map function, except the map uses long and we need doubles //static double ox = (x - xlo) ( w) / (xhi - xlo) + gx; //static double oy = (y - ylo) (gy - h - gy) / (yhi - ylo) + gy; double i; double temp; int rot, newrot;

if (redraw == true) { redraw = false; ox = (x - xlo) ( w) / (xhi - xlo) + gx; oy = (y - ylo) (gy - h - gy) / (yhi - ylo) + gy; // draw y scale for ( i = ylo; i <= yhi; i += yinc) { // compute the transform temp = (i - ylo) (gy - h - gy) / (yhi - ylo) + gy; if (i == 0) { d.drawLine(gx, temp, gx + w, temp, acolor); } else { d.drawLine(gx, temp, gx + w, temp, gcolor); } d.setTextSize(0); d.setTextColor(tcolor, bcolor); d.setCursor(gx - 40, temp); // precision is default Arduino--this could really use some format control int strip =i; d.println(strip); } // draw x scale for (i = xlo; i <= xhi; i += xinc) { // compute the transform temp = (i - xlo) ( w) / (xhi - xlo) + gx; if (i == 0) { d.drawLine(temp, gy, temp, gy - h, acolor); } else { d.drawLine(temp, gy, temp, gy - h, gcolor); } d.setTextSize(0); d.setTextColor(tcolor, bcolor); d.setCursor(temp, gy + 10); // precision is default Arduino--this could really use some format control //int strip =(i/.66666666666666666666); int strip=(i/2)/3600; d.println(strip); } //now draw the labels d.setTextSize(0); d.setTextColor(tcolor, bcolor); d.setCursor(gx , gy - h - 30); d.println(title); d.setTextSize(0); d.setTextColor(acolor, bcolor); d.setCursor(gx , gy + 20); d.println(xlabel); d.setTextSize(0); d.setTextColor(acolor, bcolor); d.setCursor(gx - 30, gy - h - 10); d.println(ylabel); } //graph drawn now plot the data // the entire plotting code are these few lines... // recall that ox and oy are initialized as static above x = (x - xlo) ( w) / (xhi - xlo) + gx; y = (y - ylo) (gy - h - gy) / (yhi - ylo) + gy; d.drawLine(ox, oy, x, y, pcolor); d.drawLine(ox, oy + 1, x, y + 1, pcolor); d.drawLine(ox, oy - 1, x, y - 1, pcolor); ox = x; oy = y; }

void Graph2(TFT_eSPI &d, long int x1, long int y, long int gx, long int gy, long int w, long int h, long int xlo, long int xhi, long int xinc, double ylo, long int yhi, long int yinc, String title, String xlabel, String ylabel, unsigned int gcolor, unsigned int acolor, unsigned int pcolor, unsigned int tcolor, unsigned int bcolor, boolean &redraw) { //if (redraw1==true){redraw=true;} double ydiv, xdiv; // initialize old x and old y in order to draw the first point of the graph // but save the transformed value // note my transform funcition is the same as the map function, except the map uses long and we need doubles //static double ox = (x - xlo) ( w) / (xhi - xlo) + gx; //static double oy = (y - ylo) (gy - h - gy) / (yhi - ylo) + gy; double i; double temp; int rot, newrot;

if (redraw == true) { redraw = false; ox2 = (x - xlo) ( w) / (xhi - xlo) + gx; oy2 = (y - ylo) (gy - h - gy) / (yhi - ylo) + gy; // draw y scale for ( i = ylo; i <= yhi; i += yinc) { // compute the transform temp = (i - ylo) (gy - h - gy) / (yhi - ylo) + gy; if (i == 0) { d.drawLine(gx, temp, gx + w, temp, acolor); } else { d.drawLine(gx, temp, gx + w, temp, gcolor); } d.setTextSize(0); d.setTextColor(tcolor, bcolor); d.setCursor(gx - 40, temp); // precision is default Arduino--this could really use some format control int strip =i; d.println(strip); } // draw x scale for (i = xlo; i <= xhi; i += xinc) { // compute the transform temp = (i - xlo) ( w) / (xhi - xlo) + gx; if (i == 0) { d.drawLine(temp, gy, temp, gy - h, acolor); } else { d.drawLine(temp, gy, temp, gy - h, gcolor); } d.setTextSize(0); d.setTextColor(tcolor, bcolor); d.setCursor(temp, gy + 10); // precision is default Arduino--this could really use some format control //int strip =(i/.66666666666666666666); int strip=(i/2)/3600; d.println(strip); } //now draw the labels d.setTextSize(0); d.setTextColor(tcolor, bcolor); d.setCursor(gx , gy - h - 30); d.println(title); d.setTextSize(0); d.setTextColor(acolor, bcolor); d.setCursor(gx , gy + 20); d.println(xlabel); d.setTextSize(0); d.setTextColor(acolor, bcolor); d.setCursor(gx - 30, gy - h - 10); d.println(ylabel); } //graph drawn now plot the data // the entire plotting code are these few lines... // recall that ox and oy are initialized as static above x = (x - xlo) ( w) / (xhi - xlo) + gx; y = (y - ylo) (gy - h - gy) / (yhi - ylo) + gy; d.drawLine(ox2, oy2, x, y, pcolor); d.drawLine(ox2, oy2 + 1, x, y + 1, pcolor); d.drawLine(ox2, oy2 - 1, x, y - 1, pcolor); ox2 = x; oy2= y; }`

Bodmer commented 5 years ago

Thanks for the info. I will have a look.

Alexandre2003 commented 4 years ago

Hello friend, well I saw that you passed these information to Bodmer look I really need to create vertical and horizontal bars I tried with the code that you described there above but it didn't work I'm a beginner and it was difficult for me I asked Bodmer for help but I went iguinorado kkkk if you can help me or give me a semi finished condition i will be forever grateful to you sorry for the inconvenience ok i'm from brazil

Att Alexandre Guaita

https://github.com/Bodmer/TFT_eFEX/issues/3#issue-427942037

Bodmer commented 4 years ago

Look here.

sorriso93 commented 4 years ago

Ciao, you can also look into this example