Touchscreen Display menu system

Status
Not open for further replies.

japreja

Active member
Hello all, I am in the process of converting my Arduino project to Teensy 4.1. I had actually had to halt the Arduino version because I quickly ran out of program memory for what I wanted to do. I found an ordered the Teensy 4.1 and have plenty of room to work with.

Everything, so far, works, the reason I am posting before going further is because I am fairly new to C, maybe about 2 years tinkering with an Uno. I think there may be an easier way to get things organized or some tricks that only a well experienced c programmer can know. I would like to store, and retrieve, some variables/setting in flash but couldn't in the Arduino version because of some bug/restriction in progmem preventing the possibility of doing that. Is this also prevented in Teensy 4.1? I would prefer that as opposed to SD storage.

I intend on altering the code to use more descriptive names than Page1, Page2, etc...

The font is written to screen using rows/columns based on font size, I think this could be more dynamic/universal and maybe added to a driver/library if it is not already done.

I appreciate all criticism! Here is my Code (2 files)

Code:
/*
  ILI9341 W/Touch
  By: japreja (Jorge Joaquin Pareja)


  Version 1.0 - Basic screen and Option screen layout and setup


  Parts Used:


    * Teensy 4.1        - [URL]https://www.pjrc.com/store/teensy41.html[/URL]
    * ILI9341 Display   - [URL]https://www.amazon.com/gp/product/B087C3PP9G/[/URL]


  Wiring is exactly as depicted on [URL]https://www.pjrc.com/store/display_ili9341_touch.html[/URL]


  With this display and the smallest font, 6x8, we can get a total of 30 lines and 53 columns
  of text with 1 pixel in between each letter. 6x53=318 and 2 pixels left over, 8x30=240 and
  no pixels left over, provided that the width is the widest measurement of the display.


  By defining:
  
    screenWidth=320
    screenHeight=240
    fntWidth=6
    fntHeight=8


  we can use some simple division to determine the line and column to start writing on so
  our letters dont overlap.
*/
//#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Wire.h>
#include <ILI9341_t3.h>
#include <XPT2046_Touchscreen.h>


#include "namedColors.h"


// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 350
#define TS_MINY 300
#define TS_MAXX 3900
#define TS_MAXY 3800


// Device chip select pins
#define XPT_CS 8
#define TFT_CS 10


XPT2046_Touchscreen ts(XPT_CS);


// TFT Data/Command pin
#define TFT_DC 9
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);


/// JJP Code follows, different display sizes will require modifications of this code, also
/// if you change the orientation.
const int screenWidth     = 320;
const int screenHeight    = 240;


//Font properties
const int fntWidth       = 6;
const int fntHeight      = 8;


// Screen Properties (Dynamicly created with values above)
const int screenMaxCharsPerLine = screenWidth/fntWidth;
const int screenMaxLines = screenHeight/fntHeight;


// padding in pixels, incase font is slightly off screen
const int cpadding = 0; //Column Padding
const int rpadding = 0; // Row/Line Padding


// 53 Columns (0 to 52) and 30 Rows (0 to 29) on a 320x240 display.  I use this for calculating the
// columns for text placement using setCursor, default font 6x8!
int tftCol[screenMaxCharsPerLine];
int tftRow[screenMaxLines];


void cls(int color, int rotation, int tsRotation); // Set some defaults


////////////////////////////////////
// Menu Settings and Variables
//
byte mIndex = 5;  // Menu/Page index
byte pIndex = 5;  // previous page index
byte cIndex = 5;  // current page index, 5 is currently default for main menu/screen
String sversion = "V1.0";
String sYes = "Yes";
String sNo = "No";


void setup(void){
  tft.begin();
  ts.begin();


  // setup easy access for text positions
  for (byte i = 0; i < screenMaxCharsPerLine; i++){
    tftCol[i] = (cpadding+(i*fntWidth));
  }
  for (byte i = 0; i < screenMaxLines; i++){
    tftRow[i] = (rpadding+(i*fntHeight));
  }


  tft.fillScreen(c_black);


  // set the text color, and the background color so that new text will cover over any old text
  // without having to blank the entire screen
  tft.setTextColor(c_white, c_black); // white text on black background, prevents having to redraw the entire screen, just overwrite a location with spaces
  tft.setTextWrap(false); // disable wrapping of text


  cls(c_black, 3, 1); // cls(color, screen orientation, touchscreen orientation)
}


void loop(){
  layoutScreen();
}


/* CUSTOM FUNCTIONS BELOW
 * From my previous code for a 128x128 screen
 * 
 */
void checkTouch(){
  if(ts.bufferEmpty()){
    return;
  }


  // just testing, menu is not yet selectable
  TS_Point p = ts.getPoint();


  p.x = map(p.x, TS_MINX, TS_MAXX, 0, screenWidth);
  p.y = map(p.y, TS_MINY, TS_MAXY, 0, screenHeight);


  String sx = "X = " + String(p.x) + "     ";
  String sy = "Y = " + String(p.y) + "     ";
  pl(sx, 14, 10);
  pl(sy, 15, 10);
}


void layoutScreen(){
  
  drawMenu(mIndex);


  switch(mIndex){
    case 1:
      Page1();
      break;
    case 2:
      Page2();
      break;
    case 3:
      Page3();
      break;
    case 4:
      Page4();
      break;
    case 5:
      Page5();
      break;
    default:
      Page5();
      break;
  }
}


void Page1(){ 
  tft.setTextColor(c_black, c_yellow);
  pl("Page 1", 2, 0);
  tft.setTextColor(c_white, c_black);
}


void Page2(){
  tft.setTextColor(c_black, c_yellow);
  pl("Page 2", 2, 0);
  tft.setTextColor(c_white, c_black);
}


void Page3(){
  tft.setTextColor(c_black, c_yellow);
  pl("Page 3", 2, 0);
  tft.setTextColor(c_white, c_black);
}


void Page4(){
  tft.setTextColor(c_black, c_yellow);
  pl("Page 4", 2, 0);
  tft.setTextColor(c_white, c_black);
}


void Page5(){ // Main Screen Page
  tft.setTextColor(c_black, c_yellow);
  pl("Page 5 - Startup Screen", 2, 0);
  tft.setTextColor(c_white, c_black);


  checkTouch();
}


void drawMenu(byte index){
  String page0 = " P1 ";
  String page1 = " P2 ";
  String page2 = " P3 ";
  String page3 = " P4 ";


  cIndex = index;


  tft.setTextColor(c_white, c_blue);
  if(pIndex != cIndex)
  {
    cls(c_black, 3, 1);
    pIndex = cIndex;
  }


  if(index == 1)
  {
    tft.setTextColor(c_black, c_red);
    pl(page0, 0, 1);
    tft.setTextColor(c_white, c_blue);
    pl(page1, 0, 6);
    pl(page2, 0, 11);
    pl(page3, 0, 16);
  }
  else if(index == 2)
  {
    pl(page0, 0, 1);
    tft.setTextColor(c_black, c_red);
    pl(page1, 0, 6);
    tft.setTextColor(c_white, c_blue);
    pl(page2, 0, 11);
    pl(page3, 0, 16);
  }
  else if(index == 3)
  {
    pl(page0, 0, 1);
    pl(page1, 0, 6);
    tft.setTextColor(c_black, c_red);
    pl(page2, 0, 11);
    tft.setTextColor(c_white, c_blue);
    pl(page3, 0, 16);
  }
  else if(index == 4)
  {
    // Page 4
    pl(page0, 0, 1);
    pl(page1, 0, 6);
    pl(page2, 0, 11);
    tft.setTextColor(c_black, c_red);
    pl(page3, 0, 16);
  }
  else if(index == 5)
  {
    // menu item not selected
    pl(page0, 0, 1);
    pl(page1, 0, 6);
    pl(page2, 0, 11);
    pl(page3, 0, 16);
  }


  tft.setTextColor(c_white, c_black);
}


void uprint(String txt, int fg_color, int bg_color, int lineNumber, int columnNumber){
  tft.setTextColor(fg_color, bg_color);
  pl(txt, lineNumber, columnNumber);
}


// Print a string based on line and column number calculated in the arrays
void pl(String txt, int lineNumber, int columnNumber){
  tft.setCursor(tftCol[columnNumber], tftRow[lineNumber]);
  tft.print(txt);
}


// Clear the screen with screen rotation
void cls(int color = c_black, int rotation = 3, int tsRotation = 1){
  tft.setRotation(rotation);
  ts.setRotation(tsRotation);
  tft.fillScreen(color);
}

The second file is just for colors I didn't realize were already in the library

Code:
#define c_black   0x0000
#define c_white   0xFFFF
#define c_red     0xF800
#define c_green   0x07E0
#define c_blue    0x001F
#define c_cyan    0x07FF
#define c_magenta 0xF81F
#define c_yellow  0xFFE0
#define c_orange  0xFC00




/*
// from https://cgit.freedesktop.org/xorg/app/rgb/tree/rgb.txt
// converted with http://www.rinkydinkelectronics.com/calc_rgb565.php
*/
#define c_AliceBlue 0xF0F8FF
#define c_Snow      0xFFFAFA

Any guidance would be appreciated.
Thank you in advance,
Jorge
 
Hi Jorge,
This will probably work for a while, but you can already see the signs of this becoming a very long file? Long files are hard to read. I would split out things to classes according to their function? If you do not know how to build a C++ class, just look in your libraries folder and learn from that?

You loop() is calling layoutScreen() that is calling PageX() that is drawing the same text on top of the same text even if it's not changed. There are so many ways you could make this code more readable and faster - but the first would be to never draw something that has not changed. Have a look at this class. It holds the position, color, size and text of a textfield for a screen. In this class, the textfield will only draw if a change to position, size, color or text has happened. The only thing you need to do is to call the draw() method on every loop and if anything has changed, the textfield will redraw itself. It will draw a rectangle over the old text (using the background color) and then write the updated text on top of this. This is the fastest possible way on most screens and it produces no noticeable flicker.

This can be done for any object. It would be logical to make a Screen-object that has multiple textfields. The screen has a draw() method that calls all the draw() method of its textfields. You can also make multiple screens and based on the Interrupt function of the touch-chip, you can make it so that the screen only redraws the millisecond you touch the screen. Using tricks like this will enable rich layouts on even slower microcontrollers than Teensy :)

I hope it was that kind of guidance you were looking for?
 
Thank you for the response, and the example. I am working to get things put into separate header files. I've been taking some time to read up on how to create a library as well as watching the plentiful YouTube videos on library creation .

I was under the impression that if my screen page did not change, by mIndex, then the screen was not updating/redrawing. I'll look into that a bit more.
 
Status
Not open for further replies.
Back
Top