Go Down

Topic: Using Nextion displays with Arduino (Read 702 times) previous topic - next topic

PerryBebbington

Mar 17, 2019, 05:58 pm Last Edit: Mar 17, 2019, 06:57 pm by PerryBebbington
Introduction

 Nextion displays include either a resistive touch panel (RTP) or capacitive touch panel (CTP) and provide an easy way to create a touch screen interface, or human machine interface (HMI) for your project. The displays require a spare serial port to communicate with them. To get the best from them requires an understanding of how to drive them, and what works and doesn't work. The advice here is based on my work with 4 projects using Nextion displays with both PIC and Arduino hosts. I don't claim the ideas here are the best way or the only way to control one with an Arduino, just what I have found to work well in my projects. The sample code has been written by me and tested on an Elegoo Mega2560, and you are free to use it, modify or improve as much as you like. The examples do not use any libraries as I never found them necessary, the displays are easy enough to drive without a library. For this reason if you want advice about a Nextion Library I'm sorry but I cannot help. I do not represent Arduino or Nextion.

Nextion support

The displays have their own instruction set which can be found here. The instructions provide the means to control the displays either through messages sent to the serial port or from using the touch screen. This tutorial and sample code uses some of the Nextion instructions and assumes you have made yourself familiar with them from the Nextion web site.

The displays are configured using a WYSIWYG editor, which you can download from here. The sample configuration attached to this tutorial can be opened with this editor, which you will need to use the example here.

Compatibility with Arduino

I have used the basic 4.3" RTP version (NX4827T043) and the enhanced 7" CPT version (NX8048K070) with a WeMos M0 and Elegoo Mega2560 without problems. I have not tried other versions or other Arduinos. As the only requirement is a spare serial port on the Arduino to connect the display to, I would expect that any Arduino with a spare serial port would work with any Nextion display, but I've not tried combinations other than those mentioned here.

Demonstration
You will need:
 
 • The attached 'Arduino Nextion demo 43V1 HMI', which can be opened with the Nextion editor.
 • The attached 'Nextion_demonstration43.ino', which can be opened with the Arduino IDE.
 • An Arduino with at least 1 spare serial port.
 • A Nextion display.
 • A micro SD card.

Connecting the Nextion display to your Arduino

The displays come with a cable with 4 wires. I have only ever seen them in the following colours but if you get one with different colours please let me know so I can update this part of the tutorial.
 • Red - for connecting to +5V
 • Black - for connecting to 0V
 • Blue - Transmit data from the display to the Arduino, connect to RX on the Arduino
 • Yellow - Receive data from the Arduino to the display. Connect to TX on the Arduino
 
 Note, Arduinios use one serial port for communication with your PC, do not use this serial port for connection to your Nextion display, use a spare one.
 
 The displays run off 5v. All the ones I have output 3.3v on their serial transmit (blue wire). I have not had any problems using them with a WeMos M0 at 3.3v, an Elegoo Mega2560 at 5V or a PIC running on 5v. However, please check the voltage on the display transmit (blue) wire is not higher than maximum voltage your Arduino can tolerate.
 
 To connect a Nextion to an Arduino you need one free serial port on the Arduino. Connect the TX from the Arduino to the yellow wire and the RX to the Arduino to the blue wire. You will also need 0v to the black wire and +5v to the red wire. The current drawn by the display depends on the model and how bright the back light is. The 7" CPT display NX8048K070 requires up to 550mA, the smaller ones less. The 4.3" NX4827T043 used for this tutorial draws 235mA. In my experience they generate quite a bit of noise on the supply and, although not essential, I recommend a 470μF capacitor across the supply soldered to the connector on the back.
 Please see photo



This shows the back of the display with a 470μF capacitor soldered to the outside 2 connections of the connector. Note that it is essential that the negative connection of the capacitor goes to GND and the positive to +5V, otherwise you will fill your room with nasty smelling smoke and scare your cat.





Demonstration software

This demonstration was created for the basic 4.3" RTP version, NX4827T043. You can adapt my configuration for a different display using the Nextion editor.
 
 Open the attached file 'Arduino Nextion demo 43V1.HMI' with the Nextion editor. If you are using a smaller display move the position of any objects that are outside the display area of the smaller display by changing X and Y for each object to a value that puts the object inside the boundaries of your display. Once you have done this select DEVICE ID from the menu and select your display from the list. If you have a bigger display you don't need to move anything around, just select the correct device ID.
 
 Compile the display configuration by clicking 'compile'.
 
 Click on File > Open build folder, this should open a window with a file 'Arduino Nextion demo 43V1.tft'
 
 Copy this file, and only this file, to a micro SD card (There must be nothing else on the SD card)
 
 Put the micro SD card into the card reader slot on the side of the display and connect the black wire to 0V and the red wire to 5V. You should see the display updating, which takes about 5 seconds.

PerryBebbington

#1
Mar 17, 2019, 06:22 pm Last Edit: Mar 17, 2019, 07:07 pm by PerryBebbington
Using Nextion displays with Arduino part 2

Once it has finished disconnect the power and then remove the SD card. Connect the power again and the display should start up and look something like this:



Whatever version of display and Arduino you use make sure you know how to reference the serial port you are using. Because there are many Arduinos and clones, with varying numbers of serial ports, and because the choice of serial port is up to you, I cannot cover all possibilities in this tutorial. To develop this tutorial I used serial port 1 on an Elegoo Mega2560. You will need to edit the code to match the serial port you are using.

By default the Nextion serial port is configured for 9600 Baud and if you are new to Arduino or Nextion or both I recommend you leave it at 9600 Baud so that is one less thing to worry about if something doesn't work.

All you need to set up the Arduino for a Nextion display is:
Code: [Select]
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.
  Serial1.begin(9600);
  
  //For demonstration
  HMI_startup_message();
}
void HMI_startup_message() {
  Serial1.print(F("t0.txt=\""));
  Serial1.print(F("Nextion demonstration by Perry Bebbington. For support go to https://forum.arduino.cc/index.php?board=7.0"));
  Serial1.print(F("\""));
  Serial1.write(0xff);
  Serial1.write(0xff);
  Serial1.write(0xff);
}


Demonstration sketch and Nextion configuration.

The demonstration sketch creates a real time clock using millis()as the timing source. If you have read the various Arduino tutorials or are experienced with Arduino you will know that millis() is not accurate enough for an accurate real time clock. The purpose of this tutorial is to demonstrate an Arduino controlling a Nextion, and a clock seemed a simple way to do so. I leave it to you to create a more accurate clock.

Sending data to the display.

Sending to the display requires an understanding of the Nextion instruction set and what the display expects to receive. In the demonstration configuration there is a text box at the bottom with objname t0. To send text to this the display needs to receive.

t0.txt="Your text here"0xff 0xff 0xff

This is typical of any instruction, text or data, sent to the display. The display expects 0xff 0xff 0xff to indicate the end of the instruction.

For example:
Code: [Select]
void HMI_display_page(uint8_t page) {
  Serial.print(F("t0.txt=""));
  Serial.print(F("This is page "));
  Serial.print(page);
  Serial.print(""");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}


Puts the page number on t0.

Sending data from the Nextion display to the Arduino

I developed my own way of sending data from the display to the Arduino, which has proved flexible enough to adapt to all the applications I have so far tried. The basic idea is to identify each object on a page by the page it belongs to, its type and an index of that type.

'Type' is whatever you want it to be. Your project will have any number of buttons, sliders and whatever else on each page, you can group similar ones together and give them the same type, which is a number from 0 to however many you need. I reserve type 0 for the page itself.

'Index of type' is a number from 0 to 1 less than however many instances of the type there are on the page.

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.

The receive function looks for 0xa5 repeated 3 times, then saves the next 5 bytes in an array, then uses 3 levels of nested switch statements to identify which object on which page sent the data. Each case of the lowest level switch statement represents an individual object on the display and can be used to call whatever code you need for your project. The receive function should be called once each time in the main loop and will empty the receive buffer each time it is called.



PerryBebbington

#2
Mar 17, 2019, 06:33 pm Last Edit: Mar 17, 2019, 11:16 pm by PerryBebbington Reason: Move 'some things that might help you' to separate post.
Using Nextion displays with Arduino part 3

Complete demonstration code

The complete code for the demonstration is here and attached as 'Nextion_demonstration43.ino'

Setup and main loop

Code: [Select]

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.
  Serial1.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);
  Serial1.print(F("t1.txt=\""));
  Serial1.print(timestring);
  Serial1.print("\"");
  Serial1.write(0xff);
  Serial1.write(0xff);
  Serial1.write(0xff);
}

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

void HMI_startup_message() {
  Serial1.print(F("t0.txt=\""));
  Serial1.print(F("Nextion demonstration by Perry Bebbington. For support go to https://forum.arduino.cc/index.php?board=7.0"));
  Serial1.print(F("\""));
  Serial1.write(0xff);
  Serial1.write(0xff);
  Serial1.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 (Serial1.available() > 0) {         //Read every byte in the receive buffer
    readtemp = Serial1.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:
              HMI_display_page(HMI_read_data[3]);
              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();
  }
}



PerryBebbington

#3
Mar 17, 2019, 11:12 pm Last Edit: Mar 17, 2019, 11:14 pm by PerryBebbington
Using Nextion displays with Arduino part 4

Some things that might help you


Numbers
You might have noticed that in this demonstration I have used a single text box, t1, to display the time, I have not used one of the pre-defined number objects available in the Nextion editor. I found the numbers to be pretty useless, they can only be integers and they can't have any symbols attached to them, so you can't easily do £123.65 or 23.85% for example. Using a text box and print is much simpler.

Sliders
Sliders generate 4 bytes to show their position. This is way too much resolution. The biggest displays are 480 x 800 pixels, so the maximum possible number of positions that can be displayed is 800 as that's the maximum number of pixels available in one direction to show unique slider positions. The first 2 bytes received are all that is needed to uniquely identify the slider position.

Baud rate
You can change the baud rate from 9600. In the Nextion editor select page 0 and find post initialisation event under event. Put baud=<required baud rate> as the first entry, for example baud=19200. This will make the display initialise with a baud rate of 19200. In your sketch initialise the serial port with:

Code: [Select]
Code: [Select]
void setup() {
   //This is for serial port 1, which is the one used in this demonstration.
   //You might need to change this depending on which serial port you are using for your display.
  Serial1.begin(19200);
}


If you want to change the baud rate during program execution you have to be careful not to end up with the Arduino at one baud rate and the display at another. For this reason you need to send the change of baud rate instruction to the display, wait for the instruction to be sent then change the rate on the Arduino, then send data and instructions at the new rate. This will tell the display to change its baud rate:

Code: [Select]
Code: [Select]
void HMI_baud_change(uint32_t baud) {
  Serial.print(F("baud="));
  Serial.print(baud);
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}


However, you have to remember that serial transmission is slow, so after the last Serial.write(0xff); has completed the 'b' of baud will probably not have been sent to the display. Also, once the display has received the complete instruction it takes time to make the change. For this reason you need to wait before changing the Arduino baud rate with:

Code: [Select]
Code: [Select]
Serial.begin(new baud rate);

Changing pages
If you look at my demonstration configuration there are 2 buttons P0 and P1 on each page. P1 on page 0 and P0 on page 1 change the page displayed but don't tell the Arduino that the page has changed. On each page under post initialisation event is the code that tells the Arduino that the page has changed. This is to ensure that the page has properly initialised before the Arduino sends any data to it.

Credits
Thank you Robin 2 and Ballscrewbob for your help with this tutorial

Watcher

Excellent Tutorial!

Does anyone know if its possible to create objects with serial commands just like its done via the editor?

I.e Is it possible to create a button from serial and the nhange all its attributes?






PerryBebbington

Excellent Tutorial!

Does anyone know if its possible to create objects with serial commands just like its done via the editor?

I.e Is it possible to create a button from serial and the change all its attributes?
Quote
Excellent Tutorial!
:) THANK YOU!!! :)


Quote
Does anyone know if its possible to create objects with serial commands just like its done via the editor?
I.e Is it possible to create a button from serial and the change all its attributes?
I think probably not. There are attributes that cannot be changed by sending instructions over the serial port. If you look in the Nextion editor at an object some of the attributes are in green text and some in black text. I have not tried every possibility but I was trying to change some of the attributes that are in black text by sending instructions over the serial port and concluded they they cannot be changed this way. I assume from this that if an object has attributes that cannot be changed over the serial port then it must be impossible to create an object over the serial port.

What are you trying to achieve? There might be a way round this restriction.


Watcher

#6
Apr 01, 2019, 08:43 pm Last Edit: Apr 01, 2019, 08:45 pm by Watcher
Quote
What are you trying to achieve? There might be a way round this restriction.
I plan to develop a touch screen display for an existing home automation system which is RS485 based.


So basically I need to program a series of soft push button on the display whose description as well as status (on/off) will come from the Arduino.

Pushing the button should send Arduino a unique code which will then execute the associated home automation command.

If it was possible to create buttons with serial commands, then the actual screen layout could be controlled by the arduino.
I did something similar on web based home automation screen using the html dom.

The button press return code whoukd also be remotely set (via serial command)  as well.




PerryBebbington


Quote
I need to program a series of soft push button on the display whose description as well as status (on/off) will come from the Arduino.
You can change the text on a button in the same way as you change the text in a text box. You can also change the background colour and the text colour with the appropriate serial commands. For example:


Code: [Select]
void HMI_button_on_message() {
  Serial1.print(F("b0.txt=\""));
  Serial1.print(F("On"));
  Serial1.print(F("\""));
  Serial1.write(0xff);
  Serial1.write(0xff);
  Serial1.write(0xff);
}

Will change the text on button b0 to On.

Play around in the Nextion editor with the debug options and see what you need to send to an object to change particular attributes. For example, in debug, if you type

Code: [Select]
b0.bco=63488<return>

then b0 will become red.


Quote
Pushing the button should send Arduino a unique code which will then execute the associated home automation command.
That's what my method does! Each button in the example sends a unique code that is decoded by the 3 levels of switch() statements to a unique point from which you can call whatever functions you like.


Quote
If it was possible to create buttons with serial commands, then the actual screen layout could be controlled by the arduino.
I don't believe you can change the layout, only the text and colours of the buttons.


Quote
The button press return code should also be remotely set (via serial command)  as well.
You don't need to. You change how your program responds to each unique code sent from the buttons.

What you could do is have multiple pages on the Nextion and have the Arduino send instructions to change the page. Each page would have the different layouts and each button would have a unique identity on the page. If you look at my demonstration I included 2 pages to illustrate how this works.





Watcher

#8
Apr 02, 2019, 09:21 am Last Edit: Apr 02, 2019, 04:20 pm by Watcher
Quote
lay around in the Nextion editor with the debug options and see what you need to send to an object to change particular attributes. For example, in debug, if you type

Code: [Select]

b0.bco=63488<return>
Yeap! Already tried all that!

eg  This function changes the text on a textbox:

Code: [Select]
void HMI_displayText(byte boxNo, char* text){
 
  nextion.print(F("t"));
  nextion.print(boxNo);
  nextion.print(F(".txt=\""));
  nextion.print(text);
  nextion.print(F("\""));
 
  HMICommandEnd();
 
}


and this changes the color of a button :

Code: [Select]
void showButtonActivated(byte buttonNo) {

char comd[20];
char temp[20];

strcpy(comd,"b");
sprintf(temp, "%01d.bco=63488", buttonNo);
strcat(comd,temp);
Serial.println (comd);
nextion.print(comd);
 
HMICommandEnd();
 
}


However, I have potentially more than 100 buttons to configure each controlling things from lights, heating, mechanical appliances to  audio, etc . The buttons are grouped together according to their logical operation. For example all bedroom lights are grouped together and should appear on the same page. I am using a 3.5in nextion (for now) which seems like it can accommodate about 8 12 or so buttons per page.

I am trying to figure out some method which will enable me to make changes on the available buttons on the nextion screen as well as their grouping without having to re-program the nextion every time since that would need physical access to the display's usb port which will not be easily accessible once mounted on the wall.

The arduino itself is  being controlled remotely via RS485 link. The same link will curry the command to be executed once a button is pressed.


PerryBebbington

Hello Watcher,

I get the impression you are getting the hang of this and don't need much more from me. My heating controller has 5 pages and buttons in one corner to switch between them. My advice to you is to look how I switch pages in the example in this tutorial; the button on the page switches to the desired page directly, it does not tell the Arduino to change pages. On each page under Postinitializationevent is the code that tells the Arduino that the page has changed. Once the Arduino receives the code that the page has changed it then replies with the data appropriate to the page. The reason for doing it this way is to make sure that the new data needed on the page is not sent until after the page has initialised. I had lots of problems with errors in the data whenever I changed pages until I realised it took ages for a page to initialise and that data sent before that might be lost.

Watcher

I decided to design a single page with 12 buttons the description of each changes as the user changes page.
I other words changing a page it will only change the button's description and the actual code each button sends when pressed.


Anyone knows where to find some nice looking "transparent" images/icons to display on these screens?

Things like arrows left,right, bulbs, thermometers etc ?

valbuz

hi.

my problems are with the fonts.....

some text fields on the page.
there are fields labeled by the editor other are labeled by sending commands from sketch.
but they are different on the page!
the fields by command aren't very good readable. the fields by editor are very well.
it's the same font and size for both.

anybody knows such a problem?

thanks
pat


PerryBebbington

#12
Apr 04, 2019, 06:50 pm Last Edit: Apr 04, 2019, 06:55 pm by PerryBebbington
Quote
Anyone knows where to find some nice looking "transparent" images/icons to display on these screens?
Things like arrows left,right, bulbs, thermometers etc ?
When I have needed them I have searched on the internet, there are loads and loads of free downloads if you go looking. Be aware that the Nextion does not support transparent images, although you might need them to construct a background to your needs.

Go Up