Tutorial on how to write code with Nextion and Arduino


In this tutorial, one can find simple tips and hints on how to control a Nextion display with an Arduino. There are examples on:


How to use the following on Nextion with simple examples on where and how they can be applied:


To present all the above in action, we made a single project in which we included all of them.
As a scenario for the project, we choose to read from a text array, stored in the Arduino.
We chose that scenario, because we can have many alternative choices and needs, in the code of both Nextion and Arduino without the need of any external hardware, e.g. sensors.
In this way, we can run the project using only an Arduino and the Nextion Editor, from the debug mode.
In the project, the pages might look the same, but the methods are different. We also use pop-up messages to show the code or comments.

Here is a short video, demonstrating the interface of the project, to take a first idea

To get the .HMI file for Nextion and .ino file for Arduino,
click the button below.



File downloaded 1127 times.

Communication protocol between Arduino and Nextion Display:


The communication between Nextion Display and Arduino is quite simple. There is no need for libraries and complicate commands as Nextion uses a simple and complete instruction set. A library cannot cover and guess all the needs of the projects wide field.
A custom communication protocol is used because of the following advantages:

  • We don’t use any Nextion LCD library
  • Nextion has a protocol to send the ID of different components via Serial, but it is very difficult to use it.
  • The produced code size is small.
  • The communication data length is sort. This causes faster communication between Arduino and Nextion LCD.
  • The protocol can be extended from user by adding his own commands.
  • It is more practical to send a specific command and then from Arduino’s Serial identify the command that is sent and assign it to the function we want, than trying to identify and assign the IDs from a big number of objects to a function, as Nextion and the most libraries do this with the event’s ID protocol.
The only thing that we must do, is to organize the commands that we are going to use with the simplest possible method.
Identifying them with the Arduino code and assigning them to the functions we want.
For this protocol, we want to thank again Vassilis Serasidis for his advises on this.
We use the following Data Format: <#> <len> <cmd> <id>
An example with the group command “Page” is:
  • From Nextion we send in HEX, by writing: < printh 23 02 50 00 >
  • Means: < # 2 P 0 >
  • <#> declares that a command is followed
  • <len> declares the number of bytes that follows (len = 2, <P> is the one Byte and <0> is the other)
  • <cmd> declares the group of commands ( P = page L=Line)
  • <id> declares the ID, to which the command is referring to. (id = 0)
This means that we are in page 0 (we have written in every page’s "preinitialize event" the command printh 23 02 50 xx (where xx is the page id in HEX, 00 for 0, 01 for 1, etc.). We have assigned a function named < first_refresh_page (uint8_t page) > and with a switch case command, we send to each page the data that must updated in first load. A second example is this with the “Line” command group (<#> <len> <cmd> <nextion_var> <cnt>)
  • From Nextion we send in HEX the following: < printh 23 03 4C 04 01 >
  • Means < # 3 L 4 1 >
  • <#> declares that a command is followed
  • <len> declares the number of bytes that will follow (len = 3, <L> is the one Byte <4> and <1>is the other)
  • <cmd> declares the group of commands (P = page L=Line)
  • <nextion_var> is the Number of the variable on Nextion that we want to write
  • <cnt> is the number of the text array Line that we want to store into Nextion's variable
We have assigned the function < sending_text (byte nextion_var, byte cnt) > where we send the last 2 bytes to local variables of the function.


How we read and identifie the commands from Arduino’s Serial port:


Code sample from .ino file

void Nextion_serial_listen() 
{
    if(Nextion.available() > 2){                // Read if more then 2 bytes come (we always send more than 2 <#> <len> <cmd> <id>
        char start_char = Nextion.read();      // Create a local variable (start_char) read and store the first byte on it  
        if(start_char == '#'){                // And when we find the character #
          uint8_t len = Nextion.read();      // Create local variable (len) / read and store the value of the second byte
                                            // <len> is the lenght (number of bytes following) 
          unsigned long tmr_1 = millis();
          boolean cmd_found = true;
            
          while(Nextion.available() < len){ // Waiting for all the bytes that we declare with <len> to arrive              
            if((millis() - tmr_1) > 100){    // Waiting... But not forever...... 
              cmd_found = false;              // tmr_1 a timer to avoid the stack in the while loop if there is not any bytes on Serial
              break;                            
            }                                     
            delay(1);                            // Delay for nothing delete it if you want
          }                                   
                                               
            if(cmd_found == true){            // So..., A command is found (bytes in Serial buffer egual more than len)
              uint8_t cmd = Nextion.read();  // Create local variable (cmd). Read and store the next byte. This is the command group
                                             
              switch (cmd){
                                    
                case 'P': /*or <case 0x50:>  IF 'P' matches, we have the command group "Page". 
                           *The next byte is the page <Id> according to our protocol.
                           *It reads the next byte as a type of <uint8_t variable> and direct send it to:
                           *first_refresh_page() function as parameter. 
                           */
                  first_refresh_page((uint8_t)Nextion.read());  
                  break;
                
                case 'L': 
                /* < case 0x4C: > (0x4c = ‘L’) IF there is a matching with 'L' then we have the command group "Line" according to the protocol
                 * We are waiting 2 more bytes from the <nextion_var> and the <cnt>... (<#> <len> <cmd> <nextion_var> <cnt>)
                 * <nextion_var> is the Number of the variable on Nextion that we want to write
                 * <cnt> is the number of the text array Line that we want to store into Nextion's variable
                 * From Nextion we have sent < printh 23 04 4C 04 xx > where 04, in this example, the <nextion_var> and xx the <cnt>
                 * Same as the above, we are going to read the next 2 bytes as <uint8_t> and direct send them to
                 * < sending_text () > fuction as parameters to the local variables of the function 
                 * < sending_text(byte nextion_var, byte cnt) > that will be created on start up of the Function
                 */

                    sending_text((uint8_t)Nextion.read(),(uint8_t)Nextion.read()); 
                    
                break;
                
              }
            }
        }  
    }    
}

Now, let’s explain what we do in every page.


Page with id=0, or as we have named it, “home”:
Here we have the first page, which loads when Nextion starts. In here, we set Nextion’s baud rate by typing on the Preinitialize Event: < baud=115200 >.
We have added a variable with a global scope, that we have named “curr_page_id”, to keep track of the pages’ id, by storing it into the variable. We use it to return to previous page after the pop_up message screen. We also use it to navigate between the pages (Previous / Next, with the precondition that the pages are in order). For the background, I made a picture with my logo. If the screen is pressed anywhere, then the next page will appear.
To do this, we have putted in the Touch Press Event of the page and all of its components this command: < page pop_up >, where pop_up is the name of a page with a welcome message and some information. Press anywhere on the message screen to go to the page with the first example.


Page with id=1, or as we have named it, “first_example”


In this page, we created five variables, va0, va1, va2, va3, va4, one after the other so their IDs are in order.

We have set the variables type attribute < sta > to STRING from NUMBER and the < txt_maxl > MaxLenth (Maximum Memory Space) to 40 characters.
In variables va0, va1, va2, va3, we store the text that is going to be printed on the four lines of the screen.
Variable va4, is used to store the next line that we “asked” Arduino for, by pressing the up (b0) or down (b1) button.

The va4 is going to replace the va0 or the va3, according to which button is pressed.
These four variables, va0, va1, va2, va3, are the variables that are printed on the screen with this order:

Display Order When b1 is pressed When b0 is pressed
va0 = first line va0.txt=va1.txt va3.txt=va2.txt
va1 = second line va1.txt=va2.txt va2.txt=va1.txt
va2 = third line va2.txt=va3.txt va1.txt=va0.txt
va3 = fourth line va3.txt=va4.txt va0.txt=va4.txt

Page with id=2, or as we have named it, “second_example”:


In this page, we created 20 variables (va0, va1...va19) one after the other so their IDs would be in order. We use them to store all of the lines of text.
The first thing we created on this page, was those variables, so their IDs would start from 1 and end at 20.
We have setted again the variables type attribute < sta > to STRING from NUMBER and the < txt_maxl > MaxLenth (Maximum Memory Space) to 40 characters.
In < va0 > we store the text of the first position of the text array < text[0] >. In < va1 > we store the text of the second position of the text array < text[1] > and so on...
It will end when we reach the ARRAY_ROWS value.
The code will adapt automatically if the lines of the text (ARRAY_ROWS) are less than twenty and is going to use as many lines as the ARRAY_ROWS is.
It will NOT adapt if there are more than twenty lines. In this case, we have to create more variables.
Nextion has more space for variables than Arduino. For that reason, most times it is better to store the text on Nextion and doing all the reading and processing from there, letting Arduino and the Serial available for other tasks of the project. The time to transfer the text array is very little, at the scale of milliseconds.

In addition, Nextion’s MCU has faster clock speed, of 48MHz on Basic, 108MHz on Enhanced over 3.5” and 200MHz on Intelligent, whereas the Arduino’s Nano and UNO have a clock speed of 16MHz. Thus, we should prefer to perform most of the tasks on Nextion rather than Arduino.

We have added a “Hotspot” component, from the toolbox, to store the code with the four < xstr > commands, that print on the display the four lines that we want to.

            

sys0=22
xstr 15,sys0,390,30,0,BLACK,34784,0,1,1,b[cnt.val].txt
xstr 15,sys0+30,390,30,0,BLACK,34784,0,1,1,b[cnt.val+1].txt
xstr 15,sys0+60,390,30,0,BLUE,34784,0,1,1,b[cnt.val+2].txt
xstr 15,sys0+90,390,30,0,BLUE,34784,0,1,1,b[cnt.val+3].txt

The counter first has the value 1. With the first < xstr >, we are printing the text value of the component with ID = cnt.val = 1. Component va0.
With the second < xstr >, we are printing the text value of the component with ID = (cnt.val + 1) = 2. Component va1. The third < xstr >, we print the b[cnt.val + 2] = b[3]. Component va2. And at the end, we print the b[cnt.val+3] = b[4]. Component va3

AS YOU NOTE, we can use the b[.id] component array, which takes component .id as index, instead of < text > or va0.txt or the objname.txt of the < string > argument in < xstr >.

It is also important to NOTE, that in the component array, we can put the variables and equations with numbers and the result of those, will be the number of that specific argument.
e.g.: If cnt.val=1, then b[cnt.val+3] = b[1+3] = b[4].
By pressing the down button(b1), we add to cnt.val, 1(cnt.val+1).
By pressing the up button(b0), we subtract by 1 the cnt.val (cnt.val-1).
With the Hotspot’s Press Event, we print four lines, starting with the one that has the same number as the cnt.val.

A slider has also been added that changes the value of the counter accordingly and by clicking the Hotspot < click n0,1 >, prints the four lines again with the new cnt.val


Page with id=3, or as we have named it, “self_scrl”:


On this page, we chose to send the lines of text one by one, directly to component g1, which is a Scrolling text box on Nextion. We have set maximum amount of characters, < txt_maxl >, to 2000
When this page loads, Arduino identifies it using our custom protocol, which can be found below, and sends the lines of text with a new line character, < \r >, at the end.

void send_text_to_g1()
{
 char temp_data[50];
 
  for(int i = 0; i < ARRAY_ROWS; i++){
    sprintf(temp_data, "g1.txt+=\"%s\\r\"", text[i]);
    Nextion.print(temp_data);
    NextionEndCommand();
  }
}
            

Component g1 now has all the text stored in it. Display and Scrolling functions are executed through the default operations of Nextion’s Scrolling text. From g1 attribute menu, we set the < en > attribute to 1, which is going to start the scrolling of the text.
With the use of a timer, we let the g1 component to self scroll for ONLY five seconds from the load of the page, to fill the display with the first five lines of text.
We stop the self scrolling, by writing in the timer’s event:
g1.en=0 //Disable the self scrolling (stop the moving of the text)
tm0.en=0 //Disable the timer, because if we don’t disable it, the timer is going to run the event every five seconds

Now, the scrolling function will start when we hold down the b1 (down) or b0 (up) buttons.
In b1 Press Event, we enable the g1

b1 Press Event
g1.dir=3 //Direction = Down to Up
g1.en=1 //Enable the scrolling
b1 Release Event
g1.en=0 //Disable scrolling
b0 Press Event
g1.dir=2 //Direction = Up to Down
g1.en=1 //Enable the scrolling
b0 Release Event
g1.en=0 //Disable scrolling

More details on Page with ID = 1, or as we have named it, “first_example”:


• Each time the page loads, we send a command to Arduino through the preinitialize event of the page, to let the Arduino know on what page we are on.
For this page the command is: < 23 02 50 01 > in hex.
This command uses a specific protocol of our own. Its function on how we organize our commands and make Arduino identify them, will be explained later at its own paragraph.
At the preinitialize event of the page, we write the following in hex: < printh 23 02 50 01 >
< printh > is one of the few commands that parameter uses space char 0x20
< printh 23 02 50 01 > send four bytes: value < #2P1 > hex: 0x23 0x02 0x50 0x01
• Arduino in its turn will send the data that we have specified through the switch case command in the Arduino code for this page which are the following:

Code sample from .ino file

                 Nextion.print("array_rows.val="); // Sending to Nextion the value of ARRAY_ROWS, that represent how many Lines is the array  
                 Nextion.print(ARRAY_ROWS); // We update the value of array_rows variable on Nextion, to be equal to ARRAY_ROWS   
                 NextionEndCommand();   
                      
                 Nextion.print("n1.val=array_rows.val"); //Set the value of n1 numeric component, (no visible)  
                 NextionEndCommand();       // to be equal to the value of array_rows variables on Nextion
                  
                 Nextion.print("t1.txt=\"");         
                 Nextion.println("Welcome to message page"); //We send & print a message to the t1 textbox
                 Nextion.print("there are ");   
                 Nextion.print(ARRAY_ROWS);     
                 Nextion.println(" NEW Message");      
                 Nextion.print("TOUCH HERE TO READ");  
                 Nextion.print("\"");  
                 NextionEndCommand();  
                  
                 sending_text(0,0);           // to fuction <sending_text (byte nextion_var, byte cnt)> send 2 values one for each variable  
                 sending_text(1,1);          // this is for sending and store the first 4 Lines on Nextion’s four first variables   
                 sending_text(2,2);         // Nextion variables: va0, va1, va2, va3  
                 sending_text(3,3);       // <sending_text(3,3);> this is going to store to the va3 on Nextion the array line 3
                              
                 Nextion.print("cnt.val=3");    // After first 4 lines printed on Nextion, the <cnt> value is 3 and we update that on Nextion  
                 NextionEndCommand();           // Remember that 4th line or place called with the number 3 (0,1,2,3,...19)

            

The first four lines have been stored to the vals and a message on the screen has also been sent and printed through the t1 textbox, which informs us for new message and the number of them by sending the value of ARRAY_ROWS.
The code will adapt automatically for maximum array Lines (places) as we define with ARRAY_ROWS at Arduino code and array_rows.val at Nextion to set all the code in Nextion for the max value of lines that are going to be showed.
Example: <cnt>, <h0.maxval> etc.

Textbox t1 is setted to multiline through its attribute and as you can see, the < print > and < println > are working fine to change into new line, because < println > sends a carriage return character (ASCII 13, or '\r') and a newline character (ASCII 10, or '\n') at the end of the text.

            //We get the same message result with the following:
                       
             Nextion.print("t1.txt=\"Welcome to message page\\rthere are ");
             Nextion.print(ARRAY_ROWS);
             Nextion.print(" NEW Messages\\rTOUCH HERE TO READ\"");
             NextionEndCommand();
        

A prompt “TOUCH HERE TO READ” on t1 box. When you press on t1, which covers all of the display, the touch event is going to print the first four lines, from the values we have sented, doing the following:

xstr 15,22,390,30,0,BLACK,34784,0,1,1,va0.txt
xstr 15,22+30,390,30,0,BLACK,334784,0,1,1,va1.txt
xstr 15,22+60,390,30,0,BLUE,34784,0,1,1,va2.txt
xstr 15,22+90,390,30,0,BLUE,34784,0,1,1,va3.txt

We are using the < xstr > command that Prints text on the Nextion device using defined area for text rendering.
Usage: xstr <x>,<y>,<w>,<h>,<font>,<pco>,<bco>,<xcen>,<ycen>,<sta>,<text>
We start to print with < xstr >, at 15 < x > and 22 < y > coordinates for the first line, and for the other three, we add 30 pixels to < y > coordinate from the last line’s < y > coordinate

By pressing button b1, we print to the serial in hex form: < printh 23 03 4c 04 > and we also print one byte of the <cnt> variable with: < prints cnt.val,1 >.
prints <attr>,<length>

  • <attr> is either component attribute, variable or Constant

  • <length> is either 0 (all) or a number to limit the bytes to send

The result of < printh 23 03 4c 04 > and < prints cnt.val,1 > is the value: < #3L4Y > (where there is a “Y”, it is the value of the cnt variable each time). In hex: 0x23 0x02 0x50 0x01
<cnt> is a counter egual to the number of the text array Line that we want to store into the Nextion's variable < nextion_var > for this example < va4 >.<br> According to our protocol, we have the command group “Line”(<#> <len> <cmd> <nextion_var> <cnt>). We send the two bytes, <nextion_var> and <cnt> to the void sending_text(byte cnt, byte nextion_var).
We are now waiting for the Arduino to send the array line that is equal to cnt value and store it to va4.
With the Release Event of b1 we change the values of the variables according to the above table at the introduction of this page(first_example) and we print them again.
The result is that we print a new line at the bottom and the other 3 lines go up a level.

At the release event of b2, the opposite things happen.

Press Event b1
n0.val=array_rows.val-1
if(cnt.val<n0.val)
{
cnt.val++
printh 23 03 4c 04
prints cnt.val,1
}
tm0.en=1
Release Event b1
if(cnt.val<n0.val)
{
va0.txt=va1.txt
va1.txt=va2.txt
va2.txt=va3.txt
va3.txt=va4.txt
xstr 15,22,390,30,0,BLUE,34784,0,1,1,va0.txt
xstr 15,22+30,390,30,0,BLUE,34784,0,1,1,va1.txt
xstr 15,22+60,390,30,0,BLUE,34784,0,1,1,va2.txt
xstr 15,22+90,390,30,0,BLUE,34784,0,1,1,va3.txt
}else if(cnt.val==n0.val&&va5.val==0)
{
va0.txt=va1.txt
va1.txt=va2.txt
va2.txt=va3.txt
va3.txt=va4.txt
xstr 15,22,390,30,0,BLUE,34784,0,1,1,va0.txt
xstr 15,22+30,390,30,0,BLUE,34784,0,1,1,va1.txt
xstr 15,22+60,390,30,0,BLUE,34784,0,1,1,va2.txt
xstr 15,22+90,390,30,0,BLUE,34784,0,1,1,va3.txt
va5.val=1 // for run one time the loop if cnt<n0
}
tm0.en=0

Code Sample From .ino File

            /* < case 0x4C: > (0x4c = ‘L’) IF there is a matching with 'L' then we have the command group "Line" according to the protocol
                             * We are waiting 2 more bytes from the <nextion_var> and the <cnt>... (<#> <len> <cmd> <nextion_var> <cnt>)
                             * <nextion_var> is the Number of the variable on Nextion that we want to write
                             * <cnt> is the number of the text array Line that we want to store into Nextion's variable
                             * From Nextion we have sent < printh 23 04 4C 04 xx > where 04, in this example, the <nextion_var> and xx the <cnt>
                             * Same as the above, we are going to read the next 2 bytes as <uint8_t> and direct send them to
                             * < sending_text () > function as parameters to the local variables of the function
                             * < sending_text(byte nextion_var, byte cnt) > that will be created on startup of the Function
                             */


            void sending_text(byte cnt, byte nextion_var){

                    /*From the Function < Nextion_serial_listen () > and <case 'L'> we have send the 2 bytes <nextion_var> and <cnt>
                     * directly to this Function and run the function with the command <sending_text((uint8_t)Nextion.read(),(uint8_t)Nextion.read());> .
                     * In this function we create 2 Byte local variables  and we assign the read bytes from case 'L' as their values
                     */
                    
                    /* From Nextion each time we press the <up> or <down> scrolling button we raise the variable on Nextion <cnt> by one cnt++ or decrease it by one cnt--
                     *In this function we want to store the line from the text array that we ask with <cnt> to the variable va4 on Nextion
                     * va4 is for this example we can write on every var that we will sent throw the <nextion_var>
                     * the command for Nextion : va4.txt="text from the <cnt> Line of char text text[cnt]"
                     */
                if(cnt < ARRAY_ROWS){
               
                     Nextion.print("va");
                     Nextion.print(nextion_var);
                     Nextion.print(".txt=\"");
                     Nextion.print(text[cnt]);
                     Nextion.print("\"");
                     NextionEndCommand();
                }
            }

        

Code Sample From .HMI File

Press Event b0
sys0=cnt.val-4
if(sys0>=0)
{
cnt.val--
printh 23 03 4c 04
prints sys0,1
}
tm1.en=1
Release Event b0
if(sys0>=0)
{
va3.txt=va2.txt
va2.txt=va1.txt
va1.txt=va0.txt
va0.txt=va4.txt
xstr 15,22,390,30,0,BLACK,34784,0,1,1,va0.txt
xstr 15,22+30,390,30,0,BLACK,34784,0,1,1,va1.txt
xstr 15,22+60,390,30,0,BLACK,34784,0,1,1,va2.txt
xstr 15,22+90,390,30,0,BLACK,34784,0,1,1,va3.txt
va5.val=0
}
tm1.en=0


< tm0 > is a timer with a setted time delay 300ms. It is enabled through < b1 > press event and disabled by < b1 > release event. Every 300ms, it triggers the < click > command. In the timer’s event, we write: clickb1,0 click b1,1
<< click cid >, event> >
<cid> is component’s .id or .objname attribute of component to refresh
<event> 1 to trigger Press Event, 0 to trigger Release Event.
The result of this is that when we hold down the < b1 > button, the text will scroll down continusly.
The same thing happens with < b0 >, only the text scrolls up continusly by < tm1 >.


More details on Page with ID = 2, or as we have named it, “second_example”:


Each time the page loads, we send a command to Arduino through the preinitialize event of the page, to let the Arduino know on what page we are on.
For this page the command is: < 23 02 50 02 > in hex.
This command uses a specific protocol of our own. Its function on how we organize our commands and make Arduino identify them, will be explained later at its own paragraph.
At the preinitialize event of the page, we write the following in hex: < printh 23 02 50 02 >
< printh > is one of the few commands that parameter uses space char 0x20
< printh 23 02 50 02 > send four bytes: value < #2P1> hex: 0x23 0x02 0x50 0x02


Arduino in its turn will send the data that we have specified through the switch case command in the Arduino code for this page which are the following:

            case0x02:
                       
                Nextion.print("array_rows.val="); // Sending to Nextion the value of ARRAY_ROWS, that represent how many Lines is the array
                Nextion.print(ARRAY_ROWS);         
                NextionEndCommand();
                       
                Nextion.print("n0.val="); // Sending to Nextion the value of n0.val a numeric component that is hidden and used as variable on nextions code
                Nextion.print(ARRAY_ROWS - 3);         
                NextionEndCommand();
                       
                Nextion.print("h0.maxval="); // setting the max value that Slider on nextion can take
                Nextion.print(ARRAY_ROWS - 4);         
                NextionEndCommand();
                       
                Nextion.print("h0.val=h0.maxval"); //  setting the value of the slider to its max value ( pointer on the top)    
                NextionEndCommand();           
                       
                save_text_to_variables_example2();
                      
                break;


            void save_text_to_variables_example2(){
              
              char temp_data[50];
              
              for(int i = 0; i < ARRAY_ROWS; i++){
                sprintf(temp_data, "va%u.txt=\"%s\"", i, text[i]);
                Nextion.print(temp_data);
                NextionEndCommand();
                delay(10);                           // Give some time to Nextion to read from Serial Buffer and Avoid buffer overflow
                
              }
            } 

            

That was a sample of the Arduino code. From now on, Arduino isn’t necessary. All of the following work with only the code on the Nextion

At the preinitialize event of the page, we write the following:
printh 23 02 50 02
vis n0,0
vis t5,0
vis m0,0
//With <vis> we make the component visible (1) or invisible (0)
//Syntax: vis <component id or name>, <1 or 0>

p[0].b[7].val=dp
//p[0].b[7].val is the clobal var curr_page_id on page0
//to read or to write in a Global variable you must refer to it
//with the arrays [ ] for
//p[pageindex].b[component.id].attribute // global scope

n3.val=p[0].b[7].val
// we print the id of the current page id at n3

When b1 is pressed, b1 Press Event
//n0.val=array_rows-3 sented from Arduino on first page refresh
if(cnt.val<n0.val)
{
cnt.val++
covx cnt.val,t3.txt,0,0 // FOR DEBUG
//We used the <covx> as an example to show how it works,
//although we could use a numeric component to print
//the <cnt.val> on the display

h0.val=n0.val-cnt.val
//Slider's <maxval> is at the top, but we need the <minval> on top,
//as <cnt.val> must be 0 on top and max value at bottom
//In order to do this, we subtract the <cnt.val> from <n0.val>,
//which is the max value that <cnt.val> can get.
//With this way, we reverse the <maxval> with <minval>

click m0,1 // t5 comp is no vis and used as temp var to store the result of
// covx h0.val,t5.txt,0,0 and then + to t4.val

covx h0.val,t5.txt,0,0
//We convert the <h0.val>, from numeric to text and store it
//at the t5 textbox, which we made invisible from the Preinitialize
//event of the page <vis t5,0> to add the value of <t5.txt>,
//at the value of <t4.txt>

if(h0.val>=10)
{
//we use this < if > command to print a "0" before the numbers with one digit
t4.txt="slider's Value"+""+"h0.val== "+t5.txt
}else if(h0.val<10&&h0.val>-1)
{
t4.txt="slider's Value"+""+"h0.val== 0"+t5.txt
}
//This is also an example on how to send text at a text box,
//with commands from Nextion using the return character, <"">,
//so as to change line. NOTE, the textbox must be setted
//to multiline, from the <txt> attribute.
//-----NOTE------
//When sending from Arduino to a textbox and we want to
//print at a new line, we must send "" EXAMPLE:
//Nextion.print("t1.txt=the first line ++second line ");
}
When b0 is pressed, b0 Press Event
//n0.val=array_rows-3 from Arduino on first page refresh
//For more comments, see "b1" button, 'Touch Press Event'

if(cnt.val>1)
{
cnt.val--
covx cnt.val,t3.txt,0,0 // FOR DEBUG
h0.val=n0.val-cnt.val
// t5 comp is no vis
covx h0.val,t5.txt,0,0
if(h0.val>=10)
{
//we use this < if > command to print a "0" before the numbers with one digit
// In < covx > command, when length is fixed and value is less, leading zeros will be added.
//In this example we didn't specify the length of < covx >. In that way, we get as many
//digits as there are on h0. left this way as an example

t4.txt="slider's Value"+""+"h0.val== "+t5.txt
}else if(h0.val<10&&h0.val>-1)
{
t4.txt="slider's Value"+""+"h0.val== 0"+t5.txt
}
click m0,1
}
Slider’s Touch Press Event
cnt.val=n0.val-h0.val
//n0.val=array_rows-3 from Arduino on first page refresh
covx cnt.val,t3.txt,0,0 // FOR DEBUG
click m0,1
// t5 comp is no vis and used as temp var to store the result of
// covx h0.val,t5.txt,0,0 and then + to t4.val

covx h0.val,t5.txt,0,0
if(h0.val<=10)
{
//we use this > if < command to print a "0" before the numbers with one digit
// In >covx < command, when length is fixed and value is less, leading zeros will be added.
//In this example we didn't specify the length of > covx <. In that way, we get as many
//digits as there are on h0. left this way as an example

t4.txt="slider's Value"+"\r "+"h0.val== "+t5.txt
}else if(h0.val>10&&h0.val<-1)
{
t4.txt="slider's Value"+"\r "+"h0.val== 0"+t5.txt
}
Slider’s Touch Release Event
cnt.val=n0.val-h0.val
//n0.val=array_rows-3 from Arduino on first page refresh
covx cnt.val,t3.txt,0,0 // FOR DEBUG
// t5 comp is no vis and used as temp var to store the result of
// covx h0.val,t5.txt,0,0 and then + to t4.val

covx h0.val,t5.txt,0,0
if(h0.val>=10)
{
//we use this < if > command to print a "0" before the numbers with one digit
// In <covx > command, when length is fixed and value is less, leading zeros will be added.
//In this example we didn't specify the length of < covx >. In that way, we get as many
//digits as there are on h0. left this way as an example

t4.txt="slider's Value"+"\r"+"h0.val== "+t5.txt
}else if(h0.val<10&&h0.val>-1)
{
t4.txt="slider's Value"+"\r"+"h0.val==0"+t5.txt
}
Slider’s Touch Move
cnt.val=n0.val-h0.val
//n0.val=array_rows-3 from Arduino on first page refresh
covx cnt.val,t3.txt,0,0 // FOR DEBUG
// t5 comp is no vis and used as temp var to store the result of
// covx h0.val,t5.txt,0,0 and then + to t4.val

covx h0.val,t5.txt,0,0
if(h0.val>=10)
{
//we use this < if > command to print a "0" before the numbers with one digit
// In command, when length is fixed and value is less, leading zeros will be added.
//In this example we didn't specify the length of < covx >. In that way, we get as many
//digits as there are on h0. left this way as an example

t4.txt="slider's Value"+"\r"+"h0.val== "+t5.txt
}else if(h0.val<10&&h0.val>-1)
{
t4.txt="slider's Value"+"\r"+"h0.val== 0"+t5.txt
}
click m0,1

How to make components visible or invisible using <vis> command:


With < vis > command we can hide or show a specific component on the current page.
• show will refresh component and bring it to the forefront layer.
• hide will remove component visually, touch events will be disabled.
When the object is hidden, we can get its value, or we can change it. Example: read or write a text from a textbox
Syntax: < vis < component ID or name >, < state > >
• < state > write 0 to make component invisible or 1 to make it visible
• In page < first_example >, we make component n0 invisible, by writing:< vis n0,0 > with objectname or < vis 13,0 > with component’s ID
• By writing < vis 255,0 >, we make every component in the current page invisible
We give the command from the "preinitialize event" of the page that the component belongs by writing: < vis n0,0 >
From Arduino, we write < Serial.print(“vis n0,0”); > and of course the 3 bytes for the end command < Serial.print("\xFF\xFF\xFF"); >


How to create a variable, change it to global scope and use it across different pages:


The Variable component is a non-visual component and is located below the Design Canvas. Variables are either 32-bit signed numeric or string content.
To create a variable, go to the “Toolbox” section and click on the “(X) Variable”. When pressed, a variable is going to be added.
From variable’s “Attribute”, change the < vscope > from local to global. “Local” is the default option when created.
From the < sta >, choose Numeric or String. Depends on how someone wants to use it.

When a variable is global, it can be accessed not only while the page they are in is currently loaded, but also while different pages are loaded.
We can access the variable with two ways:

1. By giving the name of the page and the component’s < objectname >. Example: < home.va0.val >
See the example at the < Preinitialize Event > of page < first_example > of this guide, where we use a variable created on page < home > named < curr_page_id>
< home.curr_page_id.val=dp > We set the value of < curr_page_id > variable to be equal to with < dp > (< dp > is a system variable that returns the current page id).

2. By using the b[.id] component array. Example: < p[.id].b[.id].val> .
The above example for the page < first_example > gets the form < p[0].b[7].val=dp >.
We prefer to use the second method, due to we can change the name of the page and objects freely. Be careful when changing page order, as the page ID will change too.


How to navigate between pages using < dp >, a Nextion’s system variable:


As you can see above, < dp > is a system variable that returns the current page ID when read the variable. E.g.: n0.val=dp.
And change page to value specified. E.g.: dp=1 // loads the page with ID=1.
In our example, we use the global scope variable < curr_page_id > to store the current page id.
With the navigation buttons, if we want to go to the previous page, we subtract one from the < curr_page_id >, by writing:
< page p[0].b[7].val-1 > or < dp= p[0].b[7].val-1 >.
To go to the next page, we add one to the < curr_page_id >, by writing: < page p[0].b[7].val+1 > or < dp=p[0].b[7].val+1 >.
This is very useful when we want to return to the previous page after using a pop-up message.


How to make a useful pop-up message on Nextion:


To make a pop-up, we use a page with a transparent background, by setting the < sta > attribute of the page to “0” or “no background”, so when this page loads, we are going to have as a background the previous loaded page.
We can make a textbox, customize as we like and add text either from Arduino or from a local variable on Nextion. We could also add the text to the text attribute of the textbox component.

To leave from the message page, we can set at the Press Event of every object on the page AND on the page itself, to load the previous page with the following command:

< page p[0].b[7].val > or < dp= p[0].b[7].val > Thus, wherever we press on the page, we are going to go to the previous page.
We could also use a timer, that in its event we are going to run the same commands, after the setted time has passed. Then the pop-up message will disappear.
The timer also has to be setted to enabled, through its attribute < en > and it will start counting as soon as the pop_up page loads
NOTE: When the pop_up page loads, we don’t update the curr_page_id variable, as we do with the other pages.
In this way, we can go from the message screen to the previous loaded page, as the pop_up can be called from different pages.

To avoid the need of a page for every message, we created a global scope variable at the “home” page, with < sta=String > and < txt_maxl=200 >.
In this variable, we are storing the text we want to display on the pop_up message.
If from any object or any event on any page we want to display a message, we write the desired text to the global pop_text variable.
After that, we call the page pop_up.
E.g.:< home.pop_text.txt=”Test Line 1\rTest Line 2” > & < page pop_up >
NOTE: \r for new line

In the pop_up page Preinitialize Event the text on t0 gets the text from the global variable < pop_text >, by writing:
< t0.txt=home.pop_text.txt >.


How to use < sprintf > command:


A very useful command is the <sprintf>. This command will construct a string from different type of variables and will store it
in a char array in our case <buffer>. We must declare the length of the array to be long enough to hold all the characters.
With sprintf we can include variables within a text using format specifiers with the prefix < % >, format specifiers are replaced
by the values specified in subsequent additional arguments.
sprint(char array to store value, "<TEXT TO PRINT %[format specifier]NEXT TEXT%[format specifier]",<name of 1 variable>,<name of 2 variable>)
Format specifier table from: https://arduinobasics.blogspot.com/2019/05/sprintf-function.html

%d = signed integer %f = floating point number
%s = string %.1f = float to 1 decimal place
%c = character %.3f = float to 3 decimal places
%e = scientific notation %g = shortest representation of %e or %f
%u = unsigned integer %o = unsigned octal
%x = unsigned hex (lowercase) %X = unsigned hex (uppercase)
%hd = short int %ld = long int
%lld = long long int  

More for sprintf-function to: http://www.cplusplus.com/reference/cstdio/sprintf/

How to change components’ attributes at Nextion from Arduino:


For every component on Nextion, we can chance only attributes that are showed with GREEN color when Nextion is “running”
with the following prototype <component name>.<attribute>=<value> . If attribute is text, the value must be inside <" "> quotes.
Supposing we want to send to component t3 the text <HELLO> the command for Nextion is < t3.txt="HELLO">, from Arduino, we write < Serial.print("t3.txt=\"HELLO\"")>;
When we type <\"> means that <"> is a character and it's going to print it over serial as character. Else <"> is a STRUCTURE.
To change the font color t3, we write on Nextion: < t3.pco=BLUE > or < t3.pco=<31> >
From Arduino:< Serial.print(“t3.pco=BLUE”); > or < Serial.print(“t3.pco=31”); >\

TIP: The exact names of the attributes and the values they can get, can be found on Nextion Editor at the attribute menu of any object.


How to use the return character < “\r” > on text boxes for new line :


In Nextion with the < \r > creates 2 bytes 0x0D 0x0A the first is the return character (ASCII 13, or '\r') and the second is the newline character (ASCII 10, or '\n').
We must send to Nextion the 2 bytes < \r > of the backslash (\) and character (r) to send the backslash char (\) we must add a (\) in front, for the escape character, due to we want to print the second (\) as character
E.g.: < Serial.print("t1.txt=\"Text Line 1\\rText Line2\”"); >
When we are at Nextion we must include the < \r > inside " ", result: < "\r" >.
When it is inside the text there is no need for extra "". The quote marks of the text are enough.
Example 1 < t1.txt="LINE1\rLINE2" >
Example 2 < t1.txt="LINE1\rLINE2"+"\r"+t3.txt> we add a new Line with the text of t3 component.


How to initialize Nextion’s Serial baud rate:


NEXTION MUST HAVE THE SAME BAUD RATE WITH ARDUINO. For this we write at first page to the preinitialize event the command <baud=115200> NOTE "bauds" will change the default baud rate off 9600 until it changed again <bauds=115200>.On the other hand, <baud> will change the rate until next start-up. From Arduino: <Serial.print(“baud=115200”);>
But first, we must have a Serial connection between Arduino and Nextion. This means that we have the same baud rate on both.

Second step is to change the baud rate of Nextion and then change the Serial baud rate on Arduino.


How to use the timer variable, a non-visible component:


After we select the timer from the toolbox, as this is a non-visual component, it will be added below the Design Canvas.
From timer’s event we can run specific code or commands in sequentially periods of the setted time.
This period of time can be setted by the < tim > attribute in milliseconds. We must start it by setting the < en > attribute to 1.
If we want the timer’s event not to repeat, we write at the end of all the commands of the event: < tm0.en=0 >. This disables the timer.
When timer is setted to < en=1 > from the attribute menu (when building the page), the timer will start and run with the load of the page.

To start the timer from a different time stamp, we have to set < en=0 > from the attribute menu (Nextion Editor) and enable it from an object’s Event with: < tm0.en=1 >

Examples on timers can be found on pages with ID=1, ID=3.


How to add a numeric variable inside a text (same with Arduino):


From Nextion: We must convert the numeric to text with <covx>. For this, we must create a textbox (make it visible or not. It is up to you) to store the result of the <covx>
If the numeric value is the n0 and the t0 is the place we chose to store the result of the < covx >, then we write:
< covx n0.val,t0.txt,0,0>.
If t1 is the textbox we want to add the text and the result of the < covx >, < t1.txt="slider's Value"+"\r"+"h0.val== "+t0.txt >

In <covx > command, when length is fixed and value is less, leading zeros will be added.