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("");

  }

}


 


 Anyone have a screen and Arduino that can try to duplicate my results?

After struggling with this puzzle for several days, it appears to be a timing issue related to the software serial. I replaced the two serial.print commands (under Exhibit A in the code above) with:

 

delay(1);

 

Now the program works just fine. It's odd, to me, that that single microsecond is enough to fix the issue, but it has. I guess the 2.5ms delay added by the original serial.print commands was enough to correct the timing issue, which explains the odd result.

 

Those are better results than I'm getting. I just got it and I can't seem to get the nextion to communicate with my arduino
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.

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,

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.

 

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. 

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.
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

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


 :-(

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


@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!

@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.

 

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

 

Login or Signup to post a comment