TFT Boost Gauge - stuck on making a bar graph display

Hi,

I want to display the pressure level i’m reading from my sensor (MPX4250AP) as a horizontal bar graph. I also want the graph to display relative to atmospheric pressure, i.e. anything more than ~14.3psi registers as boost and anything below as vacuum (basically like this: Arduino Boost Gauge test2 - YouTube).

Am I going about this the wrong way?

this is the relevant chunk of code:

long BoostBar() {
  int mapSen = analogRead(A5)/1;
  newBar = int((mapSen/1024.0*200));
  float boost = ((((float)mapSen/(float)1023+0.04)/.004)*.145);
    //tft.setCursor(20,0);tft.fillRect(30, 0, 150, 40, RED);
    //tft.print(" ");tft.print(i);tft.print(" ");tft.print(i2);
    //tft.fillRect(20, 40, 139,200, BLACK);
    if (newBar != lastBar){
    //tft.drawRect(142, 80, boost*2,80, BLUE); //x position then y offset
    drawBar(newBar);
    }
    //else if (boost < atmpsi){
    //tft.drawRect(141 + (boost*-2), 80, boost * 2 ,80, GREEN); //x position then y offset
    //}
}

void drawBar (int nPer){

  if(nPer < lastBar){
    tft.fillRect(141 - lastBar, 40, lastBar - nPer, 160, BLACK);
  }
  else{
     tft.fillRect(141 - nPer, 40, nPer - lastBar, 160, BLUE);
  }
  lastBar = nPer;
  
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, RED);
    tft.print(nPer);
}

here is the complete thing. I am using an Elegoo 2.8" TFT display with 320x240 resolution (i think)

long BoostBar() {
  int mapSen = analogRead(A5)/1;
  newBar = int((mapSen/1024.0*200));
  float boost = ((((float)mapSen/(float)1023+0.04)/.004)*.145);
    //tft.setCursor(20,0);tft.fillRect(30, 0, 150, 40, RED);
    //tft.print(" ");tft.print(i);tft.print(" ");tft.print(i2);
    //tft.fillRect(20, 40, 139,200, BLACK);
    if (newBar != lastBar){
    //tft.drawRect(142, 80, boost*2,80, BLUE); //x position then y offset
    drawBar(newBar);
    }
    //else if (boost < atmpsi){
    //tft.drawRect(141 + (boost*-2), 80, boost * 2 ,80, GREEN); //x position then y offset
    //}
}

void drawBar (int nPer){

  if(nPer < lastBar){
    tft.fillRect(141 - lastBar, 40, lastBar - nPer, 160, BLACK);
  }
  else{
     tft.fillRect(141 - nPer, 40, nPer - lastBar, 160, BLUE);
  }
  lastBar = nPer;
  
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, RED);
    tft.print(nPer);
}

So, removing all the unnecessary cruft from your code, we have:

long BoostBar() {
  int mapSen = analogRead(A5) / 1;
  newBar = int((mapSen / 1024.0 * 200));
  if (newBar != lastBar) {
    drawBar(newBar);
  }
}

void drawBar (int nPer) {
  if (nPer < lastBar) {
    tft.fillRect(141 - lastBar, 40, lastBar - nPer, 160, BLACK);
  }
  else {
    tft.fillRect(141 - nPer, 40, nPer - lastBar, 160, BLUE);
  }
  lastBar = nPer;

  tft.setCursor(20, 20); tft.fillRect(20, 20, 30, 14, RED);
  tft.print(nPer);
}

You didn’t post the rest of your code; just the same thing twice.
BoostBar is declared as returning a long but returns nothing.
Dividing your analogRead return value by 1 makes little sense.
Your newBar calculation would be more idiomatically performed using the map() and, if necessary, constrain() functions.
Personally, I would pass both lastBar and newBar as parameters to drawBar() and update lastBar from within BoostBar().
What you are doing in drawBar() seems sensible; removing just the bit of the bar you don’t need or adding just the bit you do need.

Thanks for the helpful reply - sorry about the code clutter its tough to keep track of what im doing!

I cant post the whole code it is too big! But I have moved from drawbar() to drawbar2() which is instead using map() like you suggested. It is working much better and i have also moved the VLine to the new origin.

Currently this code draws boxes when a new case is reached. The code is able to erase extra bars/boxes but only left to right. cannot erase right to left of the origin line (when they are not needed). any ideas?

I’m trying to work something with the difference int but it seems to keep returning 1 or -1 when it should sit at 0 most of the time. hmmm

long BoostBar() {
  int mapSen = analogRead(A5);
  int PSI = map(mapSen,0,720,0,15);
  difference = PSI - currentbar;
  
    if (PSI != currentbar){
    difference = PSI - currentbar;
    drawBar2(PSI);
    }
}

void drawBar2 (int PSI){
    tft.setCursor(60,20);tft.fillRect(20, 20, 80, 14, BLACK);
    tft.print(difference);
    
    if (difference < 0){
      tft.fillRect(20+(currentbar*10),40,9,160,BLACK);
  }
  switch (PSI){
        case 0:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("0");
    tft.fillRect(20,40,9,160,RED);
    currentbar = 0;
    break;
        case 1:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("1");
    tft.fillRect(30,40,9,160,RED);
    currentbar = 1;
    break;
        case 2:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("2");
    tft.fillRect(40,40,9,160,RED);
    currentbar = 2;
    break;
        case 3:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("3");
    tft.fillRect(50,40,9,160,RED);
    currentbar = 3;
    break;
        case 4:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("4");
    tft.fillRect(60,40,9,160,RED);
    currentbar = 4;
    break;
        case 5:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("5");
    tft.fillRect(70,40,9,160,RED);
    currentbar = 5;
    break;
        case 6:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("6");
    tft.fillRect(80,40,9,160,RED);
    currentbar = 6;
    break;
        case 7: //ATMOSPHERIC
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("7");
    tft.fillRect(90,40,9,160,RED);
    currentbar = 7;
    break;
            case 8:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("8");
    tft.fillRect(100,40,9,160,RED);
    currentbar = 8;
    break;
            case 9:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("9");
    tft.fillRect(110,40,9,160,RED);
    currentbar = 9;
    break;
            case 10:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("10");
    tft.fillRect(120,40,9,160,RED);
    currentbar = 10;
    break;
            case 11:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("11");
    tft.fillRect(130,40,9,160,RED);
    currentbar = 11;
    break;
            case 12:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("12");
    tft.fillRect(140,40,9,160,RED);
    currentbar = 12;
    break;
            case 13:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("13");
    tft.fillRect(150,40,9,160,RED);
    currentbar = 13;
    break;
            case 14:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("14");
    tft.fillRect(160,40,9,160,RED);
    currentbar = 14;
    break;
            case 15:
    tft.setCursor(20,20);tft.fillRect(20, 20, 30, 14, BLACK);
    tft.print("15");
    tft.fillRect(170,40,9,160,RED);
    currentbar = 15;
    break;  
  }
}
long BoostBar() {
  int mapSen = analogRead(A5);
  int PSI = map(mapSen,0,720,0,15);
  difference = PSI - currentbar;

    if (PSI != currentbar){
    difference = PSI - currentbar;
    drawBar2(PSI);
    }
}

You've promised the compiler that you will return a value. But, you don't. Stop lying. Either return a value or change the function return type to void.

Why do you unconditionally and conditionally assign the same value to difference?

    tft.setCursor(60,20);tft.fillRect(20, 20, 80, 14, BLACK);

How many statements go on one line? ANY answer other than ONE is WRONG!

I gave up on trying to read your code. It looks like it was typed by a drunken monkey.

Put EVERY { on a line BY ITSELF. Use Tools + Auto Format to properly indent that mess.

The cases use constants that are a multiple of PSI. You really do NOT need 10 cases to handle the values 0 to 9. You don't need 6 more cases to handle the values 10 to 15. A little thought would eliminate most of the code in drawBar2().

bushwookie: sorry about the code clutter its tough to keep track of what im doing!

Yeah, it is tough because of all the clutter...

PaulS raised lots of very valid points that you need to implement. Take a little time and try to pay attention to the details.

In general, you want to avoid boilerplate code - code that is mostly just a copy of something else with a minor tweak. Your switch statement is full of that stuff and it can be a source of errors. Always try to factor out duplication where possible, eg.

  switch (PSI){
        case 0:
    currentbar = 0;
    break;
        case 1:
    currentbar = 1;
    break;
        case 2:
    currentbar = 2;
...

Could have simply been a currentbar = PSI after the switch statement. But all the TFT stuff is boilerplate too and can all be worked out mathematically in a few lines.

Simplify things slightly first to make the task easier. Just wipe out the old bar chart with a big rectangle each time and focus on the drawing of the bar. When you get that working, then you can optimise the wiping too.

Gents, thank you for taking the time to read through my code, I appreciate the feedback. I assure you any and all of my formatting mistakes, wierd usage of functions and ‘boilerplate’ code is purely down to my inexperience. I only picked the kit up last week and have been working long hours at work - i make lots of mistakes in the evening!

PaulS:
You’ve promised the compiler that you will return a value. But, you don’t. Stop lying. Either return a value or change the function return type to void.

So this should be void Boostbar()? An example I found online used long and I just copied it and it worked. I will change that.

PaulS:
Why do you unconditionally and conditionally assign the same value to difference?

This was an attempt to get the code to update difference. With no input, it should show difference = 0 on the screen but it was showing 1 or -1. I thought that was because it never got the chance to update as it was previously only updated inside the if statement.

PaulS:

    tft.setCursor(60,20);tft.fillRect(20, 20, 80, 14, BLACK);

How many statements go on one line? ANY answer other than ONE is WRONG!

I gave up on trying to read your code. It looks like it was typed by a drunken monkey.

Put EVERY { on a line BY ITSELF.
Use Tools + Auto Format to properly indent that mess.

Thanks for letting me know about the Auto Format - I didnt know that existed.

PaulS:
The cases use constants that are a multiple of PSI. You really do NOT need 10 cases to handle the values 0 to 9. You don’t need 6 more cases to handle the values 10 to 15. A little thought would eliminate most of the code in drawBar2().

Not sure that I understand what the issue is here. Doesnt the map() function equally split the sensor range (0-720) into 16 segments at the moment? That is intentional, I want to see the small changes in pressure. In fact, I plan to expand it to 32 cases. If I have missed the point please let me know.

arduarn:
Simplify things slightly first to make the task easier. Just wipe out the old bar chart with a big rectangle each time and focus on the drawing of the bar. When you get that working, then you can optimise the wiping too.

The issue with that approach is that in the past, the TFT was slow to update a large area and doing this quickly caused the graphics to flash - when trying other graphics. Nevertheless, I will try this for the bargraph and see if I can minimise the frequency of total wipes.

Again, thank you all for the help so far - the rest of the project is coming along nicely!

Extra question. can the TX/RX lines be used to control a 5V relay? The only free pins I have are TX/RX and A5, and A5 is my sensor input. Will I have to disconnect the relay to reprogram the Arduino?

Cheers!

Doesnt the map() function equally split the sensor range (0-720) into 16 segments at the moment?

Yes. But, the 16 segments are all drawn identically. The only difference is WHERE the segment is drawn. Create a function that draws a segment, taking the PSI value as input, that determines where based on PSI.

Call that function instead of replicating the code.

Changing from 16 steps to 32 steps then will NOT involve changing 16 blocks of code and adding 16 more.

Separate the text creation from the bar creation.

Doing those two things will show that each case is nearly identical, and show that the switch statement is not really necessary.

PaulS: Yes. But, the 16 segments are all drawn identically. The only difference is WHERE the segment is drawn. Create a function that draws a segment, taking the PSI value as input, that determines where based on PSI.

Call that function instead of replicating the code.

Changing from 16 steps to 32 steps then will NOT involve changing 16 blocks of code and adding 16 more.

Separate the text creation from the bar creation.

Doing those two things will show that each case is nearly identical, and show that the switch statement is not really necessary.

Thanks PaulS,

So are you suggesting something like this:

void BoostBar() {
  int mapSen = analogRead(A5);
  int PSI = map(mapSen,0,720,0,15);
  tft.fillRect(20+(PSI*10),40,9,160,RED);
}

I'm at work at the moment, can't test it out here - but PSI should be an integer between 0 and 15, which would be drawn on the screen as a RED filled rect in one of 16 locations depending on the PSI? Love it!

So are you suggesting something like this

What is the first argument to fillRect()? I would expect that to be constant (the lower, left corner) and the 2nd argument (the upper, left corner?) to be what varied.

But, try that, and see what it actually does.

PaulS: What is the first argument to fillRect()? I would expect that to be constant (the lower, left corner) and the 2nd argument (the upper, left corner?) to be what varied.

But, try that, and see what it actually does.

fillRect() has 5 arguments, in order: origin x position, origin y position, width, height, colour.

I want the width, height and colour to remain constant, as well as the y position, just varying the origin should do the trick.

Great! now onto the wiping mechanism. It only needs to wipe when the PSI moves towards the centreline, as I would like the rest of the bar to remain visible but if that is not possible I will settle with a big black fillRect()

Great! now onto the wiping mechanism. It only needs to wipe when the PSI moves towards the centreline

Moving left or moving right? I don't understand this statement. I would expect you to have to draw two rectangles every time - one the pressure color and one the no-pressure color. The total width of the two rectangles will be constant, as will the x origin of one them. The width of that one, and the origin of the other one will change, depending on the value in PSI.

Thats the issue, moving left when the boost level decreases from peak (around +16PSI (30PSI including 14.3PSI Atmospheric) and then moving right when the vacuum decreases from 0PSI (absolute).

Heres a crappy drawing. The || in the middle is the bar graph “zero” line. To the left is Vac, where my engine intake manifold will be lower pressure than the outside world, and to the right is relative boost where my turbocharger is forcing air into the engine above atmospheric pressure.

|—Vacuum range—||-------Boost Range--------|

So the bars will need to move >>> when in boost
and move <<< when in vac
and erase themselves when needed.

Also to answer your question regarding the fillRect() arguments. The x and y coords are relative to the top left of the landscape oriented screen. So the first two arguments set a point and then the rect is drawn across > then down /.

I’m sure the drawing of the bars is solved, but the erasing might require some wizardry I thought might be solved with the switch case… hmmmm…

Full code so far

#include <Elegoo_GFX.h>    // Core graphics library
#include <Elegoo_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

//Touch For New ILI9341 TP
#define TS_MINX 120
#define TS_MAXX 900

#define TS_MINY 70
#define TS_MAXY 920

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

#define	BLACK   0x0000
#define	BLUE    0x002F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

#define BOXSIZE 40
#define PENRDIUS 3
int oldcolor, currentcolor = RED;
int screen = 0;
int graphcount = 0;
int barcount = 0;
int newBar = 0;
int lastBar = 0;
int lastPSI = 0;
int PSI = 0;
int currentbar = 0;
int difference = 0;
int atmpsi = 14.35;

void setup(void) {

  Serial.begin(9600);
  Serial.println(F("TFT LCD test"));

#ifdef USE_Elegoo_SHIELD_PINOUT
  Serial.println(F("Using Elegoo 2.4\" TFT Arduino Shield Pinout"));
#else
  Serial.println(F("Using Elegoo 2.4\" TFT Breakout Board Pinout"));
#endif

  Serial.print("TFT size is "); Serial.print(tft.width()); Serial.print("x"); Serial.println(tft.height());

  tft.reset();

  uint16_t identifier = tft.readID();
  identifier = 0x9341;
  Serial.println(F("Found 0x9341 LCD driver"));

  tft.begin(identifier);
  tft.setRotation(3);
  tft.fillScreen(BLACK);

  tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
  tft.fillRect(280, BOXSIZE, BOXSIZE, BOXSIZE, MAGENTA);
  tft.fillRect(280, BOXSIZE * 2, BOXSIZE, BOXSIZE, GREEN);
  tft.drawRect(280, 0, BOXSIZE, BOXSIZE, WHITE);
  currentcolor = RED;

  pinMode(13, OUTPUT);

}

#define MINPRESSURE 10
#define MAXPRESSURE 1000


void loop()
{
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);

  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);

  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {}

  p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
  p.y = (tft.height() - map(p.y, TS_MINY, TS_MAXY, tft.height(), 0));

  if (p.y > 210) {
    oldcolor = currentcolor;

    if (p.x > 280) {
      tft.fillScreen(BLACK);
      Screen1();
      screen = 1;
    } else if (p.x > 210) {
      tft.fillScreen(BLACK);
      Screen2();
      screen = 2;
    } else if (p.x > 140) {
      tft.fillScreen(BLACK);
      Screen3();
      screen = 3;
    }

    if (oldcolor != currentcolor) {
      if (oldcolor == RED) tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
      if (oldcolor == MAGENTA) tft.fillRect(280, 40, BOXSIZE, BOXSIZE, MAGENTA);
      if (oldcolor == GREEN) tft.fillRect(280, 80, BOXSIZE, BOXSIZE, GREEN);
    }
  }

  int mapSen = analogRead(A5);
  float boost = ((((float)mapSen / (float)1023 + 0.04) / .004) * .145) - atmpsi;
  tft.setTextColor(GREEN);
  tft.setTextSize(2);
  tft.fillRect(100, 0, 60, 20, BLACK);
  tft.setCursor(100, 0);
  tft.print(boost);
  tft.print(" PSI");
  delay(5);

  if (currentcolor == GREEN) {
    Boostgraph();
    tft.setTextColor(GREEN);
    tft.setTextSize(2);
    tft.fillRect(210, 0, 40, 20, BLACK);
    tft.print(" ON");
  }

  if (currentcolor == RED) {
    BarGraph();
    BoostBar();
    tft.setTextColor(GREEN);
    tft.setTextSize(2);
    tft.fillRect(210, 0, 40, 20, BLACK);
  }
}

//END OF VOID LOOP

void Elephant() {
  tft.setCursor(0, 0);
  tft.println();
  tft.setTextColor(GREEN);
  tft.setTextSize(2);
  tft.println("He thought he saw");
  tft.setTextSize(3);
  tft.println("an Elephant");
}

void Screen1() {
  currentcolor = RED;
  tft.drawRect(280, 0, BOXSIZE, BOXSIZE, WHITE);
  tft.fillRect(280, 40, BOXSIZE, BOXSIZE, MAGENTA);
  tft.fillRect(280, 80, BOXSIZE, BOXSIZE, GREEN);
  tft.setCursor(290, 12); tft.print("1");
  BarGraph();
  BoostBar();
}


void Screen2() {
  currentcolor = MAGENTA;
  Elephant();
  tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
  tft.drawRect(280, 40, BOXSIZE, BOXSIZE, WHITE);
  tft.fillRect(280, 80, BOXSIZE, BOXSIZE, GREEN);
  tft.setCursor(290, 52); tft.print("2");
}

void Screen3() {
  currentcolor = GREEN;
  tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
  tft.fillRect(280, 40, BOXSIZE, BOXSIZE, MAGENTA);
  tft.drawRect(280, 80, BOXSIZE, BOXSIZE, WHITE);
  tft.setTextColor(GREEN); tft.setTextSize(1);
  tft.setCursor(290, 102); tft.print("3");
  Graph();
  Boostgraph();
}

void Graph() {
  tft.drawFastVLine(20, 40, 160, WHITE); //Origin is at (20,200) Address at 21, 201
  tft.drawFastHLine(20, 200, 240, WHITE); //bottom
  //tft.drawFastHLine(20, 120, 240, WHITE); //middle
  tft.setTextColor(GREEN); tft.setTextSize(2);
  tft.setCursor(0, 0); tft.print("BOOST");
}

void BarGraph() {
  tft.drawFastVLine(89, 40, 160, WHITE);
  //tft.drawFastHLine(20, 120, 240, WHITE); //middle
  tft.setTextColor(GREEN); tft.setTextSize(2);
  tft.setCursor(0, 0); tft.print("BAR");
}

void Sinewave() {
  int count;
  float i = 0.0;
  for (i = 0.0; i < 24.0; i = i + (0.1)) {
    count = count + 1;
    delay(1);
    tft.drawFastHLine(20 + count, 120 + (80 * sin(i)), 1, BLUE);
    tft.drawFastHLine(20 + count - 1, 120, 1, WHITE);
    tft.fillRect(21 + count, 40, 15, 160, BLACK);
  }
}

void Boostgraph() {
  int mapSen = analogRead(A5);
  float boost = ((((float)mapSen / (float)1023 + 0.04) / .004) * .145) - atmpsi;
  graphcount = graphcount + 1;
  if (graphcount == 240) {
    graphcount = 0;
  }
  tft.fillRect(21 + graphcount, 40, 12, 160, BLACK);
  tft.drawFastHLine(21 + graphcount, 120 + (boost * -40), 1, BLUE);
}

void BoostBar() {
  int mapSen = analogRead(A5);
  int PSI = map(mapSen, 0, 720, 0, 15);
  difference = PSI - currentbar;

  if (PSI != currentbar) {
    difference = PSI - currentbar;
    drawBar(PSI);
  }
}

void drawBar (int PSI) {
  tft.setCursor(60, 20);
  tft.fillRect(20, 20, 80, 14, BLACK);
  tft.print(difference);
  tft.fillRect(20 + (PSI * 10), 40, 9, 160, RED);
}

It works! This is code does what I want it to. Video to follow.

void BoostBar() {
  delay(6);
  int mapSen = analogRead(A5);
  delay(10);
  int mapSen2 = analogRead(A5);
  delay(10);
  int mapSen3 = analogRead(A5);
  int PSI = map(((mapSen+mapSen2+mapSen3)/3), 0, 720, 0, 31);
  difference = PSI - currentbar;

  tft.setCursor(60, 20);
  tft.fillRect(20, 20, 80, 14, BLACK);
  tft.setCursor(20, 20);
  tft.print(PSI);
  tft.setCursor(40, 20);
  tft.print(currentbar);
  tft.setCursor(60, 20);
  tft.print(difference);

  if (PSI != currentbar) {
    drawBar(PSI);
  }
}

void drawBar (int PSI) {


  if (PSI >= 15) {
    tft.fillRect(-60 + (PSI * 10), 40, 9, 160, RED);
    tft.fillRect(60,40,29,160,BLACK);
  }
  if ((PSI >= 15) && (difference == -1)) {
    tft.fillRect(-50 + (PSI * 10), 40, 29, 160, BLACK);
  }
  if (PSI < 15) {
    tft.fillRect(90 - ((15 - PSI) * 10), 40, 9, 160, BLUE);
    tft.fillRect(90,40,29,160,BLACK);
  }
  if ((PSI < 15) && (difference == 1)) {
    tft.fillRect(70 - ((15 - PSI) * 10), 40, 19, 160, BLACK);
  }
  currentbar = PSI;
}

Complete code here:

#include <Elegoo_GFX.h>    // Core graphics library
#include <Elegoo_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

//Touch For New ILI9341 TP
#define TS_MINX 120
#define TS_MAXX 900

#define TS_MINY 70
#define TS_MAXY 920

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

#define	BLACK   0x0000
#define	BLUE    0x002F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

#define BOXSIZE 40
#define PENRDIUS 3
int oldcolor, currentcolor = RED;
int screen = 0;
int graphcount = 0;
int barcount = 0;
int newBar = 0;
int lastBar = 0;
int lastPSI = 0;
int PSI = 0;
int currentbar = 7;
int difference = 0;
int atmpsi = 14.35;

void setup(void) {

  Serial.begin(9600);
  Serial.println(F("TFT LCD test"));

#ifdef USE_Elegoo_SHIELD_PINOUT
  Serial.println(F("Using Elegoo 2.4\" TFT Arduino Shield Pinout"));
#else
  Serial.println(F("Using Elegoo 2.4\" TFT Breakout Board Pinout"));
#endif

  Serial.print("TFT size is "); Serial.print(tft.width()); Serial.print("x"); Serial.println(tft.height());

  tft.reset();

  uint16_t identifier = tft.readID();
  identifier = 0x9341;
  Serial.println(F("Found 0x9341 LCD driver"));

  tft.begin(identifier);
  tft.setRotation(3);
  tft.fillScreen(BLACK);

  tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
  tft.fillRect(280, BOXSIZE, BOXSIZE, BOXSIZE, MAGENTA);
  tft.fillRect(280, BOXSIZE * 2, BOXSIZE, BOXSIZE, GREEN);
  tft.drawRect(280, 0, BOXSIZE, BOXSIZE, WHITE);
  currentcolor = RED;

  pinMode(13, OUTPUT);

}

#define MINPRESSURE 10
#define MAXPRESSURE 1000


void loop()
{
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);

  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);

  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {}

  p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
  p.y = (tft.height() - map(p.y, TS_MINY, TS_MAXY, tft.height(), 0));

  if (p.y > 210) {
    oldcolor = currentcolor;

    if (p.x > 280) {
      tft.fillScreen(BLACK);
      Screen1();
      screen = 1;
    } else if (p.x > 210) {
      tft.fillScreen(BLACK);
      Screen2();
      screen = 2;
    } else if (p.x > 140) {
      tft.fillScreen(BLACK);
      Screen3();
      screen = 3;
    }

    if (oldcolor != currentcolor) {
      if (oldcolor == RED) tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
      if (oldcolor == MAGENTA) tft.fillRect(280, 40, BOXSIZE, BOXSIZE, MAGENTA);
      if (oldcolor == GREEN) tft.fillRect(280, 80, BOXSIZE, BOXSIZE, GREEN);
    }
  }

  int mapSen = analogRead(A5);
  float boost = ((((float)mapSen / (float)1023 + 0.04) / .004) * .145) - atmpsi;
  tft.setTextColor(GREEN);
  tft.setTextSize(2);
  tft.fillRect(100, 0, 60, 20, BLACK);
  tft.setCursor(100, 0);
  tft.print(boost);
  tft.print(" PSI");
  delay(5);

  if (currentcolor == GREEN) {
    Boostgraph();
    tft.setTextColor(GREEN);
    tft.setTextSize(2);
    tft.fillRect(210, 0, 40, 20, BLACK);
    tft.print(" ON");
  }

  if (currentcolor == RED) {
    BarGraph();
    BoostBar();
    tft.setTextColor(GREEN);
    tft.setTextSize(2);
    tft.fillRect(210, 0, 40, 20, BLACK);
  }
}

//END OF VOID LOOP

void Elephant() {
  tft.setCursor(0, 0);
  tft.println();
  tft.setTextColor(GREEN);
  tft.setTextSize(2);
  tft.println("He thought he saw");
  tft.setTextSize(3);
  tft.println("an Elephant");
}

void Screen1() {
  currentcolor = RED;
  tft.drawRect(280, 0, BOXSIZE, BOXSIZE, WHITE);
  tft.fillRect(280, 40, BOXSIZE, BOXSIZE, MAGENTA);
  tft.fillRect(280, 80, BOXSIZE, BOXSIZE, GREEN);
  tft.setCursor(290, 12); tft.print("1");
  BarGraph();
  BoostBar();
}


void Screen2() {
  currentcolor = MAGENTA;
  Elephant();
  tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
  tft.drawRect(280, 40, BOXSIZE, BOXSIZE, WHITE);
  tft.fillRect(280, 80, BOXSIZE, BOXSIZE, GREEN);
  tft.setCursor(290, 52); tft.print("2");
}

void Screen3() {
  currentcolor = GREEN;
  tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
  tft.fillRect(280, 40, BOXSIZE, BOXSIZE, MAGENTA);
  tft.drawRect(280, 80, BOXSIZE, BOXSIZE, WHITE);
  tft.setTextColor(GREEN); tft.setTextSize(1);
  tft.setCursor(290, 102); tft.print("3");
  Graph();
  Boostgraph();
}

void Graph() {
  tft.drawFastVLine(20, 40, 160, WHITE); //Origin is at (20,200) Address at 21, 201
  tft.drawFastHLine(20, 200, 240, WHITE); //bottom
  //tft.drawFastHLine(20, 120, 240, WHITE); //middle
  tft.setTextColor(GREEN); tft.setTextSize(2);
  tft.setCursor(0, 0); tft.print("BOOST");
}

void BarGraph() {
  tft.drawFastVLine(89, 40, 160, WHITE);
  //tft.drawFastHLine(20, 120, 240, WHITE); //middle
  tft.setTextColor(GREEN); tft.setTextSize(2);
  tft.setCursor(0, 0); tft.print("BAR");
}

void Sinewave() {
  int count;
  float i = 0.0;
  for (i = 0.0; i < 24.0; i = i + (0.1)) {
    count = count + 1;
    delay(1);
    tft.drawFastHLine(20 + count, 120 + (80 * sin(i)), 1, BLUE);
    tft.drawFastHLine(20 + count - 1, 120, 1, WHITE);
    tft.fillRect(21 + count, 40, 15, 160, BLACK);
  }
}

void Boostgraph() {
  int mapSen = analogRead(A5);
  float boost = ((((float)mapSen / (float)1023 + 0.04) / .004) * .145) - atmpsi;
  graphcount = graphcount + 1;
  if (graphcount == 240) {
    graphcount = 0;
  }
  tft.fillRect(21 + graphcount, 40, 12, 160, BLACK);
  tft.drawFastHLine(21 + graphcount, 120 + (boost * -40), 1, BLUE);
}

void BoostBar() {
  delay(6);
  int mapSen = analogRead(A5);
  delay(10);
  int mapSen2 = analogRead(A5);
  delay(10);
  int mapSen3 = analogRead(A5);
  int PSI = map(((mapSen+mapSen2+mapSen3)/3), 0, 720, 0, 31);
  difference = PSI - currentbar;

  tft.setCursor(60, 20);
  tft.fillRect(20, 20, 80, 14, BLACK);
  tft.setCursor(20, 20);
  tft.print(PSI);
  tft.setCursor(40, 20);
  tft.print(currentbar);
  tft.setCursor(60, 20);
  tft.print(difference);

  if (PSI != currentbar) {
    drawBar(PSI);
  }
}

void drawBar (int PSI) {


  if (PSI >= 15) {
    tft.fillRect(-60 + (PSI * 10), 40, 9, 160, RED);
    tft.fillRect(60,40,29,160,BLACK);
  }
  if ((PSI >= 15) && (difference == -1)) {
    tft.fillRect(-50 + (PSI * 10), 40, 29, 160, BLACK);
  }
  if (PSI < 15) {
    tft.fillRect(90 - ((15 - PSI) * 10), 40, 9, 160, BLUE);
    tft.fillRect(90,40,29,160,BLACK);
  }
  if ((PSI < 15) && (difference == 1)) {
    tft.fillRect(70 - ((15 - PSI) * 10), 40, 19, 160, BLACK);
  }
  currentbar = PSI;
}
  int mapSen = analogRead(A5);
  delay(10);
  int mapSen2 = analogRead(A5);
  delay(10);
  int mapSen3 = analogRead(A5);

A pet peeve of mine. Do you count “uh-huh, two, three”?, or do you count “one, two, three”?

Why do you need three variables? Do the individual values matter?

   int mapSen = 0;
   for(byte b=0; b<3; b++)
   {
      mapSen += analogRead(A5);
      delay(10);
   }
   int mapAvg = mapSen / 3;
   int PSI = map(mapAvg, 0, 720, 0, 31);

PaulS:

   int mapSen = 0;

for(byte b=0; b<3; b++)
  {
      mapSen += analogRead(A5);
      delay(10);
  }
  int mapAvg = mapSen / 3;
  int PSI = map(mapAvg, 0, 720, 0, 31);

Thanks, thats very nice :slight_smile: I’ll add that in this evening

The bar behaves how I want it to, but if PSI changes too rapidly it can move faster than the erase code can handle - it ends up leaving coloured bars stranded away from the actual reading. I need a way for PSI to only change by ±1 and then re-check to see if it meets the actual PSI. Do you think another for loop could solve this?

I need a way for PSI to only change by +-1 and then re-check to see if it meets the actual PSI. Do you think another for loop could solve this?

No. But an if statement and an assignment statement could.

static int oldPSI = 0;
int diff = abs(oldPSI - PSI);
if(diff > 1)
{
   if(PSI > oldPSI) // if pressure went up more than 1 psi, clamp it to 1
      PSI = oldPSI + 1;
   else // if pressure went down more than 1 psi, clamp it at -1
      PSI = oldPSI - 1;
}
oldPSI = PSI;

This might cause the initial reading to take a while to be reflected on the display. If it does, and that is a problem, you could use a global boolean, inited = false, and set oldPSI to PSI if !inited and then set inited = true.

Excellent! Thanks for your help PaulS, I will let you know how I get on tonight

Success! Works great! The initialisation basically scrolls from 0 to 15 but it erases as it goes and looks kinda cool actually so im leaving it :smiley:

https://youtu.be/AMIMXQrlIuM

Here’s what it looks like.

This is the code for the entire project:

#include <Elegoo_GFX.h>    // Core graphics library
#include <Elegoo_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

//Touch For New ILI9341 TP
#define TS_MINX 120
#define TS_MAXX 900

#define TS_MINY 70
#define TS_MAXY 920

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

#define	BLACK   0x0000
#define	BLUE    0x002F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

#define BOXSIZE 40
#define PENRDIUS 3
int oldcolor, currentcolor = RED;
int screen = 0;
int graphcount = 0;
int barcount = 0;
int newBar = 0;
int lastBar = 0;
int lastPSI = 0;
int PSI = 0;
int currentbar = 7;
int difference = 0;
int atmpsi = 14.35;
boolean inited = false;

void setup(void) {

  Serial.begin(9600);
  Serial.println(F("TFT LCD test"));

#ifdef USE_Elegoo_SHIELD_PINOUT
  Serial.println(F("Using Elegoo 2.4\" TFT Arduino Shield Pinout"));
#else
  Serial.println(F("Using Elegoo 2.4\" TFT Breakout Board Pinout"));
#endif

  Serial.print("TFT size is "); Serial.print(tft.width()); Serial.print("x"); Serial.println(tft.height());

  tft.reset();

  uint16_t identifier = tft.readID();
  identifier = 0x9341;
  Serial.println(F("Found 0x9341 LCD driver"));

  tft.begin(identifier);
  tft.setRotation(3);
  tft.fillScreen(BLACK);

  tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
  tft.fillRect(280, BOXSIZE, BOXSIZE, BOXSIZE, MAGENTA);
  tft.fillRect(280, BOXSIZE * 2, BOXSIZE, BOXSIZE, GREEN);
  tft.drawRect(280, 0, BOXSIZE, BOXSIZE, WHITE);
  currentcolor = RED;

  pinMode(13, OUTPUT);

}

#define MINPRESSURE 10
#define MAXPRESSURE 1000


void loop()
{
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);

  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);

  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {}

  p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
  p.y = (tft.height() - map(p.y, TS_MINY, TS_MAXY, tft.height(), 0));

  if (p.y > 210) {
    oldcolor = currentcolor;

    if (p.x > 280) {
      tft.fillScreen(BLACK);
      Screen1();
      screen = 1;
    } else if (p.x > 210) {
      tft.fillScreen(BLACK);
      Screen2();
      screen = 2;
    } else if (p.x > 140) {
      tft.fillScreen(BLACK);
      Screen3();
      screen = 3;
    }

    if (oldcolor != currentcolor) {
      if (oldcolor == RED) tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
      if (oldcolor == MAGENTA) tft.fillRect(280, 40, BOXSIZE, BOXSIZE, MAGENTA);
      if (oldcolor == GREEN) tft.fillRect(280, 80, BOXSIZE, BOXSIZE, GREEN);
    }
  }

  int mapSen = analogRead(A5);
  float boost = ((((float)mapSen / (float)1023 + 0.04) / .004) * .145) - atmpsi;
  tft.setTextColor(GREEN);
  tft.setTextSize(2);
  tft.fillRect(100, 0, 60, 20, BLACK);
  tft.setCursor(100, 0);
  tft.print(boost);
  tft.print(" PSI");
  delay(5);

  if (currentcolor == GREEN) {
    Boostgraph();
    tft.setTextColor(GREEN);
    tft.setTextSize(2);
    tft.fillRect(210, 0, 40, 20, BLACK);
    tft.print(" ON");
  }

  if (currentcolor == RED) {
    BarGraph();
    BoostBar();
    tft.setTextColor(GREEN);
    tft.setTextSize(2);
    tft.fillRect(210, 0, 40, 20, BLACK);
  }
}

//END OF VOID LOOP

void Elephant() {
  tft.setCursor(0, 0);
  tft.println();
  tft.setTextColor(GREEN);
  tft.setTextSize(2);
  tft.println("He thought he saw");
  tft.setTextSize(3);
  tft.println("an Elephant");
}

void Screen1() {
  currentcolor = RED;
  tft.drawRect(280, 0, BOXSIZE, BOXSIZE, WHITE);
  tft.fillRect(280, 40, BOXSIZE, BOXSIZE, MAGENTA);
  tft.fillRect(280, 80, BOXSIZE, BOXSIZE, GREEN);
  tft.setCursor(290, 12); tft.print("1");
  BarGraph();
  BoostBar();
}


void Screen2() {
  currentcolor = MAGENTA;
  Elephant();
  tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
  tft.drawRect(280, 40, BOXSIZE, BOXSIZE, WHITE);
  tft.fillRect(280, 80, BOXSIZE, BOXSIZE, GREEN);
  tft.setCursor(290, 52); tft.print("2");
}

void Screen3() {
  currentcolor = GREEN;
  tft.fillRect(280, 0, BOXSIZE, BOXSIZE, RED);
  tft.fillRect(280, 40, BOXSIZE, BOXSIZE, MAGENTA);
  tft.drawRect(280, 80, BOXSIZE, BOXSIZE, WHITE);
  tft.setTextColor(GREEN); tft.setTextSize(1);
  tft.setCursor(290, 102); tft.print("3");
  Graph();
  Boostgraph();
}

void Graph() {
  tft.drawFastVLine(20, 40, 160, WHITE); //Origin is at (20,200) Address at 21, 201
  tft.drawFastHLine(20, 200, 240, WHITE); //bottom
  //tft.drawFastHLine(20, 120, 240, WHITE); //middle
  tft.setTextColor(GREEN); tft.setTextSize(2);
  tft.setCursor(0, 0); tft.print("BOOST");
}

void BarGraph() {
  tft.drawFastVLine(89, 40, 160, WHITE);
  //tft.drawFastHLine(20, 120, 240, WHITE); //middle
  tft.setTextColor(GREEN); tft.setTextSize(2);
  tft.setCursor(0, 0); tft.print("BAR");
}

void Sinewave() {
  int count;
  float i = 0.0;
  for (i = 0.0; i < 24.0; i = i + (0.1)) {
    count = count + 1;
    delay(1);
    tft.drawFastHLine(20 + count, 120 + (80 * sin(i)), 1, BLUE);
    tft.drawFastHLine(20 + count - 1, 120, 1, WHITE);
    tft.fillRect(21 + count, 40, 15, 160, BLACK);
  }
}

void Boostgraph() {
  int mapSen = analogRead(A5);
  float boost = ((((float)mapSen / (float)1023 + 0.04) / .004) * .145) - atmpsi;
  graphcount = graphcount + 1;
  if (graphcount == 240) {
    graphcount = 0;
  }
  tft.fillRect(21 + graphcount, 40, 12, 160, BLACK);
  tft.drawFastHLine(21 + graphcount, 120 + (boost * -40), 1, BLUE);
}

void BoostBar() {

  int mapSen = 0;
  static int oldPSI;
  for (byte b = 0; b < 3; b++) {
    mapSen += analogRead(A5);
    delay(10);
  }
  int mapAvg = mapSen / 3;
  int PSI = map(mapAvg, 0, 720, 0, 31);
  difference = PSI - currentbar;

  tft.fillRect(0, 20, 40, 20, BLACK);
  tft.setCursor(0, 20);
  tft.print(difference);

  if (PSI != currentbar) {
    int diff = abs(oldPSI - PSI);
    if (diff > 1) {
      if (PSI > oldPSI)
        PSI = oldPSI + 1;
      else
        PSI = oldPSI - 1;
    }
    drawBar(PSI);
    oldPSI = PSI;
  }
}

void drawBar (int PSI) {

  if (PSI >= 15) {
    tft.fillRect(90 + ((PSI - 15) * 10), 40, 9, 160, RED);
    tft.fillRect(80, 40, 9, 160, BLACK);
  }
  if ((PSI >= 15) && (difference <= -1)) {
    tft.fillRect(90 + ((PSI - 14) * 10), 40, 9, 160, BLACK);
  }
  if (PSI < 15) {
    tft.fillRect(90 - ((15 - PSI) * 10), 40, 9, 160, BLUE);
    tft.fillRect(90, 40, 9, 160, BLACK);
  }
  if ((PSI < 15) && (difference >= 1)) {
    tft.fillRect(80 - ((15 - PSI) * 10), 40, 9, 160, BLACK);
  }
  currentbar = PSI;
}