<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Open Smart serial TFT LCD touch screen - example Arduino code]]></title><description><![CDATA[<p dir="auto">I bought a $10 touchscreen for Arduino, which can be controlled via serial commands.</p>
<p dir="auto">Specifically the "<a href="https://www.aliexpress.com/item/2-4-inch-UART-Serial-TFT-LCD-module-Touch-Screen-Expansion-Shield-with-TF-card-socket/32877887683.html" rel="nofollow ugc">2.4 inch UART Serial TFT LCD module Touch Screen Expansion Shield with TF card socket Touch Pen for Arduino UNO R3 Mega2560 Nano</a>" from Aliexpress. Once you power it up it identifies itself as an "Open Smart TFT LCD".<br />
Driver IC is: 9325<br />
Firmware version is v10<br />
Chip: ILI9325</p>
<p dir="auto">Specs:</p>
<ul>
<li>320x240 (can be rotated in all directions)</li>
<li>2.4 inch</li>
<li>Touch screen</li>
<li>Controlled via serial (USART/UART)</li>
<li>Adaptable brightness</li>
<li>An Arduino 328p actually controls it internally (<a href="https://forum.mysensors.org/topic/10105/touch-screen-with-built-in-arduino-328p">very hackable?</a>)</li>
</ul>
<p dir="auto">Since there weren't any libraries for it I developed a little bit of code to make working with it easier (see below).</p>
<p dir="auto">The device has some good points:</p>
<ul>
<li>Surprisingly responsive to touch for a resistive touch model. It comes with a small stylus, but you don't need it. Very light finger pressure is already registered well.</li>
<li>Very memory efficient, since you just need to send serial commands.</li>
<li>Cheap</li>
<li>Has Dupont pins already soldered on.</li>
<li>Has a space for an SD card, can show bitmap images (but I haven't tried that).</li>
</ul>
<p dir="auto">The downsides:</p>
<ul>
<li>Slow! As far as I can tell you can only send one command at a time, and have to wait for the 'ok' response before you can send the next one. Moving the text cursor takes 8 milliseconds. Filling the screen with a color takes 50 milliseconds. Most commands are in between those extremes. In practise, this means that creating a complex menu takes about a second, and you see all the things pop into view one by one. Setting it use a higher baud-rate made no difference.</li>
<li>Has a few small menu icons built into one edge of the screen. They cannot be removed. They detract, and could confuse users.</li>
<li>Some devices I've tried have more polished commands. This screen requires HEX codes. Others allow you to print text, and are more flexible. For example:</li>
<li>You can send it characters, but only in batches of 5. If you want to display a single character, this means you have to display the character and 4 space commands.</li>
</ul>
<p dir="auto">All in all though, I'm very happy with it. Users expect touch interfaces, and the cost is not much higher than other input hardware.</p>
<p dir="auto">CODE</p>
<pre><code>/*
 * This is a small bit of messy demo code for the Open Smart serial touchscreen.
 * 
 * This code is provided 'as-is', and may be considered public domain.
 * 
*/


#define MAX_BASIC_COMMAND_LENGTH 20 // How many bytes are in the longest basic command?
#define TOUCHSCREEN_WIDTH 240
#define TOUCHSCREEN_HEIGHT 320

const byte numChars = 8;
byte receivedChars[numChars];       // An array to store the received serial data

boolean touched = false;            // Was the touchscreen just touched?

#include &lt;SoftwareSerial.h&gt;
SoftwareSerial mySerial(4,5);       // RX, TX

signed int touchX = 0;              // Touch screen position X
signed int touchY = 0;              // Touch screen position Y

// All commands for the TFT should start with 0x7E, but to save storage space this is taken care of in the basicCommand function.
PROGMEM const byte resetTFT[] =         {0x02, 0x05, 0xEF,}; // Resets the TFT. But has no real effect.
PROGMEM const byte testTFT[] =          {0x02, 0x00, 0xEF,}; // Test the TFT, should respond with "OK".
PROGMEM const byte hello[] =            {0x07, 0x11, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0xEF,}; // Places the word 'hello' on the screen.
PROGMEM const byte set_vertical[] =     {0x03, 0x04, 0x02, 0xEF,}; // To set rotation of the screen to vertical. Try 0x01 or 0x03 instead of the 0x02.
PROGMEM const byte rectangle[] =        {0x0E, 0x2C, 0x00, 0x10,0x00, 0x10,0x00, 0x50,0x00, 0x50,0x00, 0x10, 0x00, 0xFF, 0xEF,}; // Test rectangle.
PROGMEM const byte backlight[] =        {0x03, 0x06}; // Backlight intensity
PROGMEM const byte fill_screen[] =      {0x04, 0x20, 0x00, 0x00, 0xEF,}; // Fill screen with one color
PROGMEM const byte fill_screen2[] =     {0x04, 0x20, 0x00, 0x8F, 0xEF,}; // Fill screen with one color

PROGMEM const byte setCurs[] =          {0x06, 0x01, 0x00, 0x10, 0x00, 0x10, 0xEF,}; // Sets text cursor position to a fixed position (16 pixels from the left, 16 pixels from the top).
PROGMEM const byte serialSpeedUp[] =    {0x03, 0x40, 0x03, 0xEF,}; // Sets communication speed to 57600 (from 9600)
PROGMEM const byte serialSlowDown[] =   {0x03, 0x40, 0x00, 0xEF,}; // Sets communication speed to 9600 again. Oddly enough, it seems it works fastest at this speed..

PROGMEM const byte text_color_black[] = {0x04, 0x02, 0x00, 0x00, 0xEF,}; // Dark text color. fill screen with one color
PROGMEM const byte text_color_red[] =   {0x04, 0x02, 0xF8, 0x00, 0xEF,}; // .. text color. fill screen with one color
PROGMEM const byte text_color_white[] = {0x04, 0x02, 0xFF, 0xFF, 0xEF,}; // white text color. fill screen with one color

/* 
The colors use this RGB565 format:
http://www.barth-dev.de/online/rgb565-color-picker/

white: FF FF = 65535;
red: F8 00
purple: F0 1F
blue: 00 1F
light blue: 07 FF
bright green: 07 E0
yellow: FF 20
orange: FC 80
*/



// The MessageDef code below comes from https://arduino.stackexchange.com/questions/49236/printing-char-array-from-array-of-structs-in-progmem-to-serial

typedef byte MessageID;
enum {
  OPTION0,
  OPTION1,
  OPTION2,
  OPTION3,
  OPTION4,
  OPTION5
};

struct MessageDef {
  MessageID ID;
  char Description[20];
};

const MessageDef MessageTable[] PROGMEM = {
  {OPTION1,"abcde"},
  {OPTION2,"abcdef"},
  {OPTION3,"abcdefg"},
  {OPTION4,"abcdefgh"},
  {OPTION5," ABC def ghi!"}  
};

const byte MessageTableSize = sizeof(MessageTable)/sizeof(MessageDef);



void setup() {
  Serial.begin(115200);                     // Start serial output of data.
  Serial.println(F("Hello world"));
  delay(1000);
  
  // Speeding up the communication has no effect on how quickly the screen responds to commands.
  
  //mySerial.begin(57600);
  //basicCommand(serialSlowDown);           // slow down the display..
  mySerial.begin(9600);

  //mySerial.begin(9600);
  //basicCommand(serialSpeedUp);            // speed up the display..
  //mySerial.begin(57600);                  // and then speed up the connection.

  
  //basicCommand(resetTFT);
  //delay(2000);

  
  Serial.println();Serial.println(F("__set rotation"));
  basicCommand(set_vertical);
  
  Serial.println();Serial.println(F("__fill"));
  basicCommand(fill_screen);

  Serial.println();Serial.println(F("__rectangle"));
  basicCommand(rectangle);

  setCur(100,100);
  delay(100);

  Serial.println();Serial.println(F("__color"));

  basicCommand(text_color_white);

  Serial.println();Serial.println(F("__color"));
  basicCommand(hello);
  displayNumber(1);
  delay(100);

}

void loop() {
  readResponse();
  if(touched){
    touched = false;
    drawPix(touchX,touchY, 65535); // Draw a pixel 
    //setCur(touchX,touchY);
    //basicCommand(hello);
    if( touched == false &amp;&amp; touchY &lt; 100 ){
      showMainMenu();
    }
  }
}


void showMainMenu()
{
  Serial.print(F("mainMenuSize")); Serial.println(MessageTableSize);
  basicCommand(fill_screen2);

  for(byte i = 0; i &lt; MessageTableSize; i++ ){
    Serial.print(F("&gt;")); Serial.println(i);
    setCur(10,50 + i * 45);
    displayNumber(i);
    writeText(i);
  }
}

// This function writes text to the screen. You can use the setCur function to place the cursor in the desired position first.
void writeText(byte textID)
{
  Serial.println(F("WRITETEXT"));

  byte j = 0;
  byte c = 0;
  byte stringLength = strlen_P(MessageTable[textID].Description);
  Serial.print(F("- stringLength: ")); Serial.println(stringLength);
  
  while ( j &lt; stringLength ){
    byte command[9] = {0x7E, 0x07, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0xEF,}; // It took quite some testing to get this right. Just using 0x00 for the entire payload will not work.
    
    for( byte i=0; i &lt; 5; i++ ){
      if(j+i &lt; stringLength){
        command[3+i] = pgm_read_byte(MessageTable[textID].Description + j + i);
        //Serial.print(command[3+i]); Serial.print(F(" "));
      }
    }
    Serial.println();
    for( int i=0; i &lt; sizeof(command); i++ ){
      mySerial.write( command[i] );
      Serial.print(command[i],HEX); Serial.print(F(" "));
    }
    waitForResponse(5);
    j = j + 5;
  }
  
  Serial.println();
}

void drawPix(int x, int y, int c) // Draw a pixel on the screen.
{
  Serial.println(F("DRAWPIX:"));
  Serial.print(F("x: ")); Serial.println(x);
  Serial.print(F("y: ")); Serial.println(y);
  Serial.print(F("c: ")); Serial.println(c);
  byte command[10] = {0x7E, 0x08, 0x21, highByte(x), lowByte(x), highByte(y), lowByte(y), highByte(c), lowByte(c), 0xEF,};
  for( int i=0; i &lt; sizeof(command); i++ ){
    mySerial.write( command[i] );
    //Serial.print(command[i],HEX); Serial.print(F(" "));
  }
  waitForResponse(5);
}


// This function places the text cursor anywhere on the screen.
void setCur(int x, int y)
{
  Serial.println(F("SETCUR:"));
  Serial.print(F("x: ")); Serial.println(x);
  Serial.print(F("y: ")); Serial.println(y);
  byte command[8] = {0x7E, 0x06, 0x01, highByte(x), lowByte(x), highByte(y), lowByte(y), 0xEF,};
  for( int i=0; i &lt; sizeof(command); i++ ){
    mySerial.write( command[i] );
    //Serial.print(command[i],HEX); Serial.print(F(" "));
  }
  waitForResponse(5);
}

// This function outputs a variable number to the screen. It can show negative and positive numbers. It cannot show floats.
void displayNumber(signed int number)
{
  Serial.print(F("DISPLAYNUMBER (")); Serial.println(number); 
  byte command[8] = {0x7E, 0x06, 0x13, 0x01, 0x0A, highByte(number), lowByte(number), 0xEF,};
  for( int i=0; i &lt; sizeof(command); i++ ){
    mySerial.write( command[i] );
    Serial.print(command[i],HEX); Serial.print(F(" "));
  }
  waitForResponse(5);
}


// This function reads the serial data (if available) from the screen. The implemented commands it can detect are 'ok', and the touch coordinates.
void readResponse()
{
  if( mySerial.available() &lt; 5 ){ // Any response should be at least 5 bytes.
    return;
  }
  boolean savingMessage = false;
  byte receivedCharsPosition = 0;
  byte startMarker = 0x7E; // Any response from the screen will start with this.
  byte endMarker = 0xEF; // Ane response from the screen will end with this.
  byte rc; // Hold the byte form the serial stream that we're examining.
  while( mySerial.available() ){ //  &amp;&amp; newData == false //  By not checking for this the entire buffer is always cleared.
    rc = mySerial.read();
    Serial.print(rc); Serial.print(F(" "));
        
    if( savingMessage == true ){ // We are now in the part of the response that is the message we were looking for.
      if(rc != endMarker){
        receivedChars[receivedCharsPosition] = rc;
        receivedCharsPosition++;
        if( receivedCharsPosition &gt;= numChars ){
          receivedCharsPosition = numChars - 1;
        }
      }
      else { // We've arrived at the end marker.
        receivedChars[receivedCharsPosition] = '\0'; // Terminate the string.
        savingMessage = false;
        receivedCharsPosition = 0;
        //Serial.println(F("(endmarker)"));
        if(receivedChars[receivedCharsPosition] == 0x06 &amp;&amp; receivedChars[receivedCharsPosition + 1] == 0x07){
          touchX = touchToX( (receivedChars[receivedCharsPosition + 2] * 256) + receivedChars[receivedCharsPosition + 3] );
          touchY = touchToY( (receivedChars[receivedCharsPosition + 4] * 256) + receivedChars[receivedCharsPosition + 5] );
          Serial.print(F("touchX=")); Serial.println(touchX);
          Serial.print(F("touchY=")); Serial.println(touchY);
          touched = true; // To indicate that a touch event has just occured.
        }
        // OK message
        else if( receivedChars[receivedCharsPosition] == 0x03 &amp;&amp; receivedChars[receivedCharsPosition + 1] == 0x6F &amp;&amp; receivedChars[receivedCharsPosition + 2] == 0x6B ){
          Serial.println(F("-OK"));
        }
        else{
          Serial.println(F("-X-"));
          receivedCharsPosition++;
          if( receivedCharsPosition == numChars ){ return; }
        }
      }
    }
    if(rc == startMarker){ // Once a valid startMarker is found, we start saving the message into the array.
      savingMessage = true;
      //Serial.print(F("(startMarker) "));
    } 
  }
}

// This function can send basic string command that don't have any variable parts in them.
void basicCommand(const char* cmd)
{
  Serial.println(F("BASIC COMMAND"));
  if( mySerial.available()){  Serial.print(F("cleaning:")); } // If necessary, clear old messages from the serial buffer.
  while( mySerial.available() ){
    char x = mySerial.read();
    Serial.print(x);
  }
  Serial.println();

  mySerial.write(0x7E); // Starting byte, is always the same.
  Serial.print(0x7E); Serial.print(F(" "));
  byte b = 0;
  while( b &lt; MAX_BASIC_COMMAND_LENGTH ){ // How many bytes are the basic commands at most?
    mySerial.write( pgm_read_byte(&amp;cmd[b]) );
    Serial.print( pgm_read_byte(&amp;cmd[b]),HEX ); Serial.print(F(" "));
    if( pgm_read_byte(&amp;cmd[b]) == 0xEF ){ // This breaks out of the loop.
      waitForResponse(b);
      b = MAX_BASIC_COMMAND_LENGTH; 
    } 
    b++;
  }
  
}


// This function can be activated after sending a command. It will wait until a response has arrived (or 100 milliseconds have passed), and then allow the Arduino to continue.
void waitForResponse(byte expectedBytes)
{
  Serial.println(); Serial.println(F("WAITING FOR RESPONSE"));
  byte b = 0;
  while( mySerial.available() &lt; expectedBytes &amp;&amp; b &lt; 100){
    b++;
    delay(1);
  }
  Serial.print(F("wait time: ")); Serial.println(b);
  delay(10); // A small extra delay seems to be required.
  readResponse();
  Serial.println();
}


int touchToX(int x)
{
  return int constrain(((x - 80) / 3.7), 0, TOUCHSCREEN_WIDTH);
}
int touchToY(int y)
{
  return int constrain(((y - 80) / 2.7), 0, TOUCHSCREEN_HEIGHT);
}

</code></pre>
<p dir="auto">As a side note, I also tried the Nextion devices, but I wasn't able to figure out how to remove all the startup logos and animations it comes with. I also wasn't able to remove a text scrolling widget that was apparently built in. No matter what I did, it stayed put, scrolling Chinese characters.</p>
]]></description><link>https://forum.mysensors.org/topic/10157/open-smart-serial-tft-lcd-touch-screen-example-arduino-code</link><generator>RSS for Node</generator><lastBuildDate>Thu, 13 Aug 2026 00:41:29 GMT</lastBuildDate><atom:link href="https://forum.mysensors.org/topic/10157.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 06 Feb 2019 15:41:03 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Open Smart serial TFT LCD touch screen - example Arduino code on Thu, 18 Jul 2019 08:55:36 GMT]]></title><description><![CDATA[<p dir="auto">A small note on my experiences so far.</p>
<p dir="auto">I have settled on using this screen for most cases where I wanted to use a bigger screen for output. Creating small UX-es is awesome.</p>
<p dir="auto">What is also great is that I turn the backlight off after a little while, and then a touch turns it back on again. Similarly, using a touch to turn the screen on and off is nice for when you don't want the screen to shine it's light into the room all the time.</p>
<p dir="auto">I have also gotten it to work slightly faster by creating a better way of handling the serial data it sends.</p>
<p dir="auto">I've also learned that you can send longer strings to it all at once. You need to send the length of the string in the command. I haven't implemented this in my own code yet, but I recently learned about it by better reading the documentation.</p>
<p dir="auto">Something more worrying is that two of the six screens have stopped working. The screens turn on, but there is no serial communication. I believe this is caused by how I handled the screens, and creating small shorts on the back of the screen. My recommendation is to add some non-conductive tape to the entire back to avoid this. Make sure your other electronics don't accidentally touch its back.</p>
<p dir="auto">The resistive touch screen works well, but if there was a capacitive version of the screen I would probably switch to that.</p>
<p dir="auto">Finally, the screen can be separated from the PCB below. It's just attached with double sided tape.</p>
]]></description><link>https://forum.mysensors.org/post/100474</link><guid isPermaLink="true">https://forum.mysensors.org/post/100474</guid><dc:creator><![CDATA[alowhum]]></dc:creator><pubDate>Thu, 18 Jul 2019 08:55:36 GMT</pubDate></item><item><title><![CDATA[Reply to Open Smart serial TFT LCD touch screen - example Arduino code on Wed, 20 Feb 2019 10:27:01 GMT]]></title><description><![CDATA[<p dir="auto">I found some more data on it:</p>
<p dir="auto"><a href="https://www.hackster.io/frankiemaker/simple-easy-to-use-serial-tft-lcd-5196cf" rel="nofollow ugc">https://www.hackster.io/frankiemaker/simple-easy-to-use-serial-tft-lcd-5196cf</a></p>
<p dir="auto">There's a youtube video about it:<br />
<a href="https://youtu.be/xf-cUhoJtLw" rel="nofollow ugc">https://youtu.be/xf-cUhoJtLw</a></p>
<p dir="auto">That page even links to a library!<br />
<a href="https://halckemy.s3.amazonaws.com/uploads/attachments/493182/Arduino_library_for_OPEN-SMART_Serial_TFT.rar" rel="nofollow ugc">https://halckemy.s3.amazonaws.com/uploads/attachments/493182/Arduino_library_for_OPEN-SMART_Serial_TFT.rar</a></p>
<p dir="auto">The video also shows their screen responding much faster. Very interesting.</p>
]]></description><link>https://forum.mysensors.org/post/97485</link><guid isPermaLink="true">https://forum.mysensors.org/post/97485</guid><dc:creator><![CDATA[alowhum]]></dc:creator><pubDate>Wed, 20 Feb 2019 10:27:01 GMT</pubDate></item><item><title><![CDATA[Reply to Open Smart serial TFT LCD touch screen - example Arduino code on Mon, 11 Feb 2019 10:31:59 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/scalz" aria-label="Profile: scalz">@<bdi>scalz</bdi></a> Thanks for the tip and thinking along, I appreciate it. The things is I actually don't use the GUI creation tool.</p>
<ul>
<li>It only works in windows.</li>
<li>Micro SD cards costs yet more money, so I don't use those either.</li>
<li>I try to keep my code resolution independent/flexible. Bitmaps are not.</li>
</ul>
<p dir="auto">That's why I went looking for screens where I can draw shapes and text by sending simple commands to it. It also forces me to keep the GUI simple and clean, as I only have basic shapes available to me.</p>
<p dir="auto">While the Nextion supports drawing shapes and text, I wasn't able to remove some UI elements by sending serial commands. Perhaps the GUI editor tool would have allowed me to do a full reset, and remove the 'built in' demo animations. But my goal is to create plug-and-play things for beginners, and I don't want them to have to use the GUI tool in that process.</p>
<p dir="auto">What I like about this cheap screen is that it has built in support for drawing rounded rectangular boxes, which is very useful. It also has a 'quick horizontal line' function, which is similarly handy.</p>
]]></description><link>https://forum.mysensors.org/post/97277</link><guid isPermaLink="true">https://forum.mysensors.org/post/97277</guid><dc:creator><![CDATA[alowhum]]></dc:creator><pubDate>Mon, 11 Feb 2019 10:31:59 GMT</pubDate></item><item><title><![CDATA[Reply to Open Smart serial TFT LCD touch screen - example Arduino code on Thu, 07 Feb 2019 09:28:52 GMT]]></title><description><![CDATA[<p dir="auto">Hi,</p>
<p dir="auto">weird that you got problems with nextion.<br />
I think you have something wrong in the gui creator tool, sdcard, or code, else it should work.<br />
I have two here, and no problem. I'm not using them for HA, not a fan of "diy" displays, with small dpi, for home..But I always thought they are noob friendly (serial, easy to use api and gui creator tool, saving some coding time), so I'm sure you'll get it working.</p>
]]></description><link>https://forum.mysensors.org/post/97184</link><guid isPermaLink="true">https://forum.mysensors.org/post/97184</guid><dc:creator><![CDATA[scalz]]></dc:creator><pubDate>Thu, 07 Feb 2019 09:28:52 GMT</pubDate></item></channel></rss>