Software Vs Hardware Serial

I have been using an Arduino MEGA to communicate with an inverter using the hardware Serial with no problem.

I'm trying the same code on an UNO R4, however, I can't use the hardware Serial as I need to read the Serial output , so I'm trying Software serial. However, I get a NAKKS response from the inverter so I wondered if there is a difference between what the Software Serial and Hardware Serial would output?

Here is the Arduino UNO code:

#include <SoftwareSerial.h>
SoftwareSerial mySerial(12, 13); // RX, TX

/////////////////////////////////AC V Hz////VA  AC W/////////BattV BatA+ SOC/////PV1A PV1V/////////////////////////////PV1W
char  InvString[] = "000.0 00.0 230.0 50.0 0000 0000 000 437 55.60 009 094 0029 01.7 283.1 00.00 00000 00010110 00 00 00492 010⸮";
char *power;             //watts generating
char *BV;             // battery voltage
char *B1A;            // Battery current inward going from solar
char *B2A;            // battery current outward going variable
char *ptr = NULL;
char buff[108];
char *PV1;
char *BV1;
char *chg;
char *dschg;
char *SOC;
char *strings[21];
const byte numChars = 108;
char receivedChars[numChars];
byte message[] = {0x51, 0x50, 0x49, 0x47, 0x53, 0xb7, 0xa9, 0x0d};
String QPIGS = "\x51\x50\x49\x47\x53\xB7\xA9\x0D";
boolean newData = false;
String strin;

// RS485 set up to send
#define MASTER_EN   2
byte txValue;


void setup()  
{
    Serial.begin(9600);
    mySerial.begin(2400, SERIAL_8N1);
    pinMode(MASTER_EN , OUTPUT);
    //Serial1.begin(115200);
    digitalWrite(MASTER_EN , LOW);
    Serial.println("<Arduino is ready>");
    Serial.println("<File: inverter-get-variablesTest>");


}  
void loop(){
recvWithStartEndMarkers();
showNewData();
}  

void Split(){
    strin.toCharArray(buff , 108);
    byte index = 0;           //initilise byte variable
    ptr = strtok(buff, " ");  // takes a list of delimiters
    while(ptr != NULL) {
        strings[index] = ptr;
        index++;
        ptr = strtok(NULL, " ");  // takes a list of delimiters
        }
          
          for(int n = 0; n < index; n++)
          {
            if (n==10)
          {
            SOC=strings[n]; // Battery SOC
           
            }
            if (n==5)
          {
            power=strings[n]; // Watts generating
           
            }
          if (n==8)
          {
            BV1=strings[n]; // Battery Voltage
           
            }
          if (n==9)
          {
            chg=strings[n]; // charge current
            
           }
          if (n==13)
          {
            PV1=strings[n]; // PV Voltage
           }
          if (n==15)
          {
            dschg=strings[n]; // discharge current
           }
   }

}
void recvWithStartEndMarkers() {
  Serial.println("collecting data");
    static boolean recvInProgress = false;
    static byte ndx = 0;  
    char startMarker = '(';
    char endMarker = '(';
    char rc;
 
    //mySerial.write(message, sizeof(message));
    mySerial.print(QPIGS);
    delay(100);
    while (mySerial.available() > 0 && newData == false) {
        rc = mySerial.read();
        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
        strin = receivedChars;
        Split();
    }
}

void sendData() {
  digitalWrite(MASTER_EN , HIGH); 
  delay(5); 
  Serial1.print('<');//begine message for RS485
  Serial1.print(power); // 5 characters
  Serial1.print(" ");
  Serial1.print(SOC); //3 characters
  Serial1.print(" "); 
  Serial1.print(chg); // 3 chars
  Serial1.print(" ");
  Serial1.print(dschg); //3 chars
  Serial1.print(" ");
  Serial1.print('>');
  Serial1.flush();
  delay(1000);
  digitalWrite(MASTER_EN , LOW);
}

void showNewData() {
    if (newData == true) {
        //Serial.print("This just in ... ");
        Serial.println(receivedChars);
        sendData();
        //Split();
        newData = false;
        //delay(3000);
    }
}

I have no experience with your board.

It's my understanding that the Uno R4 has multiple UARTs. See the end of ArduinoCore-renesas/cores/arduino/Serial.h at main · arduino/ArduinoCore-renesas · GitHub.

According to the schematic of the Uno R4 WiFi, pins 0 and 1 are not the pins that are used for communication with the PC; this is a difference with the normal Uno.

So you should be able to use pins 0 and 1 for communication with your inverter. Now the big question is how to refer to them. You can try

  1. Serial1.begin()
  2. _UART1_.begin() (or one of the other _UARTx_ objects.

Assuming that the Serial1 was for the Mega, why did you change the baudrate for mySerial?

You don't need to. The Uno R4 boards have 2 hardware serial interfaces

Serial uses the USB port
Serial1 uses a separate hardware UART on pins 0 and 1

Can you explain this?

In addition to my previous reply, Arduino.h defines the below

#ifndef NO_USB
#define Serial  SerialUSB
#define Serial1 _UART1_
#define Serial2 _UART2_
#define Serial3 _UART3_
#define Serial4 _UART4_
#define Serial5 _UART5_
#else
#define Serial _UART1_
#define Serial1 _UART2_
#define Serial2 _UART3_
#define Serial3 _UART4_
#define Serial4 _UART5_
#endif

So that is where SerialX comes from.

@leebaz
This is a tested Software UART Port (SUART Port) based communication test sketch between UNOR4WiFi and UNOR3.

UNOR4WiFi Sketch:

#include<SoftwareSerial.h>
SoftwareSerial SUART(6, 7);  //SRX = DPin-6, STX = DPin-7

void setup() 
{
  Serial.begin(9600);
  SUART.begin(9600);
}

void loop() 
{
  if(SUART.available()>0)
  {
    char y = SUART.read();
    Serial.println(y);
  }
  SUART.write('A');
  delay(1000);
}

UNOR3 Sketch:

#include<SoftwareSerial.h>
SoftwareSerial SUART(6, 7);

void setup()
{
  Serial.begin(9600);
  SUART.begin(9600);
}

void loop()
{
  if (SUART.available() > 0)
  {
    char y = SUART.read();
    Serial.println(y);
  }
  SUART.write('B');
  delay(1000);
}

From programmer's point of view, UNOR4WiFi is direct drop-out of UNOR3; so, UNOR4WiFi has one Hardware UART Port marked as RX(0)/TX(1) and any two permissible DPins could be configured to work as Software UART Port (post #6).

Wuld appreciate to see a testable sketch using UART1 Port for UNOR4WiFi.

You can use this one:

https://docs.arduino.cc/built-in-examples/communication/SerialPassthrough/#code

Just jumper pin 0 to pin 1 to create a "loopback" configuration for Serial1.

I don't have the board; just replace SUART in your code for the R4 by Serial1 and test and use pins 0 and 1.

And your point is?

One only makes one's life miserable when using SoftwareSerial if there are other options.

By the way, have you ever tried to use pin change interrupts on an Uno while using SoftwareSerial as well ; SoftwareSerial claims all PCINT vectors; you will have to hack the SoftwareSerial library to circumvent that. If not mistaken, the same applies to the Mega.

I want to leave 0, 1 for Serial0 Port for communication with PC/IDE/SM. Like MEGA and ESP32, I would like to use some other DPins for UART1 Port -- something like (in line with ESP32):

Serial1.begin(9600, SERIAL_8N1, 6, 7);

Pins 0 and 1 aren't used for that purpose on the UNO R4 WiFi.

2 Likes

Pins 0 and 1 are not used for communication with the PC on the Uno R4. The same applies to 32U4 based boards and a lot of new Arduinos. If the processor uses native USB, the serial pins are free.

2 Likes

The Baudrate for the inverter is super slow (2400). When I tried to use the Hardware serial I was getting an error message from the UNO, something about not being able to complete a process in time. I'll have to set it up again to and paste it here. That's why I switched to try the Software Serial to see if I could get it to work that way.

@ptillisch and @sterretje are right in saying that 0, 1 are not used for Serial Monitor/PC. The US (D+/D-) signals are demodulated/converted by the MCU itself similar to ESP32-C3. Unfortunately, the following line is not compiled:

 Serial1.begin(9600, SERIAL_8N1, 0, 1);

@ptillisch
The referred link of your post #8 does not contain UNOR4WiFi Board.

The pin number arguments on the begin function are a non-standard API created unilaterally by the ESP32 platform developers. When using the UNO R4 WiFi board, Serial1 is associated with pins 0 and 1 specifically.

There is something similar in the UNO R4 WiFi's core (except pins are configured via the constructor rather than a function):

But I don't see a reason to use that feature in this case since it is already done for you with Serial1:

1 Like

Post the exact code example and the error log. Hardware serial (if available) should always work better than software serial.

It works now with the following code:

Serial1.begin(9600);

Note: UNOR4WiFi shuld have the following marks on the board:

RX1 --> 0
TX1 --> 1

As indicated in post #3 above

1 Like

There was no reason that I did not read that post; unfortunately, I could not apprehend the meanings. Apologize for my cognitive limitations.

People say that UNOR4WIFi is the drop-out of UNOR3. So, RX-->0/TX-->1 should be UART0/Serial0 which is not true and this can be known only by consulting the schematic of UNOR4WiFi.

Thank you for the heads up about the USB Serial Vs UART Serial1. That makes a lot of sense!
However, I'm still getting a NAKss response using the UNO R4. I'm going o try again with a MEGA and see if I can spot the difference.