Faster Printing/ data handling on UTFT display with Mega2560

Hi Everyone,

First arduino/ C++ project.

I am using a Benewake TF03 laser range finder with a SPI Arduino 2.8"TFT Touch Shield Example w/ILI9341 for Mega/Due/Uno 240x320 pixels and an Arduino Mega2560.

The purpose of the project is to display the measured distance taken by the TF03 LIDAR.

Originally I wanted to smooth these values using an array and print them after X number of loops but I couldn’t make it work with my level of experience so I have made this pared down version which simply prints the distance measured to the screen and it does work.

Here is the problem:

The code seems to execute much slower than the actual delay time and the print outs on the screen take almost a second between each print even though I believe I have written it to do so every 1/2 second.

Also, I have tried to use what I believed to be the most efficient method to clear the last displayed distance so there aren’t a bunch printed on top of each other, but this seems very slow and it causes a distinct blink every time a new distance is printed.

Here is my code, I tried to make it as clear as possible what each element is meant to do in my mind:

/*************************
**  Declare Libraries   **
*************************/
#include <UTFT.h>
#include <UTouch.h>
UTFT myGLCD(ILI9341_4L, 3, 2, 9, 10, 7);      // LCD: 4Line  serial interface. Initialize display
UTouch  myTouch( 2, 6, 3, 4, 5);              // RTP: byte tclk, byte tcs, byte din, byte dout, byte irq

#include <SoftwareSerial.h>                   // Header file of software serial port
SoftwareSerial Serial4(50, 51);               // RX is digital pin 50 (connect to TX of TF03) TX is digital pin 51 (connect to RX of TF03)


/*************************
**  Declare Variables   **
*************************/
extern uint8_t BigFont[];                     // Declare which fonts we will be using
extern uint8_t Grotesk32x64[];
extern uint8_t Grotesk16x32[];
int dist;                                     // Actual distance measurements of LiDAR
int check;                                    // Save check value
int i;
int uart[9];                                  // Save data measured by LiDAR
const int HEADER = 0x59;                      // Frame header of data package from LiDAR
int numToAvg = 100;                           // The number of loops between each print
int incr = 0;                                 // Count the number of loops
int erase = 0;                                // Save the previous data measured by LiDAR to overwrite the old print


/*************************
** Initialization Tasks **
*************************/
void drawButtons()                                   // Draw the buttons
{

  myGLCD.setFont(BigFont);

  myGLCD.setColor(0, 0, 255);
  myGLCD.fillRoundRect (40, 180, 280, 230);
  myGLCD.setColor(255, 255, 255);                    // Set the stroke color to white
  myGLCD.drawRoundRect (40, 180, 280, 230);
  //myGLCD.setColor(255, 255, 255);
  myGLCD.print("0 ALL VALUES", 60, 197);             // 0s out the incr, erase, and dist int when there is a hang up

  myGLCD.setBackColor(0, 0, 0);
}


/*************************
**     Loop Setup       **
*************************/
void setup() {
  Serial.begin(115200);                              // Set bit rate of serial port connecting Arduino with computer
  Serial4.begin(115200);                             // Set bit rate of serial port connecting LiDAR with Arduino



  // Bring screen online
  myGLCD.InitLCD();
  myGLCD.clrScr();

  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);

  myGLCD.setBackColor(0, 0, 255);
  drawButtons();
}


/*************************
**   Main Program Loop  **
*************************/
void loop()
{

  // Read the value from the sensor
  if (Serial4.available()) {                         // Check if serial port has data input
    if (Serial4.read() == HEADER) {                  // Assess data package frame header 0x59
      uart[0] = HEADER;
      if (Serial4.read() == HEADER) {                // Assess data package frame header 0x59
        uart[1] = HEADER;
        for (i = 2; i < 9; i++) {                    // Save data in array
          uart[i] = Serial4.read();
        }
        check = uart[0] + uart[1] + uart[2] + uart[3] + uart[4] + uart[5] + uart[6] + uart[7];
        if (uart[8] == (check & 0xff)) {             // Verify the received data as per protocol
          dist = uart[2] + uart[3] * 256;            // Calculate distance value
        }
      }
    }
  }

  Serial.print("     "); Serial.print(dist);         // Sanity check on serial mon.
  
  incr++;
  if (incr == numToAvg)                              // Should allow the below statement to execute every half second when numToAvg = 100
  {
    if (dist < 30 || dist > 17999 )                  // Defines acceptable data range
    {
      myGLCD.setColor(255, 0, 0);
      myGLCD.setFont(Grotesk32x64);
      myGLCD.print("     ", CENTER, 20);
     
      myGLCD.print("BAD", CENTER, 20);
      delay(20);
      myGLCD.setColor(0, 0, 0);
      myGLCD.print("BAD", CENTER, 20);
    }

    else
    {
      dist = dist/ 30.48;                            // Converts distance in CM measured by LIDAR to feet
      if (dist != erase)                             // Only print the distance if it is different from the last
      {
      myGLCD.setFont(Grotesk32x64);
      
      myGLCD.setColor(0, 0, 0);
      myGLCD.printNumI(erase , CENTER, 20);          // Prints old value in black to 'erase' it from screen before printing the new
     
      myGLCD.setColor(255, 255, 255);                                                           
      myGLCD.printNumI(dist , CENTER, 20); myGLCD.print("FT", RIGHT, 20);
      
      erase = dist;                                  // Stores the newest value for the next execution of the printout
      }
    }
    incr = 0;
  }
    delay(5);                                        // Loops 200 times per second. LIDAR measureing frequency is set at 100HZ
  }

(note that the “0 all values” button is currently just displayed and unused at this point. I know how to implement that after I solve this issue.)

Im not sure where the bottleneck lies that cause the very apparent lag.

What can I do to make the display/ measurement “refresh” or execute faster and without the distinct black to white font blink?

Thank you!

Anyone got any ideas?

If you are using software serial on a Mega, you clearly aren't interested in doing anything quickly. Why would you do that when you have four hardware serial ports? And running software serial at 115200 is probably the kiss of death anyway. I'm surprised you have anything working.

Using a graphic display for text might not be such a good idea. A larger font may mean more drawing time taken. This may depend on the library you are using.

Nick_Pyner: software serial on a Mega, running software serial at 115200

This is a good point here is why Im doing it though;

The benewake LIDAR communicates at 115200

and the fact that the device is UART requires change interrupts: "Note: Not all pins on the Mega and Mega 2560 support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69"

Also; very early on I tried every hardware port and could get no data from them. Do you know why this may be or show how it should be written in my code to communicate via the hardware serials?

Thank you

show how it should be written in my code to communicate via the hardware serials?

Just connect the device to a pair of pins associated with one of the hardware Serial interfaces, begin() that interface and read from it

What did you try previously

UKHeliBob: Just connect the device to a pair of pins associated with one of the hardware Serial interfaces, begin() that interface and read from it

What did you try previously

I had:

void setup() {

    Serial1.begin(115200);   //19(RX), 18(TX)
}

and tried this with every hardware serial respectively with their pins and I was wondering if this has to do with change interrupts or if that,s a software serial only thing?

void setup() {

    Serial1.begin(115200);   //19(RX), 18(TX)
}

Looks OK as long as you connected your device the right way round and used the associated Serial1 functions

Whatever the problem was it had nothing to do with pin change interrupts because the serial interfaces are hardware UARTs

Nick_Pyner:

UKHeliBob:

Ok, so I realized past me was a little less educated on this stuff and was trying to declare pins for the hardware serial… no wonder it didnt work.

It does now and I’ve made some changes to my code which seem to have helped the speed; especially when watch the serial monitor. HOWEVER, now whenever the loop reach the correct count and the screen prints the there seems to be a lag in the data collection (as observed in the serial monitor). Which, when the distance value is constantly changing causing the Serial1 to print on GLCD the data collection is too slow…

I understand this may be due to the nature of C++ and how loops execute line by line. SO, how can run the data collection at same time the lines executing the screen print are running?

/*************************
**  Declare Libraries   **
*************************/
#include <UTFT.h>
#include <UTouch.h>
UTFT myGLCD(ILI9341_4L, 3, 2, 9, 10, 7);      // LCD: 4Line  serial interface. Initialize display
UTouch  myTouch( 2, 6, 3, 4, 5);              // RTP: byte tclk, byte tcs, byte din, byte dout, byte irq


/*************************
**  Declare Variables   **
*************************/
extern uint8_t BigFont[];                     // Declare which fonts we will be using
extern uint8_t Grotesk32x64[];
extern uint8_t Grotesk16x32[];
int dist;                                     // Actual distance measurements of LiDAR
int check;                                    // Save check value
int i;
int uart[9];                                  // Save data measured by LiDAR
const int HEADER = 0x59;                      // Frame header of data package from LiDAR
int numToAvg = 50;                           // The number of loops between each print
int incr = 0;                                 // Count the number of loops
int erase = 0;                                // Save the previous data measured by LiDAR to overwrite the old print
int x;
int y;
int conv;

/*************************
** Initialization Tasks **
*************************/
void drawButtons()                                   // Draw the buttons
{

  myGLCD.setFont(BigFont);

  myGLCD.setColor(0, 0, 255);
  myGLCD.fillRoundRect (40, 180, 280, 230);
  myGLCD.setColor(255, 255, 255);                    // Set the stroke color to white
  myGLCD.drawRoundRect (40, 180, 280, 230);
  //myGLCD.setColor(255, 255, 255);
  myGLCD.print("0 ALL VALUES", 60, 197);             // 0s out the incr, erase, and dist int when there is a hang up

  myGLCD.setBackColor(0, 0, 0);
}
// Draw a red frame while a button is touched
void waitForIt(int x1, int y1, int x2, int y2)
{
  myGLCD.setColor(255, 0, 0);
  myGLCD.drawRoundRect (x1, y1, x2, y2);
  while (myTouch.dataAvailable())
    myTouch.read();
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (x1, y1, x2, y2);
}

/*************************
**     Loop Setup       **
*************************/
void setup() {
  Serial.begin(9600);                                // Set bit rate of serial port connecting Arduino with computer
  Serial1.begin(115200);                             // Set bit rate of serial port connecting LiDAR with Arduino. 19(RX), 18(TX)



  // Bring screen online
  myGLCD.InitLCD();
  myGLCD.clrScr();

  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);

  myGLCD.setBackColor(0, 0, 255);
  drawButtons();
}


/*************************
**   Main Program Loop  **
*************************/
void loop()
{

  // Read the value from the sensor
  if (Serial1.available()) {                         // Check if serial port has data input
    if (Serial1.read() == HEADER) {                  // Assess data package frame header 0x59
      uart[0] = HEADER;
      if (Serial1.read() == HEADER) {                // Assess data package frame header 0x59
        uart[1] = HEADER;
        for (i = 2; i < 9; i++) {                    // Save data in array
          uart[i] = Serial1.read();
        }
        check = uart[0] + uart[1] + uart[2] + uart[3] + uart[4] + uart[5] + uart[6] + uart[7];
        if (uart[8] == (check & 0xff)) {             // Verify the received data as per protocol
          dist = uart[2] + uart[3] * 256;            // Calculate distance value
        }
      }
    }
  else
  {
    
  }
  }

  Serial.print("     "); Serial.print(dist);         // Sanity check on serial mon.
  if (myTouch.dataAvailable())
    {
      myTouch.read();
      x=myTouch.getX();
      y=myTouch.getY(); 
      if ((x>=40) && (x<=280))                       // Center Column
      {
        if ((y>=180) && (y<=230))                    // Button: 1sec Average
        {
          waitForIt(40, 180, 280, 230);
          conv = 0;
          dist = 0;
          incr = 0;
          erase = 0;
        }
      }
    }
 
  incr++;
  if (incr == numToAvg)                              // Should allow the below statement to execute every half second when numToAvg = 100
  {
    if (dist < 30 || dist > 17999 )                  // Defines acceptable data range
    {
      myGLCD.setColor(255, 0, 0);
      myGLCD.setFont(Grotesk32x64);
      myGLCD.print("     ", CENTER, 20);
     
      myGLCD.print("BAD", CENTER, 20);
      delay(20);
      myGLCD.setColor(0, 0, 0);
      myGLCD.print("BAD", CENTER, 20);
    }

    else
    {
      conv = dist/ 30.48;                            // Converts distance in CM measured by LIDAR to feet
      if (conv != erase)                             // Only print the distance if it is different from the last
      {
      myGLCD.setFont(Grotesk32x64);
      
      myGLCD.setColor(0, 0, 0);
      myGLCD.printNumI(erase , CENTER, 20);          // Prints old value in black to 'erase' it from screen before printing the new
     
      myGLCD.setColor(255, 255, 255);                                                           
      myGLCD.printNumI(conv , CENTER, 20); myGLCD.print("FT", RIGHT, 20);
      
      erase = conv;                                  // Stores the newest value for the next execution of the printout
      }
    }
    incr = 0;
  }
    delay(10);                                        // Loops 100 times per second. LIDAR measureing frequency is set at 100HZ
  }

EDIT: I think maybe this is what Im looking for? Arduino Playground - AvoidDelay

maybe implement a millis() timer on each task? Where in the if statements would I put each timer though?

I'm not sure delays are the problem here. You only have one in the loop and it is 10ms. I suspect the real problem is your approach to the exercise. I say that without having any idea of what everybody else is doing but I'm pretty sure that nobody ever does this,  myGLCD.printNumI(erase , CENTER, 20);          // Prints old value in black to 'erase' even if they are not in a hurry, and it might be indicative of what is really going on. I rather think it is time to learn to walk instead of run, and go through some of the examples included in the library, in order to familiarise yourself with the display. If you leave the LCD out of the game and just check the serial monitor, you might find where the real villain lies. You might find this is all down to a bad choice of display and an even worse choice of font.