Start a new topic

Strange results with Serial Communications to Arduino

 I'm working on interfacing an Arduino Uno with a Nextion 2.8" HMI display, but I'm getting strange results with my serial communications that I cannot explain. I'm hoping someone here can help explain what's going on.

I'm trying to read the data sent from the HMI display into a buffer, but for some reasons, extra characters are being added to the buffer. When I press the button on the display, I should be receiving (as HEX):

 

65 0 1 1 FF FF FF

However, Instead, I'm getting the following:

 

65 FF FF FF
0 1 1 FF FF FF


To be clear, I can get my code to show me the intended result (the first above), if I output the characters one at a time to the Serial Port, but if i store them in an array before printing them, then I get the strange result shown above. If I setup my code to both print them one at a time and store them in the buffer and print them again, then I get the correct sequence both from the direct printing and from the array.

In the code below, there are two Serial.print commands commented inside the while loop. With those two lines commented (search for Exhibit A in the code), the results show the expected data split across two lines with three terminating characters injected after the first (this is repeatable, happens the same way every time). If I uncomment the lines, then it prints the line twice (once immediately after reading the byte, and again when it prints the contents of the array). Both print exactly the result I'm expecting.


At this stage, I'm just trying to test the serial communications with the Arduino Serial Monitor, but this result is something I can't quite understand. I tried using the Nextion libraries, but I found them difficult to work with.

 

#include <SoftwareSerial.h>
#include <Wire.h>

SoftwareSerial HMI(9, 8); // Define software serial for the HMI adapter (RX, TX)

const byte NL = 0x0a; // Define a constant as a newline character
const int BAUDRATE = 9600;

byte buffer[30]; // buffer for bytes coming from HMI.


void setup() {

  //Setup the serial port
  Serial.begin(BAUDRATE);
  while (!Serial)
  {
    //wait for serial port to connect. Needed for native USB only.
  }

  Serial.println("Serial Port Ready.");

  //Setup the HMI port
  HMI.begin(BAUDRATE);
  Serial.println("HMI Ready");
  HMI.println("");

}

void loop() {

  // When data arrives on the Serial port, send it to HMI.
  if (Serial.available())
  {
    byte inbyte = Serial.read();
    if (inbyte == NL)
    {
      HMI.write(0xff);
      HMI.write(0xff);
      HMI.write(0xff);
    }
    else
    {
      HMI.write(inbyte);
    }
  }

  if (HMI.available())
  {
    bool moretocome = true;
    int endcount = 0;
    int bytesread = 0;
    byte inbyte;
    //bool isascii = false;

    while (moretocome)
    {
      inbyte = HMI.read();

      // Exhibit A: Uncommenting these two lines produces the desired result, but prints the data twice.
      //Serial.print(inbyte, HEX);
      //Serial.print(" ");

      if (inbyte == 0xFF)
      {
        endcount++;
        if (endcount == 3)
        {
          moretocome = false;
          Serial.println("");
        }
      }
      else
      {
        endcount = 0;
      }
      buffer[bytesread] = inbyte;
      bytesread++;

    }

    for (int x = 0; x < bytesread; x++)
    {
      Serial.print(buffer[x], HEX);
      Serial.print(" ");
    }

    //Serial.println(bytesread, DEC);
    Serial.println("");

  }

}


 


Ok I will switch to the Mega2560.  I haven't used one or needed it, until now.  

I believe David's answer was clear he is using a Mega because the Uno wasn't serving his purpose.


I started with a Uno then due to limitations (using 7 serial ports!) stepped it up to a Mega2560.

David H:  I am having trouble just using (1) NEXTION, on Arduino Uno with (1) other serial port (a bluetooth hc-05).  The system either communicates with the Nextion, or the HC-05 (using the onboard UART as the debugger / upload from computer testing).


If I serial.begin nextion before / after the serial bluetooth determines which serial port will be use and which would be ignored.




@Paul Dufresne


Thanks!. This makes sense. I tried just removing HMI.println("");, but that didn't seem to fix it. After your explanation, I really thought that would work.


However, adding HMI.write(TERMINATOR,3); does work. It returns an invalid instruction, but everything works great after that initial junk is sent. I left in HMI.println("") and it still worked as well, however, I'm not sure why you would want that in the first place?


Either way, you are the man! Thank you so much! 


I have said it before, but this is an incredible forum with a very active community. It really makes working with these displays a pleasant experience. I just recently purchased mine, and I feel like it has been really good timing!


Thanks again!

Clarification on my post above. You should try one or the other, you shouldn't need both.

 

@Joshua Stump

It's possible that the first time you send out a command, there's already data that has been sent without a proper terminating character. Two things you can try, assuming you're using my code above

Remove the following line from setup():

HMI.println("");

 

At the end of setup(), add the following to force a clearing of any characters that have already been sent:
HMI.write(TERMINATOR,3); // Send three 0xff at the end of the command

 

HMI.write(TERMINATOR,3); // Send three 0xff at the end of the command

 

 That's my best guess.

 

@Paul Dufresne


Fantastic code! I spent a while trying to do something similar, but yours is just so clean. I am having one issue I was wondering if you were experiencing it as well.


For some reason, the first time I set a value using the arduino serial port (IE inputting h0.val=100 with a new line on the serial port) I get an error message back 1A FF FF FF, which is variable name invalid. However, if I send that exact same line again, It goes without a hitch. From that point on I can't mess it up. I have to restart the arduino and then it does it again, but only the first time. Do you have any ideas?


Thanks again for the code!

Hi,

The main problems I faced with the Arduino is the fact I could only get the Itead library to work one display!  It may support more but My skills are not strong enough to make the mods to their library.

I utilised a library from Dan Nixon https://github.com/DanNixon/NeoNextion and modified it to do the job.


I have a project that is working fine using four Nextion displays at once (1 Main 5", 1 central 3.5" and 2 x 2.4" either side of the 3.5)  I started with a Uno then due to limitations (using 7 serial ports!) stepped it up to a Mega2560.

No problem with refresh rates yet.


It uses hardware serial for the 5", and software serial for the three smaller screens..

Basically a full car body control and dash.


This is an extract from my .ino file.  It has a few notes that may help others. 

    

/* Body Control Module V2.65 to suit Mega2560
    By David H December 2015
    Ver 2.64 I am trying to run three Nextion screens using Softserial now
    This version uses NeoNextion library from Dan Nixon https://github.com/DanNixon/NeoNextion
    http://www.dan-nixon.com/neonextion-arduino-library/
    Ver  2.65 Moved the serial ports over for the 3 small displays and the fingerprint scanner to software    serial to leave the main screen on hardware serial 1 and hwser 2 & 3 for the ecu on powerjection. 
      Not all pins on the Mega and Mega 2560 support change interrupts,
      so only the following can be used
      RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53,
      A8 (62), A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69).


    HARDWARE SERIAL COMMS PINS
      0 - RX0 - Not used - left for serial debug on console
      1 - TX0
    * 19 - RX1 - this is the 5" Main screen
    * 18 - TX1
     17 - RX2 - use for efi computer 1 serial connection
     16 - TX2 -
     15 - RX3 - use this one for the efi computer serial
     14 - TX3 -

   SOFTWARE SERIAL COMMS PINS

     52 - RX - to Right side Nextion 2.8" display
     48 - TX
     53 - RX - to Left side Nextion 2.8" display
     49 - TX
     50 - RX- to Middle Nextion 3.5" display
     46 - TX 
    * 51 - RX - to software serial finger print scanner
    * 47 - TX 

  


#define NEXTION_5_PORT Serial1
Nextion nex5(NEXTION_5_PORT);

SoftwareSerial nexSerial2a(53, 49); // RX, TX Left Screen 2.8"
SoftwareSerial nexSerial35(50, 46); // RX, TX Middle screen 3.5"
SoftwareSerial nexSerial2b(52, 48); // RX, TX Right Screen 2.8"

Nextion nex2A(nexSerial2a);
Nextion nex35(nexSerial35);
Nextion nex2B(nexSerial2b);

 

void setup() {
  NEXTION_5_PORT.begin(57600); // Initialise the 5" Display
  nex5.init();
  
  nexSerial2a.begin(9600); // Initialise the 2.8" display (a) Left side Oil & Water Temp
  nex2A.init();

  nexSerial35.begin(9600); // Initialise the 3.5" display in the middle
  nex35.init();
  
  nexSerial2b.begin(9600); // Initialise the 2.8" display (b) right side Fuel & Battery
  nex2B.init();

  Serial.begin(57600); // start serial for output
  finger.begin(57600); // fingerprint sensor serial2 set the data rate
 

  

 I also found with the Uno that I had problems using hardware serial for the Nextion and trying to debug to the serial console via Uno usb. So I would suggest if you use a Uno use Software serial.


Also with Uno avoid setting SoftwareSerial up on Digital pins 0 & 1 as it will interfere with uploading of your Arduino sketches.


Love the displays, they can only get better.

Regards

Dave


Hey thanks for trying to help me. I researched at the websites of itead an found settings for the uno and the library for nextion.



Nice manuel...there is just a problem...It doesn´t work! The compiler is working without error messages but the upload takes 5 minutes until it stops without success


 :-(

Joachim,

For my project, I'm not using the Nextion library at all. I downloaded the library, but personally find it's overkill for my purposes, so my example code above is just a simple testing using serial data directly.

That said, by default, the Nextion Library uses Serial2 for communications with the HMI display. However, the UNO doesn't have a Serial2, which is why it won't compile. In NexConfig.h, you have to modify:
 
1
#define nexSerial Serial2

I haven't found a way to override this and use a SoftwareSerial.



 


1 person likes this
I'm a beginner also so I can't help you there. I do know that they modified library's. You have to use their version of RTCLib for the clock examples to work, the other versions of RTClib would not compile.

Hello Paul,


you said that you use an arduino for the nextion Display. I have a question which is not to your issue but you maybe could answer that. I also like to use the uno with my nextion. But i always get Compiler Errors, even when i trie the examples from the nextion library. Then i read on the itead Homepage, that i have to Change something in the nexconfig.h

Itead says here that i have to "If your board has only one hardware serial, such as UNO, you should disable dbSerial and redirect nexSerial to Serial(Refer to section:Serial configuration)."

I don´t know what to do exactly. this sentence is to much for me (i´m a beginner).

Can you say me what i have to do? Like "erase this sentence in nexconfig.h and "write this sentence"?

That would be so friendly. I spend hours on this Problem.


Thank you


Joachim


P.S. when i compile the examples and the mega is selected in "boards" everything works fine. This is why i think it is about the choosen "uno" in boards. 

Jesse,

I solved the timing issue in my code, and it was due to the way I was receiving bytes. I was trying to read multiple bytes without waiting for multiple bytes to be received. I've corrected my mistake, and the following code will be a better example of how to communicate with the HMI display:


 

#include <SoftwareSerial.h>
#include <Wire.h>

SoftwareSerial HMI(9, 8); // Define software serial for the HMI adapter (RX, TX)

const byte NL = 0x0a; // Define a constant as a newline character
const int HMIBAUDRATE = 9600;
const int SERIALBAUDRATE = 19200;

const byte TERMINATOR[] = {
  0xFF, 0xFF, 0xFF};

bool HMIcommand = false;
bool Serialcommand = false;

byte HMIbuffer[80]; // buffer for bytes coming from HMI.
byte Serialbuffer[80]; // buffer for bytes coming from Serial.

int HMIbytes = 0;
int Serialbytes = 0;

int HMIendcount = 0;

void setup() {

  //Setup the serial port
  Serial.begin(SERIALBAUDRATE);
  while (!Serial)
  {
    //wait for serial port to connect. Needed for native USB only.
  }

  Serial.println("Serial Port Ready.");

  //Setup the HMI port
  HMI.begin(HMIBAUDRATE);
  Serial.println("HMI Ready");
  HMI.println("");

}

void loop() {

  // When data arrives on the serial interface, store it in a buffer until you seel a NL character.
  if (Serial.available())
  {
    byte inbyte = Serial.read();

    if (inbyte == NL)
    {
      Serialcommand = true;
    }
    else
    {
      Serialbuffer[Serialbytes] = inbyte;
      Serialbytes++;
    }

  }

  // When data arrives on the HMI interface, store it in a buffer until you see three 0xff in a row.
  if (HMI.available())
  {
    byte inbyte;
    //int endcount = 0;

    inbyte = HMI.read();

    //delay(1);

    if (inbyte == 0xFF)
    {
      HMIendcount++;
      if (HMIendcount == 3)
      {
        HMIcommand = true;
        HMIendcount = 0;
      }
    }
    else
    {
      HMIendcount = 0;
    }

    HMIbuffer[HMIbytes] = inbyte;
    HMIbytes++;

  }

  // Process serial commands after they have been completely received and print them to the HMI interface
  if(Serialcommand)
  {
    for (int x = 0; x < Serialbytes; x++)
    {
      HMI.write(Serialbuffer[x]);
      Serial.write(Serialbuffer[x]);
    }
    HMI.write(TERMINATOR,3); // Send three 0xff at the end of the command
    Serial.println("");

    Serialcommand=false;
    Serialbytes=0;
  }

  // Process HMI data when they have been completely received and print them to the Serial interface
  if(HMIcommand)
  {

    // If the data received is a string, display it as a string
    if (HMIbuffer[0] == 0x70)
    {

      String command;
      for (int x = 1; x < HMIbytes - 3; x++)
      {
        command = command + char(HMIbuffer[x]);
      }
      Serial.print(command);
    }

    // If it wasn't a string, display it as hex
    else
    {
      for (int x = 0; x < HMIbytes; x++)
      {
        Serial.print(HMIbuffer[x], HEX);
        Serial.print(" ");
      }
    }
    //Serial.println(bytesread, DEC);
    Serial.println("");

    HMIcommand = false;
    HMIbytes = 0;
  }

}

 Hope it helps.

 

Thanks I'll go go try that. But why is that not in the example sketch they provide? That's setting people up for failure.
Jesse,

Feel free to take a look at the code I posted above. It might help. A couple of things to look out for:

  • When you send a command to the Nextion screen, you have to send three 0xFF for the screen to recognize the end of the command. In my test code, using the serial monitor, I have a simple if statement that replaces the "newline" character (sent by the serial monitor) with three OxFF so that the screen acknowledges the command
  • In your Nextion code, when you create a button or other object, make sure you check the "Send Component ID" box in either the press or release event tab.
  • The screen defaults to 9600 baud.


I hope this helps.

Login or Signup to post a comment