Why doesn't working on H/W serial

We make a small display with Differntial pressure transmitter on arduino mega 2560.

This source works on SoftwareSerial. But, It does not work on H/W Serial communication.

Plz read and give me a help.

#include <MsTimer2.h>

char buf[40];
int cmd[3];
String txt_data;
String file_name;
int val[3];
int set_val[3][2] = {{1,0},{1,0},{1,0}};
bool flag,flag1,flag2 = false;

int air_flow = 1000;
int dPressure = 300;
float temp = 23.4;
float humid = 50.0;
float baro = 1010.0;

void setup() {
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial) {
}
Serial.println("USB is connected!");

Serial2.begin(115200);
while (!Serial2) {
}
Serial.println("Display is connected!");
randomSeed(analogRead(A0));
MsTimer2::set(200,txData);
MsTimer2::start();
}


void loop() {
rxData();
}

void rxData() {
if(Serial2.available() > 0) {
  if(flag) {
    if(flag1) {
      for(int i = 0; i < 3; i++) {
        val[i] = Serial2.read();   // val[] receives that component ID from Nextion Display at touching penel.
      }                                     // Nextion display sends bytes with 0x65, next, 3 numbers.
      for(int i = 0; i < 3; i++) {
        cmd[i] = Serial2.read();
      }
      if(cmd[2] == 0xff) {
         flag = false;  // Display sends 0xff * 3 at last.
      }
      if(val[0] == 2) {  // It means "if sended components ID's page is 2"
        set_switch(val[1]);   // val[1] is object ID on Display.
      } else if(val[0] == 4) {   // component ID from Page no.4
        Serial.println("Recording is Ended.");
      } else {
        flag = false;
      }
    } else if(flag2) {
      Serial2.readBytes(buf,40);
      String txt_temp = String(buf);
      txt_data = txt_temp.substring(0,txt_temp.length()-3);
      file_name = txt_data + ".txt";
      Serial.print("file_name : ");
      Serial.println(file_name);
      flag = false;
    } else {
      long b = Serial2.read();  // Nextion display can send long type binary data.
      Serial.print("Num : ");
      Serial.println(b);
      flag = false; 
    }
  } else {
    int a = Serial2.read();
    switch(a) {
      case 0x65:
      flag = true; flag1 = true; flag2 = false; break;
      case 0x70:
      flag = true; flag1 = false; flag2 = true; break;
      case 0x71:
      flag = true; flag1 = false; flag2 = false; break;
    }
  }
} else {
  flag = false;
}
}

void set_switch(int val) {
switch(val) {
  case 3:
  if(set_val[0][0]==0) {
    set_val[0][0] = 1;
    set_val[0][1] = 0;
  }
  Serial.println("Actual Airflow");
  break;
  
  case 4:
  if(set_val[0][1]==0) {
    set_val[0][0] = 0;
    set_val[0][1] = 1;
  }
  Serial.println("Nominal Airflow");
  break;
  
  case 5:
  if(set_val[1][0]==0) {
    set_val[1][0] = 1;
    set_val[1][1] = 0;
  }
  Serial.println("Flowrate unit is CMH.");
  break;
  
  case 6:
  if(set_val[1][1]==0) {
    set_val[1][0] = 0;
    set_val[1][1] = 1;
  }
  Serial.println("Flowrate unit is CFM.");
  break;

  case 7:
  if(set_val[2][0]==0) {
    set_val[2][0] = 1;
    Serial.println("5 inch nozzle is Opened.");
  } else {
    set_val[2][0] = 0;
    Serial.println("5 inch nozzle is Closed.");
  }
  
  break;

  case 8:
  if(set_val[2][1]==0) {
    set_val[2][1] = 1;
    Serial.println("7 inch nozzle is Opened.");
  } else {
    set_val[2][1] = 0;
    Serial.println("7 inch nozzle is Closed.");
  }
  break; 
}
}

void txData() {
int temp_data;
temp_data = air_flow + random(500);
Serial2.print("main.dpFlow.txt=\"");
Serial2.print(temp_data);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);
Serial2.print("record.dpFlow.txt=\"");
Serial2.print(temp_data);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);

temp_data = dPressure + random(50);
Serial2.print("main.dpDP.txt=\"");
Serial2.print(temp_data);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);
Serial2.print("record.dpDP.txt=\"");
Serial2.print(temp_data);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);

float temp_data2;

temp_data2 = temp + random(200) / 100;
Serial2.print("main.temp.txt=\"");
Serial2.print(temp_data2,1);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);
Serial2.print("record.temp.txt=\"");
Serial2.print(temp_data2,1);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);

temp_data2 = humid + random(300) / 100;
Serial2.print("main.humid.txt=\"");
Serial2.print(temp_data2,1);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);
Serial2.print("record.humid.txt=\"");
Serial2.print(temp_data2,1);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);

temp_data2 = baro + random(1000) / 100;
Serial2.print("main.baro.txt=\"");
Serial2.print(temp_data2,1);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);
Serial2.print("record.baro.txt=\"");
Serial2.print(temp_data2,1);
Serial2.print("\"");
Serial2.write(0xff); Serial2.write(0xff); Serial2.write(0xff);
}

Welcome to the Forum. Please read these three posts:

How to use this forum - please read.
and
Read this before posting a programming question ... and
Planning and Implementing an Arduino Program

You have posted code without using code tags. The code tags make the code look

like this

when posting source code files. It makes it easier to read, and can be copied with a single mouse click. Also, if you don't do it, some of the character sequences in the code can be misinterpred by the forum code as italics or funny emoticons.
If you have already posted without using code tags, open your message and select "modify" from the pull down menu labelled, "More", at the lower left corner of the message. Highlight your code by selecting it (it turns blue), and then click on the "</>" icon at the upper left hand corner. Click on the "Save" button. Code tags can also be inserted manually in the forum text using the code and /code metatags.

Unless the sketch is too large, it's better if you post your code, rather than attach it. When it's attached, we have to download it, create a folder then open your code in our IDE. And afterwards, the folder remains unless we navigate to the "Temp" folder and manually remove it. It's much easier to just view the code in your post.

Many questions can be answered by reading the documentation which is provided with the IDE, available under the help tab, or online here.

There are many other things that programmers do to make their code understandable. Please do them, as a courtesy to the members who volunteer their time to help you here. One is to use a standard indentation to clearly show the code blocks. Never put more than one statement per line. Place any brackets by themselves on a separate line. Before posting the code, use Ctrl-T in the IDE to reformat the code in a standard format, which makes it easier for us to read. Another is to give things descriptive names. You can name numerical constants, pin numbers, variables and many other things in this way. For example, you can refer to a pin and an output level by number, like digitalWrite(3,0). But such a statement doesn't reveal anything about the purpose. digitalWrite(hornRelayPin, LOW) does. You can do that by declaring const byte hornRelayPin = 3; before setup() in your program. Many such names are already defined for you by the compiler and the Arduino IDE. Here are some:

#define HIGH 0x1
#define LOW  0x0
#define PI 3.1415926535897932384626433832795

Use them. There are many more. Use compiler math to compute values so you can see where they came from (or at least document them). For example, if you see the number 73, you would be hard put to explain the significance of it. But if you see "daysPerYear/5", it is obvious. One more thing. When you work on program continuously, you become familiar with it. So many things seem obvious even if they are not spelled out explicitly. But try looking at your own code six months later. It will be as if a stranger wrote it. So write for strangers, not yourself.

All good advices !

I place opening { for if, for, while, switch,... on the same line - personal preference...
Also indenting on a mac is cmd-T not ctrl-T

@OP - see your code turns italic in the for loop, that is likely because you have a val[i] expression written there but the forum software interpreted [i] as a command to go in italic. So second guessing where you have indexes or not based on the font is painful and you won't get much help because of this.

Also Serial communication is arriving at a slower pace than your microprocessor and code can read it so your code might end up starving and reading garbage so Your code likely does not work (or just by accident) with software serial because for example in rxData you check if there is at least one character available to read from the Serial port but you read many in one go. So you will read garbage if no character is there yet (read will return -1)

Best is to check at every loop for incoming data and handle receiving byte by byte before you have a full message, in a non blocking manner - see Robin's post on Serial Input for some best practices with Serial

I'm sorry that I don't follow manners.

And thank you for your helps. T T

Thanks for fixing the appearance of your first post! (Corrected a few error in my first answer now that I can see your code better)

I don't know why it makes problem.

But I shoot the trouble about receiving data.

This is the key.

      if(flag1) {
        for(int i = 0; i < 3; i++) {
          val[i] = Serial2.read();
          delay(1);              // just added this 1 line.
        }

... Ha...;;

void rxData() {
  while (Serial2.available() > 0) {
    if(flag) {
      if(flag1) {
        for(int i = 0; i < 3; i++) {
          val[i] = Serial2.read();
          delay(1);
        }
        flag = false;
        if(val[0] == 2) {
          Serial.print("Val : "); Serial.print(val[0]); Serial.print(", "); Serial.print(val[1]); Serial.print(", "); Serial.print(val[2]); Serial.println();
          //set_switch(val[1]);
        } else if(val[0] == 4) {
          Serial.println("Recording is Ended.");
        } else {
          flag = false;
        }
      } else if(flag2) {
        Serial2.readBytes(buf,16);
        String txt_temp = String(buf);
        txt_data = txt_temp.substring(0,txt_temp.length()-3);
        file_name = txt_data + ".txt";                           //여기에 파일명이 저장됨.
        Serial.print("file_name : ");
        Serial.println(file_name);
        flag = false;
      } else {
        long b = Serial2.read();
        Serial.print("Num : ");
        Serial.println(b);
        flag = false;
      }
    } else {
      int a = Serial2.read();
      switch(a) {
        case 0x65:
        flag = true; flag1 = true; flag2 = false; break;
        case 0x70:
        flag = true; flag1 = false; flag2 = true; break;
        case 0x71:
        flag = true; flag1 = false; flag2 = false; break;
      }
    }
  }
}
          delay(1);              // just added this 1 line.

this is a very bad fix... sure there is a chance that in the next ms a new character will have arrived.. but you don't know.. may be you'll have received more than 64 in the next ms and then you lost data... or may be for some reason it has not arrived and then you have your bug again...

what's wrong is the way you read the serial line...

I quite agree that that's wrong answer.

But I don't know why reading serial2 data.

for(int i = 0; i < 3; i++) {[color=#222222][/color]
  val[i] = Serial2.read();[color=#222222][/color]
}

Is it wrong way to read data from serial communication?

I want to read 3 bytes int type data.

yuitoyuis:
Is it wrong way to read data from serial communication?

I want to read 3 bytes int type data.

Have you studied the link in Reply #2? Serial Input Basics - simple reliable ways to receive data.

...R

yuitoyuis:
I quite agree that that's wrong answer.

But I don't know why reading serial2 data.

for(int i = 0; i < 3; i++) { val[i] = Serial2.read();}

Is it wrong way to read data from serial communication?
I want to read 3 bytes int type data.

well two things

1/ you enter the part where you go read the Serial line by doing while (Serial2.available() >[color=red] 0[/color]) { so you know that there is at least 1 byte waiting to be read, but clearly not more... if you need 6 bytes to be there in your code, then check for 6 not for just 1 - but that comes with its own issues (buffer overflow if you wait for too long, best is to read data as soon as it becomes available)

2/ if you want to read int, they are on two bytes on a UNO, and the read function returns only 1 byte. so if you are sending from the other side an int coded on two bytes, on the receiving end you need to rebuild the integer by reading the two bytes and combining them into an int

read Robin's post on Serial - that will become clearer

Thank you for your advices.

But It doesn't receives only 1 type data.

I use Nextion 4.3 HMI Display and it sends components ID data and String type text.

Display sends 3 cases.
first byte is 0x65, 3 byte type data is received to arduino. Last 3 bytes is 0xff.
first byte is 0x70, Display send Strings(it's just "filename.txt". SD card kit can just 8 word filename.) to arduino. Last 3 bytes is 0xff.
first byte is 0x71, Display send long type number to arduino.

Robin's tutorial is very awesome. And I repeat to read that at long time.

I think that I solve the case about first 0x65 byte.
It works pretty well in receiving file name and long type number.
But it makes problem about first 0x65 byte.

Display sends data to arduino like this.

ex>
0x65 0x02 0x04 0x00 0xff 0xff 0xff
It sends component ID. 0x02 in 2nd means page number. 0x04 in 3rd means object ID. 0x00 in 4th means touch event(release).

ex2>
0x70 f i l e n a m e 0xff 0xff 0xff
It sends char type data next of first 0x70 byte.

The basic confusion is that Serial.read() does not block.

If there is no character available, it returns with junk.

You have to check before every call to read if there is data to read.

It is done this way because blocking functions are unfriendly to a microcontroller event loop.

So remember always check with available() before calling read(). Every time.

Add delay() calls is not going to fix this, it usually makes everything worse (less responsive).

yuitoyuis:
Display sends data to arduino like this.

So what's the problem?

it seems to me that your examples use 0xff as the end marker and either 0x65 or 0x70 as the start marker.

Try using the second example in Serial Input Basics with 0xff as the end marker and see if you receive data you can make sense of.

Also, change the datatype for receivedChars etc to byte

...R