There is wide range of TFT displays available for ATmega processors. Displays distinguish them selves by resolution, dimensions and serie or parallel interfaces.

For an ATmega328 processors an 8bit parallel display consumes all IO pins except the Series TTL interface and one Analog IO. The good thing is that with this processor its possible to build a relative simple low volume general purpose TFT display.
Many controller interfaces require a combination of digital and Analog IOs interfacing to various sensors and a reasonable sized display to display results and status of the sensors. By having a display with a Txt Rx communication interface space is saved on the IOS needed to control external sensors.
The display on the right is a 3.5 Inch 320 x 480 resolution ILI9488 display controlled by a ATmega328 processor. The code exist out the following functions
- The screen layout software
- A Command Line Interpreter (CLI)
- A real time clock.
The CLI is responsible for reading values from the TTL Rx Tx interface and displaying them on the TFT screen. The screen is grouped in Battery, Grid/Net and Photovotaic related values. It can read all parameters defined on the TFT screen like:
- Battery : voltage current, SoC, battery cycle count, battery health values
- Grid/Net : voltage current, power energy values and power factor
- Photovotaic : voltage current, power Energy, panel temperature values
- Time and date values.
The TFT libary used to implement the program consumes a reasonable percentage of all program memory on a ATmega 328 but after finalizing the code sufficient program and RAM space is left over for some extra functions. The code uses 27.7K program space and around 1.1K RAM code.
For the ones interested below the basic code for the CLI copy it in your sketch and have fun.
#define CR 0x0D // \r #define LF 0x0A // \n #define SPACE 0x20 // " " #define OPT 0x25 // % typedef struct cmds { String str; void (*pt2function)(char); } commands; commands cmd[] = {{"",},{"settm",settm}, {"batt",batt}, {"net",net}, {"pv",pv} }; void readstream(byte state){ uint8_t n=1; if (Serial.available()!=0){ while (Serial.peek()==LF || Serial.peek()==CR || Serial.peek()==SPACE) Serial.read(); // Read all Cr, Lf,spaces out of the stream until first characters cmd[0].str=Serial.readStringUntil(SPACE); // Read Command string until first space while( cmd[0].str!=cmd[n].str && n<=sizeof(cmd)/sizeof(cmd[0])) n++; // Find Command in the cmd array list. if (n>sizeof(cmd)/sizeof(cmd[0])) return; // If command not found, terminate the cammand processing while ((Serial.available()!=0 && (Serial.peek()!=LF || Serial.peek()!=CR ))) { // Check stream has no Cr/Lf characters if (Serial.read()==OPT) cmd[n].pt2function(Serial.read()); // If stream is Option sign Call function pointed by cmd[0] and read option parameter else Serial.read(); // IF not option characters read stream } } } void settm(char par){ int8_t n; switch (par){ case 'T' :{ for (n=2; n>=0; n--) *(&RTC.time.sec+n)=Serial.parseInt(); } // read three times data from the stream to the time struct sec, min, hr. break; case 'D' :{ for (n=0; n<=2; n++) *(&RTC.time.mday+n)=Serial.parseInt()%100; } // read three times data from the stream to the time struct date, month, year (years needs MOD 100 break; case 'C' :{ RTC.derror=RTC.derror+Serial.parseFloat()/24; } break; } }Examples of commands are : Set the time : settm %T 06:05:10 %D 11/12/1962
Other commands are but not seen in this code : batt %V 12.56 %I 23.25 %E 2534.1
net and PV