2.8" TFT and Thermocouple - Refresh Issues

Hello forum,
I am a bit of a newbie to Arduino, but have some experience programming. I am baffled by the issue I am having with my current project: a Mega 2650, with 2.8" TFT, and thermocouple amplifiers to sense and display cylinder head and exhaust gas temps on an air-cooled Volkswagen.

I am using an mcufriend 2.8" TFT touchscreen with the fine library available at MCUFRIEND_kbv Library for Uno 2.4, 2.8, 3.5, 3.6, 3.95 inch mcufriend Shields - Displays - Arduino Forum

I am using one MAX 6675 thermocouple amplifier board currently, with the fine library available at GitHub - adafruit/MAX6675-library: Arduino library for interfacing with MAX6675 thermocouple amplifier

This is running on a Mega 2650, which I realize is not ideal for this screen, but I needed the end of the board open for four total thermocouple amps. It is still much faster than I need for what is essentially a multi-gauge.


The issue I have is that the code executes, and displays the correct temperature, but print() and printNumI() will not overwrite the initial thermocouple reading unless I use clrScr(), which allows it to update the proper temp. Mind you, I added a cycle counter using the same call (printNumI[]), and it works correctly, counting up main loop executions while the thermocouple temp remains static. Here is my code, which I cobbled together from two known working sketches (one for the thermocouple and one for the screen):

#define TOUCH_ORIENTATION  LANDSCAPE

#include <Adafruit_GFX.h>
#include <UTFTGLUE.h>            //we are using UTFT display methods
UTFTGLUE myGLCD(0x9341, A2, A1, A3, A4, A0);
#include <max6675.h>

// ThermoCouple
int thermo_gnd_pin = 45;
int thermo_vcc_pin = 47;
int thermo_so_pin  = 53;
int thermo_cs_pin  = 51;
int thermo_sck_pin = 49;

int count = 0;
  
MAX6675 thermocouple(thermo_sck_pin, thermo_cs_pin, thermo_so_pin);


extern uint8_t SmallFont[];

uint32_t cx, cy;
uint32_t rx[8], ry[8];
int32_t clx, crx, cty, cby;
float px, py;
int dispx, dispy, text_y_center, swapxy;
uint32_t calx, caly, cals;
char buf[13];

void setup()
{
    Serial.begin(9600);
      pinMode(thermo_vcc_pin, OUTPUT); 
  pinMode(thermo_gnd_pin, OUTPUT); 
  digitalWrite(thermo_vcc_pin, HIGH);
  digitalWrite(thermo_gnd_pin, LOW);
    digitalWrite(A0, HIGH);
    pinMode(A0, OUTPUT);
    myGLCD.InitLCD(TOUCH_ORIENTATION);
    myGLCD.clrScr();
    myGLCD.setFont(SmallFont);
    dispx = myGLCD.getDisplayXSize();
    dispy = myGLCD.getDisplayYSize();
    text_y_center = (dispy / 2) - 6;
    myGLCD.print("Temp:", CENTER, text_y_center - 12);
}

void loop()
{
    myGLCD.setColor(255, 255, 255);
    myGLCD.setBackColor(0, 0, 0);
    //myGLCD.clrScr();
    myGLCD.printNumI(int(thermocouple.readFahrenheit()), CENTER, text_y_center);
    myGLCD.printNumI(count, CENTER, text_y_center + 12);
    count++;
}

TFT_Thermocouple_Test_no_touch.ino (1.52 KB)

I'm not familiar with the UTFT library, but in general, you need to remove existing text before writing new ones. Clearing the complete screen will obviously do this, but updating the entire screen takes a long time, and looks terrible.

In the Adafruit libraries, you can (if using the default font) set the font background colour to be the same as the screen background colour. This automatically blanks out any existing characters when you write new ones. If you use any of the additional fonts, you can't do this, as you can't set the text background colour. You have a couple of options:

  1. Print a rectangle over the existing text. Similar to clearing the screen, but only in a small area.
  2. Print the existing text in the screen background colour to delete the existing characters , and then print the new text in the text colour.

Both work, but option 2 looks a lot better and you don't really see the text flash as it's changed.

Cheers,

Ian.

Ian,
Thanks for your reply. The process of setting the background color of the text, and using it to clear previous text, is exactly how my sketch is set up. Like I said, the line below it, which displays a simple integer, refreshes properly as written.

I'll give the rectangle a try, but I'd be shocked if it works, since I'm effectively already doing that with the text background.

Assuming you're trying to cast the thermocouple reading to an integer, I'm not sure this line is entirely correct:

myGLCD.printNumI(int(thermocouple.readFahrenheit()), CENTER, text_y_center);

Either that, or I've never seen it done like that before.

Have you tried without trying to cast ?

Cheers,

Ian.

Oh, I forgot I posted it like that. Yes, that's one of many ways I have tried. Other options I have tried with exactly the same result:

myGLCD.printNumI(thermocouple.readFahrenheit()), CENTER, text_y_center);
myGLCD.print(String(thermocouple.readFahrenheit())), CENTER, text_y_center);
I have also tried loading it into a variable on a separate line (and inside a separate call), then simply printing that integer or string (the exact same code as my 'count' int). Same result.

It acts like the readFahrenheit function isn't updating until I use clrScr, but that doesn't make any sense.

Ok, back with some very strange info...

So the text updates properly if I arbitrarily draw a rectangle over most of the screen (myGLCD.fillRect(1,15,318,224);)...

HOWEVER, if I shrink the area of the rectangle to just cover the temp reading, leaving all other things constant, it no longer updates (myGLCD.fillRect(140,110,180,130);), despite the text continuing to flash as it is overwritten -- only to be replaced again with the outdated, original reading.

Either way, I think it might cause seizures. It looks awful, so I don't think manually drawing a rectangle is a viable solution. And this test only raises more questions as to why the device/library is behaving this way.

Any help is appreciated.

Strange.

I'm not sure if it would make a difference, but maybe try moving these lines to setup.

myGLCD.setColor(255, 255, 255);
myGLCD.setBackColor(0, 0, 0);

Not sure what happens in the background when these are set, but they probably don't need to be set every time through loop.

Ian.

An excellent suggestion. However, no change.

I just tried a completely different display library and calls at the suggestion of David Prentiss (library dev). Experienced EXACTLY the same symptoms. No matter if I draw a bar with the value of the thermocouple as the width, or if I black out the text after every print, thermocouple.readFahrenheit() is returning the same value every time -- only when the display is running.

UNLESS I unplug the thermocouple or TC amp. Then the function returns 32 and stays there. readCelsius() also drops to 0 and stays there, which makes sense.

So, I suspect that the whole issue lies somewhere in the thermocouple library. Perhaps there is an issue brought on by the slow loop speeds, or something else?

MAX6675.cpp

// this library is public domain. enjoy!
// www.ladyada.net/learn/sensors/thermocouple

#ifdef __AVR
  #include <avr/pgmspace.h>
#elif defined(ESP8266)
  #include <pgmspace.h>
#endif
#include <util/delay.h>
#include <stdlib.h>
#include "max6675.h"

MAX6675::MAX6675(int8_t SCLK, int8_t CS, int8_t MISO) {
  sclk = SCLK;
  cs = CS;
  miso = MISO;

  //define pin modes
  pinMode(cs, OUTPUT);
  pinMode(sclk, OUTPUT); 
  pinMode(miso, INPUT);

  digitalWrite(cs, HIGH);
}
double MAX6675::readCelsius(void) {

  uint16_t v;

  digitalWrite(cs, LOW);
  _delay_ms(1);

  v = spiread();
  v <<= 8;
  v |= spiread();

  digitalWrite(cs, HIGH);

  if (v & 0x4) {
    // uh oh, no thermocouple attached!
    return NAN; 
    //return -100;
  }

  v >>= 3;

  return v*0.25;
}

double MAX6675::readFahrenheit(void) {
  return readCelsius() * 9.0/5.0 + 32;
}

byte MAX6675::spiread(void) { 
  int i;
  byte d = 0;

  for (i=7; i>=0; i--)
  {
    digitalWrite(sclk, LOW);
    _delay_ms(1);
    if (digitalRead(miso)) {
      //set the bit to 0 no matter what
      d |= (1 << i);
    }

    digitalWrite(sclk, HIGH);
    _delay_ms(1);
  }

  return d;
}

MAX6675.h

// this library is public domain. enjoy!
// www.ladyada.net/learn/sensors/thermocouple

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

class MAX6675 {
 public:
  MAX6675(int8_t SCLK, int8_t CS, int8_t MISO);

  double readCelsius(void);
  double readFahrenheit(void);
  // For compatibility with older versions:
  double readFarenheit(void) { return readFahrenheit(); }
 private:
  int8_t sclk, miso, cs;
  uint8_t spiread(void);
};

Problem solved!

Over the weekend I found another library for the MAX 6675, apparently unrelated to the previous library: Ryan McLaughlin's library available at GitHub - mcleng/MAX6675-Library: MAX6675 Arduino Library.

Rewrote my code for his library, fired it up, and bingo. Works like a charm.

If anyone is interested in using a TFT for thermocouple display, I will post my code once it is done. This is probably the most economical way to do this my a long shot, and using a Mega with the Uno TFT means no off-board wiring. All plug-and-play.

Hi finchamp,

Sorry for dig out the old thread. Would you mind post your working code? Thanks in advance.