Start a new topic

» Nextion TTL Serial


So here is an animation of how a byte transfers via N81 serial (made with v0.46)

Note that TTL is HIGH on idle (rs232c is LOW on idle).  Animation is approx 1 bps. 

Valid Nextion baud rates are: 2400, 4800, 9600, 19200, 38400, 57600 and 115200.

Nextion has a 1024 bit buffer which works out to a max of 128 bytes before overload.
When Nextion is in command mode, Nextion will only start processing command
once the three terminating 0xFF bytes have been received.  Nextion sends out any
Return Data after processing has completed.  This can range from near immediate,
to 3ms, to even longer depending on what the command was requested to accomplish.

Nextion commands are text based.  All commands are terminated with thee 0xFF bytes.

Before we get into how to send a command over serial in code,

   the more important question is What to send over serial.

There are two main types that need to be dealt with

   - Text data belonging to a Component's .txt attribute

   - Numeric data of Component attributes or system variables

For text data belonging to a Component's .txt attribute

   we need to know what component, and is that component global.

    - If the component is local, take the .objname in the attribute.

       for Text Component t0   t0.txt="Hello"ÿÿÿ needs to be sent.

       for Button Component b1   b1.txt="Hello"ÿÿÿ

       for Variable va0.txt   then va0.txt="Hello"ÿÿÿ

    - every .txt attribute is text data and needs double quotes " around its data.

For numeric data belonging to other Component attributes

    we again need to know which Component and if it is global

    - for local component numeric attributes, numbers need to be in text format.

      to set a Number Component n0 value to 123   n0.val=123ÿÿÿ

      to set a Text Component t0 background Color .bco to 32   t0.bco=32ÿÿÿ

      to set a Waveform grid height to 50   s0.gdh=50ÿÿÿ

So what if the Component is global?  what pagename is it on?

       for b1 on page main then   main.b1.txt="Hello"ÿÿÿ

       for t0 on page page3     page3.t0.txt="Hello"ÿÿÿ

       for n0 on page page2     page2.n0.val=234ÿÿÿ

       for va4 on page page0   page0.va4.txt="Hello"ÿÿÿ

    adding the pagename before the global component means it can be  accessed

       from any page should the HMI user be on a different page.

    Without the pagename, the component is only for the current page and  if the HMI

       user is on a different page - it will try to update the wrong component.

Which Component attributes can be updated over serial?

    In the Nextion Editor, if the attribute name is in the color green ... then yes.

    If it is not in green, well then no.  It can be read, but not updated.

So how do we read a Component's attribute?  Use the get command.

    get t0.txtÿÿÿ

    get main.va0.valÿÿÿ

    get p0.hÿÿÿ

    get page0.p0.wÿÿÿ

    get dpÿÿÿ

    get dimÿÿÿ

Commands in the Nextion Instruction Set

   - these also require to be terminated with three 0xFF bytes.

   - one space between command and its parameters, no spaces between parameters.

   - numeric values need to be in text format

   - text data needs to surround the text data with double quotes "

   click m0,1ÿÿÿ

   cirs 100,100,40ÿÿÿ

   xstr 0,0,100,30,1,RED,BLACK,1,1,1,"China"ÿÿÿ 

   page page0ÿÿÿ


Another advanced point to mention is the page index and component arrays

    t0 with .id of 7 on page 3 (number is left of pagename)

       this can be alternatively accessed with p[3].b[7]

       get p[3].b[7].txtÿÿÿ

       vis p[3].b[7],1ÿÿÿ

       click p[3].b[7],0ÿÿÿ


    likewise n0 with .id of 2 on page 5 (number is left of pagename)

       this can be alternatively accessed with p[5].b[2]

       get p[5].b[2].valÿÿÿ

       vis p[5].b[2],1ÿÿÿ

       click p[5].b[2],0ÿÿÿ


     if it is not global but just local the p[5]. is not needed and b[2] is enough

So before you push out text commands, know what needs to be pushed over serial.

♪♫♪ ... Now Push It ... Push It Real Good ... ♪♫♪

Now how to push bytes out over serial is another story ...

This depends heavily on your Programming Language and your Compiler.

   and more so on what Library you use for serial communications.

It isn't just enough to say use Serial2.print("page page0ÿÿÿ");

This may work for an Arduino C++ with HardwareSerial on RX2/TX2,

But the embedded world is much much larger than Arduino.

Most microcontrollers have at least one Hardware UART, many have more.

And when hardware UARTs aren't available, then there is bit-banging the

data over serial by Software.  On a lower level, the pins used for serial

need to be set, interrupts or polling, buffer sizes, and ... and ... and ...

This is very much dependent on which microprocessor you are using and

is going to be found in your microcontrollers documentation.

Once all the low level stuff has been taken care of, many write out a library

to simplify their programs - this is very dependent upon the programmer.

Did they use write.usart(); or uart1_write(); or Serial.print, or other.

So to make this story short:  There just isn't a means to post how-to-serial

that would be correct across 10,000 MCUs, 100 programming languages,

multiple compilers, and who knows how many serial library implementations.

Each having variations and specific requirements per microprocessor.

This stage requires the users to dig in to their microprocessor documentation,

Their compiler documentation for the programming language chosen, and

read the documentation of the specific serial library being used (often found inside

the code).  But there is a short cut to be had.  The compiler and microprocessor

forums will surely know amongst their thousands of users, where a good serial

library is and how to use it with ample of examples available.

Thanks Patrick, nice thread.

When this hit the forum last night, I got to thinking.....

So just how robust is the Arduino Serial.print() function and how good is Nextions serial based input to the interpreter.

Turns out they're almost bomb proof. I wrote some simple code to do a little testing, and many of you will be quite surprised at the results. I pushed to the MAX and couldn't break it! I'm going to do a short video clip and a write up, and will start a new thread shortly. 

Stay tuned....:)

[Update:] Steve's thread is located here:

2 people like this

Let's consider a few things about Hardware UART modules.

 ... and since we don't have the Nextion source to examine

we make a few assumptions based on good practices (assumed)

A Hardware UART module should be able to receive a byte independent by itself.

One of the first steps in configuring a hardware uart is setting the registers with all the information needed: data bits per frame, parity, length of the stop bit, baud, so right from the falling edge of the start bit, the timing is already known.

Most take measures of averaging by oversampling to ensure against line noise.  This is also needed to handle the variation between the two crystals used by each end of the communications line so ensure some tolerance is built in. If we dig into some data sheets, we see that there is a variance error rate that needs to be addressed when the baud rate isn't an evenly divisible into the mcu's clock. So, indeed this variance should be already taken into consideration by any mature microprocessor manufacturer.

So when receiving the bits of a byte, it isn't until the entire byte has been loaded into the register that the interrupt occurs to notify the MCU that the byte is now available in the RX register.  We know how many bits were to be coming - it is part of the agreed upon protocol to connect, and so part of the configuration we set up in our programs.

Let's consider the timing of such.  The STMF030 is usually running with 48 MHz clock, the GD32F103 I assume is configured for a 108MHz clock. Once the interrupt is triggered, the only priority task the interrupt needs to do is get the byte out of the Register and into the software buffer.  At 115200 baud, we have one bit width starting from the stop bit - it's the start bit, to get this task done before data would begin to be corrupted by the next incoming bit.  So just assuming only one bit width, an F030's 48MHz clock allows around 416 clock cycles to get this task done.  On a F103 at 108MHz that's around 937 clock cycles.  So plenty of time to get it from the Register and into the buffer.  We can also consider that the next byte interrupt  will not arrive until another 10 bits go by. This allows for 4160 clock cycles at 48MHz  and around 9735 clock cycles at 108MHz between the-byte-has-arrived interrupts.

For transmitting a byte, a similar process occurs.  Our programs send a byte from our transmit buffer into the TX register.  Here the module will send out each bit (start, data bits, stop bit) according to the configured parameters fairly independently.  When the byte has finally been sent and the TX Register is empty, it raises an interrupt to state it is empty (if our TX Empty interrupt is enabled).  The only priority task needing to be completed during this interrupt is getting the next byte from the TX Buffer (if any) and loading it into the TX Register. So when we have a Hardware UART module on our MCUs, we see very little time actually being used to handle incoming and outgoing bytes.

Next I examine a Software Serial implementation of this via bit-banging.

Login or Signup to post a comment