Serial input: distortion of bytes

Hello fellow creators,

im quite new to the entire Arduino world, but eager to get deeper in this topic. I have an Arduino UNO board and I have connected it (over two SoftwareSerial interfaces, one for communication with the GSM interface and one for the GPS interface) with an AI Thinker A9G Pudding board. I can send without any problems, and I also receive information back, but the issue I'm struggling with is, that I get a lot of disturbed bytes (that's at least my interpretation).

When I print my retrieved information on the serial monitor, I see some lines which are OK:
$GPGSV,3,1,11,04,79,204,30,39,34,167,*7A

and others are distorted:
$GNGGA,074953.000,4706.8611,r��b�ʊr�bj�43.5,M,,*40

I have followed the tutorials from the forum (and others) and I came up with this function to receive data

const unsigned int MAX_MESSAGE_LENGTH = 85;

void readGPSSerialData(){
  GPSData.listen();
  //delay(25);
  while (GPSData.available() < 63) {}; // I get the best result, if I wait till the buffer is really full before I start reading, otherwise I get even more distorted bytes
  while (GPSData.available() > 0) {
    char inByte = GPSData.read();  // Get one byte of the GPS data and deletes it from the buffer

    static char message[MAX_MESSAGE_LENGTH];
    static unsigned int message_pos = 0;

    if (inByte != '\n' && (message_pos < MAX_MESSAGE_LENGTH - 1)) {
      message[message_pos] = inByte;  //Add the incoming byte to our message
      message_pos++;
    } else {
      message[message_pos] = '\0';    //Add null character to string
      if (debugModus == true){
        Serial.println(message); //Print the message 
      }       
      message_pos = 0;                //Reset for the next message
    }
    nmea.process(inByte);  //this function from the nmea library creates valid GPS data out of this bytes
  }
  AIA9G.listen(); // I'm switching back to the other SoftwareSerial
}

My baud rate is set to 9600.

I've already searched tutorials on YouTube and here, and if I follow them 1:1 I still get the same issue where others seem to work. I don't get it and would really appreciate help on this topic.

Kind regards
Chris

PS: Because more context was asked for, here is a compressed, functional version of my code, with the same issue:

#include <SoftwareSerial.h>  // Library for using serial communication
#include <MicroNMEA.h>       // Library for converting NEMA message


SoftwareSerial AIA9G(3, 4);      // Pins 3, 4 are used as used as software serial pins RX ,TX
SoftwareSerial GPSData(10, 11);  // Pins 10, 11 are used as used as software serial pins RX ,TX
const unsigned int MAX_MESSAGE_LENGTH = 85; // For retreiving serial messages

const String api_key = "XXXX";  //API Key from thingsspeak.com

char buffer[85]; // Necessary for MicroNMEA
MicroNMEA nmea(buffer, sizeof(buffer)); // Initialize NMEA convertion

const unsigned long eventInterval = 20000; // Time interval for sending GPS data
unsigned long previousTime = 0; // Timestamp for time interval

float latitude_mdeg; // Variable for extracted latitude value
float longitude_mdeg; // Variable for extracted longitude value

void setup() {
  Serial.begin(19200);  // baudrate for serial monitor
  AIA9G.begin(115200);  // baudrate for GSM shield
  GPSData.begin(9600);  // baudrate for GPS data

  initGsmModule(); // Sends basic AT commands to configure the GPS and GSM module

}

void loop() {
  
  unsigned long currentTime = millis(); // base for the time interval section below
  readGPSSerialData();

  if (currentTime - previousTime >= eventInterval) {

    sendGPSData();
    previousTime = currentTime;

  }

  AIA9G.listen();

}

void initGsmModule() {

  // Enable GPS
  AIA9G.println("\r");
  AIA9G.print("AT+GPS=5");
  AIA9G.println("\r"); //This command is used to enable GPS. When this command is sent the GPS is turned On and the LED on module for GPS starts blinking.
  delay(100);

  AIA9G.print("AT+GPSRD=5");
  AIA9G.println("\r"); // The number defines how often the GPS data will be sent through the serial port
  readA9GSerialData();

  // Some more AT+Commands are sent here to AIA9G Software Serial

  
  
}

// ##### HERE ARE TWO FUNCTIONS WHERE I STRUGGLE #######
void readA9GSerialData(){

  AIA9G.listen();

  while (AIA9G.available() == 10) {};
  while (AIA9G.available() > 0) {
    char inByte = AIA9G.read();  // Get one byte of the GPS data and deletes it from the buffer

    static char message[MAX_MESSAGE_LENGTH];
    static unsigned int message_pos = 0;

    if (inByte != '\n' && (message_pos < MAX_MESSAGE_LENGTH - 1)) {
      message[message_pos] = inByte;  //Add the incoming byte to our message
      message_pos++;
    } else {
      message[message_pos] = '\0';    //Add null character to string
      Serial.println(message); //Print the message        
      message_pos = 0;                //Reset for the next message
    }
  }
}

void readGPSSerialData(){

  GPSData.listen();

  while (GPSData.available() < 63) {};
  while (GPSData.available() > 0) {
    char inByte = GPSData.read();  // Get one byte of the GPS data and deletes it from the buffer

    static char message[MAX_MESSAGE_LENGTH];
    static unsigned int message_pos = 0;

    if (inByte != '\n' && (message_pos < MAX_MESSAGE_LENGTH - 1)) {
      message[message_pos] = inByte;  //Add the incoming byte to our message
      message_pos++;
    } else {
      message[message_pos] = '\0';    //Add null character to string
      Serial.println(message); //Print the message       
      message_pos = 0;                //Reset for the next message
    }
    nmea.process(inByte); // Load the NMEA function to retreive GPS information
  }
  AIA9G.listen();
}

void sendGPSData() {
  Serial.print("http://api.thingspeak.com/update?api_key=");  // Display on Serial monitor
  Serial.print(api_key);
  Serial.print("&Latitude=");
  Serial.print(latitude_mdeg, 6);
  Serial.print("&Longitude=");
  Serial.print(longitude_mdeg, 6);
  Serial.println();

  if (true) {  //Function will follow later
    AIA9G.print("AT+HTTPGET=\"https://api.thingspeak.com/update?api_key=");
    AIA9G.print(api_key);
    AIA9G.print("&field1=");
    AIA9G.print(latitude_mdeg, 6);
    AIA9G.print("&field2=");
    AIA9G.print(longitude_mdeg, 6);
    AIA9G.println("\r");
    
    readA9GSerialData();

  }
}

Welcome to the forum

Oh dear !

Except in the most trivial of cases I have never heard of anyone successfully using 2 instances of SoftwareSerial

Consider using a board with more hardware UARTS such as the Mega to keep the Serial interface entirely separate

2 Likes

Really need to see what else is going on in your code .

I have managed a reasonably reliable combo of softwareSerial and AltSoftSerial, but fully reliable i never managed,
We do need to see the whole code of course if to make an attempt at all.
And the wiring i guess.
I think part of the issue may be the construction you use here

while (GPSData.available() < 63) {}; // I get the best result, if I wait till the buffer is really full before I start reading, otherwise I get even more distorted bytes
  while (GPSData.available() > 0) {
1 Like

Thank's for the input. I thought this issue is handled with the "SoftwareSerial.listen()" function. Is that function not reliable? Is there an issue if I have multiple baud rates?
Sadly I only have this board for now.

@hammy and @Deva_Rishi: I have added some context with (a compressed version of the original code, with the same issue).

@Deva_Rishi: I have experimented with that part quite a while and I get the best results with this constilation. But still I have doubts here as well. The only thing which puzzles me: Why do I get disturbed bytes? If that part would be the issue, I should lose some bytes here and there, but I would not understand, why I get disturbed ones (�).

Software serial turns off interrupts may mean that the processor doesn't get a chance to transfer the most recent byte from the serial hardware to RAM. Missing a byte of data may cause the incorrect character to be displayed.

Using words in an internet search will reveal such info.

1 Like

SoftwareSerial and a baudrate of 115200 don't combine well.

Further I would suggest that you check the return value of the listen method to make sure that the switching did succeed.

1 Like

Thanks for the input @Idahowalker!
Internet search is kind of tricky, when you are new to a topic. I have ca. 30 tabs in my browser, all regarding this topic, so it's not that I haven't tried :wink:

this is beyond what you can receive with swSerial, is there a way to set the baudrate for AIA9G to 9600bps ? because running swSerial at 2 different baudrates is just asking for trouble.

I actually would switch one of the devices to hwSerial, and use a USB-TTL converter to display what is now going to hwSerial.

btw

AIA9G.listen();

  while (AIA9G.available() == 10) {};
  while (AIA9G.available() > 0) {

This is nonsense, you mean to wait for the data to be exactly not 10 bytes in the buffer, while you are not listening constantly.

1 Like

Use a board with multiple hardware serial ports, like a ESP32.

1 Like

or a Micro with 1 swSerial or a Mega etc.

1 Like

Thank's @Deva_Rishi, @Idahowalker and @sterretje for your fast and competent responses!
Even thou I haven't successfully solved my issue, you brought me an important step further.

To summarize my take aways (if some should stumble over the same issue and find this by searching the web):

  1. Try to avoid SoftwareSerial, if you need more than one
  2. Don't push SoftwareSerial to a baud rate of 115200
  3. If you have to use more than one SoftwareSerial, try to have them at the same baud rate
  4. Check return value of the SoftwareSerial.listen() method

Thanks again and have a nice day!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.