Adding Color Gradients to Bar Graph

Have a working thermocouple displaying values to an adafruit hxd8357d 3.5" display from an uno. They are also displayed via bar graph, which works nicely. I have been trying to get color gradients though as the bar graph moves.

Intention is to have multiple sensors (pressure, temperature, etc) read out to the screen, each with a bar graph and values displayed.

I’ve seen some of bodmer’s libraries etc, but have been unable to get it to work with my hardware. Well, I did after extensive library changes, but the values would not display, so I scrapped it and started over.

Here’s my current project.

#include <SPI.h>
#include "Adafruit_GFX.h"
#include "Adafruit_HX8357.h"
#include "Adafruit_MAX31855.h"

// Assign human-readable names to some common 16-bit color values:
#define LTBLUE      0xB6DF
#define LTTEAL      0xBF5F
#define LTGREEN     0xBFF7
#define LTCYAN      0xC7FF
#define LTRED       0xFD34
#define LTMAGENTA   0xFD5F
#define LTYELLOW    0xFFF8
#define LTORANGE    0xFE73
#define LTPINK      0xFDDF
#define LTPURPLE    0xCCFF
#define LTGREY      0xE71C

#define BLUE        0x001F
#define TEAL        0x0438
#define GREEN       0x07E0
#define CYAN        0x07FF
#define RED         0xF800
#define MAGENTA     0xF81F
#define YELLOW      0xFFE0
#define ORANGE      0xFD20
#define PINK        0xF81F
#define PURPLE      0x801F
#define GREY        0xC618
#define WHITE       0xFFFF
#define BLACK       0x0000

#define DKBLUE      0x000D
#define DKTEAL      0x020C
#define DKGREEN     0x03E0
#define DKCYAN      0x03EF
#define DKRED       0x6000
#define DKMAGENTA   0x8008
#define DKYELLOW    0x8400
#define DKORANGE    0x8200
#define DKPINK      0x9009
#define DKPURPLE    0x4010
#define DKGREY      0x4A49

// These are 'flexible' lines that can be changed
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST -1 // RST can be set to -1 if you tie it to Arduino's reset

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC, TFT_RST);

// SoftSPI - note that on some processors this might be *faster* than hardware SPI!
//Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST, MISO);

// Example creating a thermocouple instance with software SPI on any three
// digital IO pins.
#define MAXDO   2
#define MAXCS   3
#define MAXCLK  4

// Initialize the Thermocouple
Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);

// Example creating a thermocouple instance with hardware SPI
// on a given CS pin.
//#define MAXCS   3
//Adafruit_MAX31855 thermocouple(MAXCS);

int high = 0;
int low = 1500;
int egt;

boolean graph_1 = true;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  tft.begin();
  Serial.println("HX8357D Test!");
  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(HX8357_RDPOWMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(HX8357_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(HX8357_RDCOLMOD);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(HX8357_RDDIM);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(HX8357_RDDSDR);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
  tft.setRotation(0); 
  tft.fillScreen(HX8357_BLACK);
  tft.fillScreen(HX8357_RED); 
  tft.fillScreen(HX8357_BLACK);

  Serial.println("MAX31855 test");
  // wait for MAX chip to stabilize
  delay(500);
  Serial.print("Initializing sensor...");
  if (!thermocouple.begin()) {
    Serial.println("ERROR.");
    while (1) delay(10);
  }
  Serial.println("DONE.");
}

void loop() {
  
   egt = (thermocouple.readFahrenheit());
   
   DrawBarChartH(tft, 30, 70, 200, 30, 0, 2000, .5, egt, 4, 0, GREEN, DKGREEN, GREEN, WHITE, BLACK, "EGT", graph_1);

   //Store and Display High Temperature Readings
   HighReadings(tft, 180, 15, 4, 0);

   //Store and Display Low Temperature Readings
   LowReadings(tft, 10, 15, 4, 0);

   
  delay(250);
}

void DrawBarChartH(Adafruit_HX8357 & d, double x , double y , double w, double h , double loval , double hival , double inc , double 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));
}

void HighReadings(Adafruit_HX8357 & d, double x, double y, int dig, int dec)
{
     if(egt>high){
      d.setCursor(x,y);
      d.setTextSize(4);
      tft.print(Format(egt, dig, dec));
      high=egt;
     }   
}

void LowReadings(Adafruit_HX8357 & d, double x, double y, int dig, int dec)
{
     if(egt<low){
      d.setCursor(x,y);
      d.setTextSize(4);
      tft.print(Format(egt, dig, dec));
      low=egt;
     }
}

String Format(double val, int dec, int dig ) {
    int addpad = 0;
    char sbuf[20];
    String condata = (dtostrf(val, dec, dig, sbuf));


    int slen = condata.length();
    for ( addpad = 1; addpad <= dec + dig - slen; addpad++) {
        condata = " " + condata;
    }
    return (condata);
}

Which Bodmer example are you trying to replicate ?

It should be fairly straightforward to draw a graded colour Bar with a WHITE border and BLACK background.
I would not want to blend colours when drawing text.

I start to get queasy when I see people creating orphan Strings and whole herds of double variables.

David.

Use of Strings is a bad idea on the Uno. They cause program crashes and memory problems.

david_prentice:
Which Bodmer example are you trying to replicate ?

It should be fairly straightforward to draw a graded colour Bar with a WHITE border and BLACK background.
I would not want to blend colours when drawing text.

I start to get queasy when I see people creating orphan Strings and whole herds of double variables.

David.

I originally found it on instructables here: Meter RIng. I was running in SPI when I was merging his code . It doesn't need to replicate it exactly, but for the bar graph to go from green to red etc. I attempted to change text colors if a certain threshold was reached, ie. if max temp greater than 1200 degrees turn orange, else if temp greater than 1300 turn red. Issue is it requires a redraw of the entire screen since it draws over existing text.

Not all of this code is my own, which is why String is used. In this case it's to format the numbers being output to limit decimal places and digits . I'm alright at reading and adapting other peoples code, but don't have the knowledge depth to create much from scratch yet.

jremington:
Use of Strings is a bad idea on the Uno. They cause program crashes and memory problems.

I read through some of that. We shall see if I have some errors. I have left it to run for last 24hrs, no issues, which in general would be way longer than it would ever be used since this is will be placed in my truck to read sensors.

This is my first real arduino project, with limited coding knowledge left over from college 15 years ago, lol. Having said that, I should have done more reading before I purchased the uno, as I'll need a mega for the additional pins and might get a nextion screen if I must, but wanted to see what I could acheive with this screen before buying another.

If ya'll have any suggestions on formatting the output to digits only without the use of string, I'm all ears. In the mean time I'll do some reading.