Using the Nextion Display without the Library

This page is focused on connecting MCUs to the Nextion Display using the serial port. Many people use the Nextion.h library. I found the library to be challenging to use. I started making the videos for myself due to my lousy memory. I didn’t think anyone would watch them, but the YouTube channel has grown over the years. If you need the code for the videos on YouTube, go to the “need help” page and submit a request. I will get to you as quickly as I can.

CLICK TO DONATE

This link is to a Nextion Display : https://amzn.to/3SHUsuh

This link is to an Arduino Nano : https://amzn.to/3HZbGyz

Default Arduino Nextion Configuration

The main page for this site will cover the basic setup of the Nextion/Arduino combination. This tutorial will use a basic 2.8-inch display (NX3224T028) and an Arduino Nano.

NEXTION IDE (V1.63.3)

We will start in the Nextion IDE. First, we create a stand-alone Nextion program similar to the video below. The sample will use a text box, number field, progress bar, timer, and variable. The timer will cause the progress bar to move to the right and then back to left. This will repeat infinitely. Note: the “tim” attribute is set to 50 milliseconds.

The program will change the text box to show “POSITIVE” when the black square is moving to the right and “NEGATIVE” when the black square is moving to the left. The number field will show the current value of the progress bar. In this example, I will show how to send values and text between the Nextion Display and the Arduino MCU. I like this example because it is a good way to show the commands sent from the Arduino are the same commands used in the Nextion.

The Nextion IDE running in DEBUG mode.

The only code for this project is tied to the timer called tm0. In the attributes, there is an attribute called “en” for enable. When you add the timer, it will be set to 1. Later in the tutorial, we will change the setting to 0. Setting the value to 0 will disable the timer and keep the code from running. There is another way to disable the timer by sending a command from the Arduino. I will show you how to do both. The code you need for tm0 is below.

h0.val+=va0.val
n0.val=h0.val
if(h0.val==100)
{
  va0.val=-1
  t0.txt="NEGATIVE"
}
if(h0.val==1)
{
  va0.val=1
  t0.txt="POSITIVE"
}

To change the text field t0, we need a command t0.txt=”POSITIVE.” First, we have the name of the object t0. Second, we have the attribute we want to change called “txt.” Finally, we have the value we want to change it too. In this case, we want it to display the word POSITIVE. The text object requires we surround the text we want to display with quotes. This is not the case in the number field.

To change the number field n0, we use the same logic. First, we have the name of the object n0. Second, we have the attribute “val.” Finally, we have the value that is to be assigned. Notice we do not surround values with quotes. This distinction is important when sending commands back from the Arduino.

ARDUINO IDE

Now we will create the same results but we will use an Arduino NANO. I use a default configuration when I start a project that uses a Nextion display. My configuration can be downloaded below.

The download contains four files. I will review each before I add the code to control the Nextion display. I will start with the first tab. Please note the name of the folder is also the name of the first tab. If you can’t download and need to copy and paste, I call this file default_config.ino.

// NOTE : Below is a String I use to add to the data sent to the Nextion Display
//        And to verify the end of the string for incoming data.
//        Replace 3 x Serial2.write(0xff);
String  endChar = String(char(0xff)) + String(char(0xff)) + String(char(0xff));
String  dfd  = ""; // data from display
// NOTE : General Async Delay 
unsigned long asyncDelay = 0;// NOTE : 4,294,967,295
int	 delayLength = 1000;
// NOTE : Comment out the next two lines if using an Arduino with more than 1 serial port(MEGA)
#include <SoftwareSerial.h>
SoftwareSerial Serial2(2, 3); // RX, TX

void setup() {
  Serial.begin(9600);
  Serial2.begin(9600);
  pinMode(13,OUTPUT);
}

void loop() {
  // NOTE : COLLECT CHARACTERS FROM NEXTION DISPLAY
  if(Serial2.available()){
    inputFunction();
  }
  // NOTE : ASYNC DELAY
  if(millis() > asyncDelay){
    asyncDelay+=delayLength;
    delayFunction();
  }
}

I start by declaring a String called endChar. It contains a series of three 0xFF. This comes in handy when sending commands to the Nextion. Every command needs to end with 0xFF. I follow that with another string variable called dfd, or dataFromDisplay. I use the variable to collect the characters sent from the Nextion.

I have two variables for my Asynchronous Delay. I have an unsigned long that counts from 0 to 4,294,967,295 and an int set to the length of the delay. I start with it set to 1000 milliseconds or 1 second.

I need a second Serial port for the Nextion. If you have a MEGA, PRO MICRO, or ESP32, then you can comment out the SoftwareSerial lines. I used a MEGA for a while, so I named the Software Serial port Serial2. this makes it so if you comment out the Software Serial, it works fine on a MEGA. I noticed it also works fine on the ESP32. If you have a PRO MICRO, you must change Serial2 to Serial1.

In the setup function, I start both serial ports and initialize the onboard LED. The LED is used to test the delay function.

In the main loop, I have two if statements. The first one executes if the Nextion sends characters to the Serial port. The second one executes when the delay times out. I set up separate files for what is executed.

cc_stuff.ino file

byte bcdToDec(byte val){
  return((val/16*10) + (val%16));
}
byte decToBcd(byte val){
  return((val/10*16)+(val%10));
}

void printBinary(int value){
 for(int mask = 0x80; mask; mask >>= 1){
   if(mask  & value)
       Serial.print('1');
   else
       Serial.print('0');
 }
}

I use the BCD functions for I2C applications, including a Real Time Clock. I use the print binary in some videos to show data in binary format.

delay.ino file

void delayFunction(){
  digitalWrite(13,!(digitalRead(13)));
  // NOTE : STUFF HERE
}

The delay is pretty simple. I digitally read the LED, and digitally write the inverted value. This comes in handy when starting a project. You can adjust the delay length to ensure your writing to the Arduino properly.

input.ino file

void inputFunction(){
  dfd += char(Serial2.read());
  if(dfd.length()>3 && dfd.substring(0,3)!="C:C") dfd="";
  else{
    if(dfd.substring((dfd.length()-1),dfd.length()) == "?"){
      String command = dfd.substring(3,6);
      String value = dfd.substring(6,dfd.length()-1);
      // NOTE : FOR TESTING
      Serial.println(command + " : " + value);
      // NOTE : TEST COMMAND "CMD"
      if(command == "CMD"){
        Serial.println("TEST COMMAND CMD : " + value);
      }
      dfd="";
    }
  }
}

The input.ino file is where the magic happens. I read the serial port and collected one character at a time. I structure the commands sent from the Nextion in a format for easy interpretation. I start each command with C:C delimiter. This lets me know I have a valid command. The third line of checks for garbage. If more than characters are received, and the first three are not C:C, the dfd string is overwritten. You could change your starting delimiter, but you would have to adjust this line for the characters you are looking for and the length.

Once we determine a legitimate command, we move down to the else statement. The first if statement in the else statement looks for my ending delimiter. I use the question mark (?). I thought I would have changed it, but so far, I have not sent a question mark from the Nextion. If you want to change your ending delimiter, you need to change the dfd.length()-1 portion to the length of your delimiter and the “?” to your delimiter.

Once we know, we have a string that starts with C:C and ends with ? I parse the string. My commands from the Nextion start with C:C then have a three-character command, then a value, followed by the ?. An example would be C:CCMD01?. The command is CMD, and the value is 01. I get the substring of characters 3-5 for the command and all the characters to the end, except the ? for the value.

I leave the CMD in my default configuration so I can do a quick test from the display. I start adding if(command ==””) for each command I want to send from the Nextion display.

Add in the Code

There is a variable that hold the position of the slider. That will be added to the main tab like below. We also need to disable the timer. If we do this in the Arduino, you will be able to see when it happens. If you start the display you will see the original code run. After you upload the code to the Arduino it should disable the timer and shift to the Arduino control.

// NOTE : Below is a String I use to add to the data sent to the Nextion Display
//        And to verify the end of the string for incoming data.
//        Replace 3 x Serial2.write(0xff);
String  endChar = String(char(0xff)) + String(char(0xff)) + String(char(0xff));
String  dfd  = ""; // data from display
// NOTE : General Async Delay 
unsigned	long asyncDelay = 0;// NOTE : 4,294,967,295
int	delayLength = 1000;
// NOTE : Comment out the next two lines if using an Arduino with more than 1 serial port(MEGA)
#include <SoftwareSerial.h>
SoftwareSerial Serial2(2, 3); // RX, TX

/***********************************************************************/
int incrementValue = 10; // NOTE : delay is 1 sec increment by 10 show change quicker
int progressValue = 50;  // NOTE : start at 50
/***********************************************************************/

void setup() {
  Serial.begin(9600);
  Serial2.begin(9600);
  pinMode(13,OUTPUT);
  /************************************************************************/
  delay(500); // Note : wait .5 seconds to make sure serial ports are established
  // NOTE : This command will disable the timer.
  //        In the Nextion you would adjust the attribute or use tm0.en=0
  Serial2.print("tm0.en=0" + endChar);
  /************************************************************************/
}

void loop() {
  // NOTE : COLLECT CHARACTERS FROM NEXTION DISPLAY
  if(Serial2.available()){
    inputFunction();
  }
  // NOTE : ASYNC DELAY
  if(millis() > asyncDelay){
    asyncDelay+=delayLength;
    delayFunction();
  }
}

The next step will add the commands to adjust the slider. Those will be added in the delay tab. This way we can control the speed as we move the progress bar left and right. I left the code from the Nextion timer and also added comments. IF you find that hard to follow I will also display the code without the Nextion code.

void delayFunction(){
  digitalWrite(13,!(digitalRead(13)));
  // NOTE : STUFF HERE
  // NOTE : I have coped the code from the Nextion display
  // h0.val+=va0.val -- variables are now in the Arduino
  progressValue+=incrementValue;
  // NOTE : now we send the value to the nextion
  Serial2.print("h0.val=" + String(progressValue) + endChar);
  // n0.val=h0.val -- send value to n0
  Serial2.print("n0.val=" + String(progressValue) + endChar);
  //if(h0.val==100) -- h0 needs changed to progressValue
  if(progressValue==100)
  {
    //va0.val=-1 -- va0 is incrementValue variable
    incrementValue = -10;
    //t0.txt="NEGATIVE" -- need to send text to t0
    Serial2.print("t0.txt=\"NEGATIVE\"" + endChar);
  }
  //if(h0.val==1) -- h0 needs changed to progressValue
  if(progressValue==0)// NOTE : need to change from 1 to 0
  {
    //va0.val=1
    incrementValue = 10;
    //t0.txt="POSITIVE"
    Serial2.print("t0.txt=\"POSITIVE\"" + endChar);
  }
}
void delayFunction(){
  digitalWrite(13,!(digitalRead(13)));
  progressValue+=incrementValue;
  // NOTE : now we send the value to the nextion
  Serial2.print("h0.val=" + String(progressValue) + endChar);
  Serial2.print("n0.val=" + String(progressValue) + endChar);
  if(progressValue==100)
  {
    incrementValue = -10;
    Serial2.print("t0.txt=\"NEGATIVE\"" + endChar);
  }
  if(progressValue==0)// NOTE : need to change from 1 to 0
  {
    incrementValue = 10;
    Serial2.print("t0.txt=\"POSITIVE\"" + endChar);
  }
}

I have attached a copy of the completed code

Below is a link to the DataRecord program