Using Nextion displays with Arduino

Hi Theron, Here is some demonstration code for a Nextion with 5 pages, this changes the pages 0, 1, 2, 3, 4 then back to 0. You can change the number of pages by changing pageCount to however many pages you have. I have set the baud rate to 9600 as that is the default for a Nextion.

/* Demonstrates changing pages with the Arduino telling the Nextion which page to change to */
/* Uses the Nextion configuration 'Nextion_additional_features', which can be found in part 4 of this tutorial */
/* Tested on a Mega using serial port 1 connected to a NX4827T043_11 */

#define waitTime 1000       // Delay between each change of page
#define pageCount 5         // Number of pages on the Nextion
#define serialBaud 9600     //Baud rate for serial monitor
#define NextionBaud 9600    //Baud rate for Nextion

void setup() {
  Serial.begin(serialBaud);       // For the serial monitor
  Serial1.begin(NextionBaud);     // For the Nextion
}

void loop() {
  change_page();
}

void change_page() {
  static uint8_t page = 0;    //Current page on the Nextion
  static uint32_t previousMillis;
  uint32_t currentMillis = millis();
  if (currentMillis - previousMillis >= waitTime) {
    previousMillis = currentMillis;
    Serial.print("Page changing to ");      // Prints onto the serial monitor
    Serial.println(page);
    Serial1.print("page ");                 // Tells the Nextion to change pages
    Serial1.print(page);
    Serial1.print("\xFF\xFF\xFF");
    page = ++page % pageCount;
  }
}

Hello Perry and everyone else, this has been an amazing useful chunk of info packed for everyone to start using the Nextion :)

I've been playing around with a 4.3" and an arduino for an audio project, and yes it does generate some noise. Does the 470uF capacitor help with the noise, or is it for smoother run of the LCD? Have you investigated further into the noise thing?

Thank you, Vangelis

Does the 470uF capacitor help with the noise, or is it for smoother run of the LCD? Have you investigated further into the noise thing?

When I first used Nextion displays I noticed they were interfering with things. Most notable I had a GPS receiver that would only work if I put it a long way from the Nextion. I put a 1 Ohm resistor in series with the supply and used it to monitor the current with an oscilloscope, you can see the result below. As this is measured across a 1 Ohm resistor the peak of the spikes is about 930mA. The second image is the exact same set up but with a 470μF capacitor soldered across the connector on the Nextion. 470μF was the smallest value capacitor that completely eliminated the spikes.

Thanks for the tutorial! I am just getting started with the Nextion display and I have a question about how you are changing data sent from the display to the screen. You said:

"Unlike the displays, I chose not to use 0xff 0xff 0xff as a terminator for the data sent to the Arduino. Instead I use 0xa5 0xa5 0xa5 as a start indicator followed by 5 bytes. Sometimes the last byte or 2 is just padding to bring the total to 5. You can modify the code to expect more or fewer bytes, or use a different start sequence. The 5 bytes are the page number, the type, the index of the type and 2 data bytes."

I am trying to understand how you accomplish this? I read through the tutorial and I may have missed it. Could you explain how you are doing so?

Also, I tried to open your .HMI file and am getting the error message "Wrong Resource file or resource file has been damaged". It could be my computer, but I did go download the Visual studio files you suggested.

If you feel like the issue is my computer ok, but I am able to open other HMI files and create my own without issue, so I thought it may have something to do with the file?

My main question is how to change the serial output from the display to the arduino. Thanks in advance!

Hi Perry.

I’m successfully using your method to drive 3 displays. They are set to sleep after 30 seconds and wake on touch. I want to only update one display when it wakes (It’s mainly a clock and temperature display).

On wake, they send :
68 xx xx yy yy 01 FF FF FF → touch coordinate
68 xx xx yy yy 00 FF FF FF → release coordinate
0x87 0xFF 0xFF 0xFF

They don’t register the wake touch as a touch/release event, so I can’t use your 8 byte sequence.

Is it possible to integrate reading 0x87 0xFF 0xFF 0xFF into your read code?

Nextion_3_V1.zip (274 KB)

Hello Chrisplusian

I tried to open your .HMI file and am getting the error message "Wrong Resource file or resource file has been damaged". It could be my computer, but I did go download the Visual studio files you suggested.

As a test I have downloaded 2019-07-27 Arduino Nextion demo 43.zip from this tutorial, extracted the HMI file and opened it with V0.59 of the Nextion editor without difficulty, so I am confident that the file on this web site is not corrupted. The Visual studio files are required for V0.59 of the Nextion editor to run. If you have managed to open the editor then it working. If you can't open the HMI file then the problem is elsewhere, but I don't know what to suggest. I am assuming you extracted it from the zip file before trying to open it and that you are using V0.59 (V0.58 works too).

"Unlike the displays, I chose not to use 0xff 0xff 0xff as a terminator for the data sent to the Arduino. Instead I use 0xa5 0xa5 0xa5 as a start indicator followed by 5 bytes. Sometimes the last byte or 2 is just padding to bring the total to 5. You can modify the code to expect more or fewer bytes, or use a different start sequence. The 5 bytes are the page number, the type, the index of the type and 2 data bytes."

Everything I send from the Nextion is sent using printh, which sends a single hexadecimal byte, giving me complete control over what is sent. When you manage to open the HMI file take a look at touch release event under the buttons, you will see the code I use to send from the Nextion to the Arduino. Note that in the direction Arduino to Nextion the terminator is 0xff 0xff 0xff as there is no way that I know of to change this.

mazellan: Hi Perry.

I'm successfully using your method to drive 3 displays. They are set to sleep after 30 seconds and wake on touch. I want to only update one display when it wakes (It's mainly a clock and temperature display).

On wake, they send : 68 xx xx yy yy 01 FF FF FF -> touch coordinate 68 xx xx yy yy 00 FF FF FF -> release coordinate 0x87 0xFF 0xFF 0xFF

They don't register the wake touch as a touch/release event, so I can't use your 8 byte sequence.

Is it possible to integrate reading 0x87 0xFF 0xFF 0xFF into your read code?

I've never used sleep in any of my project, so not considered how to use it. If you look at part 4 of the tutorial (reply #3) there is Nextion_additional_features.zip, download that. In the function HMI_read() (in the tab _01_Middle) I have added code to save Nextion return codes ending with 0xff 0xff 0xff so they can be sent to the serial monitor. You could use this as a way to capture the 'wake' messages and then do whatever you need to with them.

On 2 of my projects I dim the display to a low level if it is not touched for 30 seconds or so, then it goes back to full brightness when touched. I realise this is not the same as sleep, but it does mean I have full control over what happens when the display is touched.

PerryBebbington:
Hello Chrisplusian
As a test I have downloaded 2019-07-27 Arduino Nextion demo 43.zip from this tutorial, extracted the HMI file and opened it with V0.59 of the Nextion editor without difficulty, so I am confident that the file on this web site is not corrupted. The Visual studio files are required for V0.59 of the Nextion editor to run. If you have managed to open the editor then it working. If you can’t open the HMI file then the problem is elsewhere, but I don’t know what to suggest. I am assuming you extracted it from the zip file before trying to open it and that you are using V0.59 (V0.58 works too).

Everything I send from the Nextion is sent using printh, which sends a single hexadecimal byte, giving me complete control over what is sent. When you manage to open the HMI file take a look at touch release event under the buttons, you will see the code I use to send from the Nextion to the Arduino. Note that in the direction Arduino to Nextion the terminator is 0xff 0xff 0xff as there is no way that I know of to change this.

I was finally able to open the .HMI screen. I previously had verison 53, and I did the update and apparently it didn’t work. I uninstalled and re-installed the nextion editor and for some reason it still installed V53. I used my wifes laptop and installed V59 with no problem. So I couldn’t open the .hmi as a result of an older version. Thanks for the tutorial and quick responses!

I have finally had the chance to sit down with the Code you provided and the HMI. I don't know why, but the display is not actually showing the clock value, however I am able to see the functionality of all the buttons, the slider, and the page concepts. I am guessing it has something to do with the fact I have an Arduino Uno, and am using one of the Basic displays, but I am not positive.

This tutorial has the tools necessary to allow me to develop the application I am creating.

One side note: The Nextion website lists print to be depreciated and it looks like it will add a length attribute, but it seems you can limit the number of bytes sent as well.

Thanks again for taking the time to put this demo together.

I don't know why, but the display is not actually showing the clock value, however I am able to see the functionality of all the buttons, the slider, and the page concepts. I am guessing it has something to do with the fact I have an Arduino Uno, and am using one of the Basic displays, but I am not positive.

I would not expect that using a basic display would cause a problem, I was careful to design the code to use the minimum of the resources available on a Nextion and everything in this tutorial has been tested on a NX4827T043, which is one of the basic Nextion displays.

A Uno might be a problem as the only serial port is the one used for the USB connection to your PC, so using it for connection to a Nextion (or anything else) means you have 2 different serial connections fighting each other. I did originally test everything using a Uno and I didn't find any problems, however, given that, theoretically at least, there might be problems I have not stated in the introduction that any of this works with a Uno. For changes to this tutorial I mostly test on a Mega, and sometimes on an MKR1010.

One side note: The Nextion website lists print to be depreciated and it looks like it will add a length attribute, but it seems you can limit the number of bytes sent as well.

Thanks, I didn't notice that, I appreciate you pointing it out. I have updated the demonstration files to use prints, which I see replaces print. If you find I've missed any please tell me (I think I only used print for the scroll bar, but there's always the possibility I used it elsewhere and forgot!) ++Karma;

I have a question? where do i set what RX TX port im using with my mega2560? i cant seem to find the info.

//This is for serial port 1, which is the one used for the Nextion in this demonstration. You might need to change this depending on which serial port you are using for your display. Serial1.begin(9600);

If im using serial port 2 then do i put Serial2.begin(9600) in my code? or am i missing something? thanks

DRE50: If im using serial port 2 then do i put Serial2.begin(9600) in my code? or am i missing something? thanks

Yes, correct. You also need to go through the code and change every instance of Serial1 to Serial2.

Hello Perry,

I recently tried contacting you about an issue with this project that I am experiencing and you told me to post it on the forum. I have tried that 3 separate times and even after following the the forum guidelines it keeps having errors and not posting so I am just going to post it here.

I am fairly new at using both Arduino and Nextion displays so I tried looking online for tutorials about how other people have made them work together. Most of these tutorials have use of the Nextion library so I have tried multiple uses of that but none of them worked quite right. The board and display would not communicate. So I finally found your demonstration about how to do this without the library and it seemed much more simple and made more sense to me. But since I was frustrated with not getting these devices to communicate together I just used your code (Nextion_demonstration43) and displays for starters so that I could change things around once I everything communicating.

The only difference between your display and mine is that mine is the 10.1" so when I loaded your screens onto it they stayed in the upper left corner. Not an issue when you're just trying t make something work. The code however was slightly changed but only by changing the serial port used like you had said to do. Since my board is an Arduino Uno I do not have any extra ports so I have to use pins 0 and 1. I had seen on other tutorials that people have made this work by loading the sketch to the board with the RX and TX of the HMI disconnected and then unplugging the board from the computer and powering it with an external power supply and reconnecting the RX and TX to the TX and RX of the board. I did this and most of the program seemed to work like the messages "This is page 0" and "Please do not press this button again", the hex and decimal values for the slider on page 1 even read. But the clock on page 0 remains at "hh: mm: ss" with not number values there.

I guess my question is if there is a different way of using serial communication with my Uno or if I need an Arduino Mega? And are there any errors in my code that I missed? Like I said all I changed were the comm. ports but then it should have worked. Any help would be greatly appreciated.

Sorry this would not send as one piece…

void setup() {
  //This is for the serial monitor. Remove the // if you need to use it.
  //Serial.begin(9600);
  
  //This is for serial port 1, which is the one used for the Nextion in this demonstration. You might need to change this depending on which serial port you are using for your display.
  Serial.begin(9600);

  //For  demonstration
  HMI_startup_message();
}

void loop() {
  HMI_read();
  clock_run();
}

struct CLOCK {
  int8_t hour;
  int8_t minute;
  int8_t second;
};
struct CLOCK clock;

//This displays the clock
void HMI_display_clock() {
  char timestring[9];
  sprintf(timestring, "%02d:%02d:%02d ", clock.hour, clock.minute, clock.second);
  Serial.println(timestring);
  Serial.print(F("t1.txt=\""));
  Serial.print(timestring);
  Serial.print("\"");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}

//This displays the page number
void HMI_display_page(uint8_t page) {
  Serial.print(F("t0.txt=\""));
  Serial.print(F("This is page "));
  Serial.print(page);
  Serial.print(F("\""));
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}

void HMI_P1_display_slider(uint8_t slider_d1, uint8_t slider_d0) {
  uint16_t slider_val = (slider_d1 <<8 | slider_d0);
  
  //This displays byte 1 of the slider value in HEX
  Serial.print(F("t2.txt=\""));
  Serial.print(slider_d1, HEX);
  Serial.print(F("\""));
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
  
  //This displays byte 0 of the slider value in HEX
  Serial.print(F("t3.txt=\""));
  Serial.print(slider_d0, HEX);
  Serial.print(F("\""));
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  //This displays the complete slider value in decimal
  Serial.print(F("t4.txt=\""));
  Serial.print(slider_val);
  Serial.print(F("\""));
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}

void HMI_startup_message() {
  Serial.print(F("t0.txt=\""));
  Serial.print(F("Nextion demonstration by Perry Bebbington. For support go to https://forum.arduino.cc/index.php?board=7.0"));
  Serial.print(F("\""));
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}

//HMI_read takes the data sent from the Nextion to the serial port and processes it depending on what has been sent
//There are 3 levels of nested switch statements corresponding to the page, the type of object and the index of the object.
void HMI_read() {
  static uint8_t HMI_read_data[10];         //This is a temporary buffer to hold the data from the display. Space for 10 bytes although this demonstration only uses 6 bytes
  static uint8_t HMI_read_data_i;           //This is a count of how many bytes have been received from the display.
  static uint8_t a5count;                   //0xa5 repeated 3 times is used as a start indicator, this is a count of how many times it has been received.
  uint8_t readtemp;                         //This is to hold the last received byte to ensure that it is only read from the receive buffer once.
  
  while (Serial.available() > 0) {         //Read every byte in the receive buffer
    readtemp = Serial.read();
    if (readtemp == 0xa5) {                 //Count the number of times 0xa5 has been received
      ++a5count;
      if (a5count > 2) {
        a5count = 0;
        HMI_read_data_i = 0;
      }
    }
    else {
      a5count = 0;
    }
    HMI_read_data[HMI_read_data_i] = readtemp;
    if (HMI_read_data_i == 5) {
      switch (HMI_read_data[1]) {             //HMI_read_data[1] contains the page the data has come from
        case 0:                               //Case 0 means the data has come from page 0
          switch (HMI_read_data[2]) {         //HMI_read_data[2] contains the type of object on the page that the data has come from
            case 0:                           //In this demonstraton case 0 selects a page
              HMI_display_page(HMI_read_data[3]);
              break;
            case 1:                            //In this demonstration case 1 is a button for setting the clock
              switch (HMI_read_data[3]) {      //HMI_read_data[3] is the index of the type of button, so 0 to 5 as there are 6 buttons for setting the clock. Each case is a different button.
                case 0:
                  ++clock.hour;
                  if (clock.hour > 23) {
                    clock.hour = 0;
                  }
                  break;
                case 1:
                  --clock.hour;
                  if (clock.hour < 0) {
                    clock.hour = 23;
                  }
                  break;
                case 2:
                  ++clock.minute;
                  if (clock.minute > 59) {
                    clock.minute = 0;
                  }
                  break;
                case 3:
                  --clock.minute;
                  if (clock.minute < 0) {
                    clock.minute = 59;
                  }
                  break;
                case 4:
                  ++clock.second;
                  if (clock.second > 59) {
                    clock.second = 0;
                  }
                  break;
                case 5:
                  --clock.second;
                  if (clock.second < 0) {
                    clock.second = 59;
                  }
                  break;
              }
              HMI_display_clock();
              break;
          }
          break;
        case 1:                               //Case 1 means the data has come from page 1
          switch (HMI_read_data[2]) {
            case 0:                           //Data from the page itself, this is the post initialisation request to update the page, which displays the page number
              HMI_display_page(HMI_read_data[3]);
              break;
            case 1:                           //Data from the slider on page 1
              HMI_P1_display_slider(HMI_read_data[5], HMI_read_data[4]);      //HMI_read_data[5] is byte 1 of the slider value, HMI_read_data[4] is byte 0 of the slider value
              
              
              
              break;
          }
          break;
      }
    }
    ++HMI_read_data_i;
    if (HMI_read_data_i > 9) {
      HMI_read_data_i = 9;
    }
  }
}

void clock_run() {
  static unsigned long previousMillis;
  unsigned long currentMillis = millis();
  const unsigned long interval = 1000;
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    ++clock.second;
    if (clock.second > 59) {
      clock.second = 0;
      ++clock.minute;
      if (clock.minute > 59) {
        clock.minute = 0;
        ++clock.hour;
        if (clock.hour > 23) {
          clock.hour = 0;
        }
      }
    }
    HMI_display_clock();
  }
}

Hello,

I would expect you to have problems using a Uno to communicate with a Nextion because the serial port is already in use communicating with the USB connection. The Uno schematic shows 1k Ohm resistors in series with the connection between the ATmega328 and then CH340 that controls the USB connection, so you might be able to get it working on the serial port, but this seems like a bit of a bodge to me. If it works then fine, it works. If not then yes, I suggest buying an Arduino with a spare serial port, such as a Mega. However, if you have some features of my code working that suggests the problem is not the serial port.

And are there any errors in my code that I missed?

I'm not sure how you expect me to answer that with code I cannot see....! :confused:

You need to find every single instance of Serial1.something and change it to Serial.something. Miss one and it won't work. If you are not seeing the clock then I guess you missed one in the function void HMI_display_clock();

[EDIT] You had not posted your code when I typed the above.... Also, my dinner is ready, back later :)

In the function:

//This displays the clock
void HMI_display_clock() {
  char timestring[9];
  sprintf(timestring, "%02d:%02d:%02d ", clock.hour, clock.minute, clock.second);
  Serial.println(timestring);
  Serial.print(F("t1.txt=\""));
  Serial.print(timestring);
  Serial.print("\"");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}

Is the line

  Serial.println(timestring);

Which sends the time to the serial monitor. When HMI_display_clock is used as intended, with the Nextion on serial port 1, this line doesn't matter. When you connect the Nextion to the serial port monitor then this line makes a mess of the data sent to the Nextion. You need to comment out that line then it will work, like this:

//This displays the clock
void HMI_display_clock() {
  char timestring[9];
  sprintf(timestring, "%02d:%02d:%02d ", clock.hour, clock.minute, clock.second);
  // Serial.println(timestring);
  Serial.print(F("t1.txt=\""));
  Serial.print(timestring);
  Serial.print("\"");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}

Thank you that worked! The clock is now counting and everything appears to be communicating properly. And it appears that the dimming of the screen is 100% controlled by the program in the HMI and has nothing to do with the arduino code... Is that correct?

Thank you again.

Squid171: It appears that the dimming of the screen is 100% controlled by the program in the HMI and has nothing to do with the Arduino code... Is that correct?

Yes, the screen dimming is on the Nextion, I leave you to discover how it works.

This tutorial is locked because I think there are enough questions and answers to cover most things.

Please do not send me a PM with questions about this tutorial or Nextion displays in general, I will just reply telling you to use the forum.

If you have a question about either this tutorial or about your project that includes a Nextion display then read how to get the best out of this forum and start a new question in the appropriate section of the forum.

Thank you!