SoftwareSerial reads mysterious characters.

Working with a data logging project which use RS485 port with UNO board, and I’m using SD card , Real-time clock, and Nokia 5110 display. I use MAX485 chip as shown in the fig with softwareSerial library , Sometimes reading going wrong and it contain some mysterious characters.
My project is really stuck :frowning: due to this issue and I believe that issue is with SoftwareSerial Library and it interfered by other libraries.

:frowning: please help...

You know, it's really frustrating. My mind-reading skills seem to be not working well tonight. I'm having trouble determining:

How reading is going wrong.
What mysterious characters you're getting.
Why you think it's a problem with the SoftwareSerial library.
What code you are using to read whatever is coming in on RS485.

To answer your questions.

  1. I don't know, because you have not given us any relevant information.

  2. Probably, but you may or may not need an alternative.

  3. Perhaps, but you may or may not need to use it.

"please help".

I'd love to, really I would, if only I knew more about your symptoms and code.

By the way. I have a problem with one of my horses. Could you tell me what I should do with her?

I was wondering where the code was.

Plus what you said. :slight_smile:

I have attached the code with this.

The story is…
I have a Sensor which communicate via RS485 ASCII and I’am using two commands to retrieve two types of data(Ex data01 and data02). Finally I need to store date_time + data01 + data02 as a one line in my SD card in every second(using DS1307 real time clock).
Also I need to Display those data in LCD

This code is working properly

#include <SoftwareSerial.h>
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>

SoftwareSerial mySerial(8, 9); // RX, TX


String time_now;
int t_second;
tmElements_t tm;

void setup() {
  pinMode(A0,OUTPUT);
  Serial.begin(9600);
  mySerial.begin(9600);
  Serial.println("Loading.......");
  
   if (!SD.begin(4)) 
      {
        Serial.println("SD Card failed, or not present");
      }
    else 
      {
        Serial.println("initialized....");
      }
}

void loop() {

 if (RTC.read(tm)) 
  {
   if (t_second != tm.Second )
     {
       t_second = tm.Second;
       Serial.print(time_now);
       SaveData(RS485());

       delay(100);
    }
  }
}
//-----------------------------SD card Save---------------------------------------------
void SaveData(String DataString){
     time_now =String(tmYearToCalendar(tm.Year))+"-"+c2d(tm.Month)+"-"+c2d(tm.Day) + " " + c2d(tm.Hour)+ ":" + c2d(tm.Minute)+":"+ c2d(tm.Second) ;
     File dataFile = SD.open("data.txt", FILE_WRITE);
         if (dataFile) 
              {
               
               dataFile.print(time_now);
               dataFile.println(DataString);
               //dataFile.println(DataString);
               
               //Serial.println("Data Write Ok");
               Serial.println(DataString);
               dataFile.close(); 
           } 
         else 
            {
            Serial.println("data loging err..");
            } 
}
//-----------------------------------Convert two Digit number------------------------
String c2d(int x){
  String conv;
 if (x < 10) { 
  conv ="0" + String(x);
  }
  else
  {
   conv= String(x);
  }
 return conv;
}
//----------------------------------Get data from RS485 ASCII-------------------------
String RS485(){
  String a,b;
  char myChar,Energy;
  
  digitalWrite(A0, HIGH);
  mySerial.write("#01A\r");
  digitalWrite(A0, LOW);
  delay(10);
        
  while(mySerial.available())
  {
    myChar=mySerial.read();
    a=a+(String)myChar;
  }
  //delay(10);
  //---------------------
  digitalWrite(A0, HIGH);
  mySerial.write("#01W\r");
  digitalWrite(A0, LOW);
  delay(10);
        
  while(mySerial.available())
  {
    Energy=mySerial.read();
    b=b+(String)Energy;
  }
  
  
  return a+b;
}

output is correct in order (date Time + Data01+Data02)

But once I change my code to display in the LCD

#include <SoftwareSerial.h>
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <LCD5110_Basic.h>

SoftwareSerial mySerial(8, 9); // RX, TX
LCD5110 myGLCD(5,6,7,3,2);

extern uint8_t SmallFont[];//LCD
tmElements_t tm;//time

String time_now;
int t_second,RS485_pin=2,V=230,I=5;



void setup() {
  myGLCD.InitLCD();
  myGLCD.setFont(SmallFont);
  myGLCD.print("Loading",CENTER, 8);

  delay(2000);

  pinMode(A0,OUTPUT);
  Serial.begin(9600);
  mySerial.begin(9600);
  myGLCD.clrScr();
  myGLCD.print("Scaning", CENTER, 16);
  delay(1000);
   if (!SD.begin(4)) 
      {
        myGLCD.clrScr();
        myGLCD.print("SD failed", CENTER, 16);
        delay(2000);
      }
    else 
      {
        
        myGLCD.clrScr();
        myGLCD.print("Status OK", CENTER, 16);
        delay(1000);
      }
}

void loop() {

 if (RTC.read(tm)) 
  {
   if (t_second != tm.Second )
     {
       t_second = tm.Second;
       Serial.print(time_now);
       SaveData(RS485());


       delay(100);
    }
  }
}
//-----------------------------SD card Save---------------------------------------------
void SaveData(String DataString){
     time_now =String(tmYearToCalendar(tm.Year))+"-"+c2d(tm.Month)+"-"+c2d(tm.Day) + " " + c2d(tm.Hour)+ ":" + c2d(tm.Minute)+":"+ c2d(tm.Second) ;
     File dataFile = SD.open("data.txt", FILE_WRITE);
         if (dataFile) 
              {
             if(SD.exists("data.txt")){   
                 dataFile.print(time_now);
                 dataFile.println(DataString);
                   
                 Serial.println(DataString);
                 dataFile.close();
               
                 display_data(DataString);//on LCD
             } 
            else 
             {
                 myGLCD.clrScr();
                 myGLCD.print("Please Insert", CENTER, 8);
                 myGLCD.print("SD Card", CENTER, 24);
             } 
            }
}
//-----------------------------------Disply Data on LCD------------------------------
void display_data(String LCD_data){
 
  myGLCD.clrScr();
  
  myGLCD.print("A:"+String((StrToFloat(LCD_data.substring(0,7)))*V)+" V", CENTER, 0);
  myGLCD.print(" "+String((StrToFloat(LCD_data.substring(8,14)))*I)+" A", CENTER, 8);

}
//-----------------------------------String to float---------------------------------
float StrToFloat(String Str_Raw_Data){
  float x;
  char carray[Str_Raw_Data.length() + 1]; //determine size of the array
  Str_Raw_Data.toCharArray(carray, sizeof(carray)); //put str into an array
  x=atof(carray);
  return x;
}
//-----------------------------------Convert two Digit number------------------------
String c2d(int x){
  String conv;
 if (x < 10) { 
  conv ="0" + String(x);
  }
  else
  {
   conv= String(x);
  }
 return conv;
}

//----------------------------------Get data from RS485 ASCII-------------------------

String RS485(){
  String a,b;
  char Energy,data_byte;
  
  
  digitalWrite(A0, HIGH);
  mySerial.write("#01A\r");
  digitalWrite(A0, LOW);
  
        
  while(mySerial.available())
  {
    data_byte=mySerial.read();
    a=a+(String)data_byte;
  }
  
  //---------------------
  digitalWrite(A0, HIGH);
  mySerial.write("#01W\r");
  digitalWrite(A0, LOW);
  
        
  while(mySerial.available())
  {
    Energy=mySerial.read();
    b=b+(String)Energy;

  }
  
  
  return a+b;
}

Result is like this,

  • it has some mysterious characters.
  • data Order also has changed. I need String data 'data01' and 'data02' in the order of data01+data02 but it resulted as data02+data01
  • those type of characters appear not only at the starting but also amidst the data logging.

Any Idea how to overcome this ?

I suspect you are running out of RAM. You are using the String class, which is very memory hungry. The "mysterious characters look a lot like unterminated character arrays that do not contain printable ASCII characters. I would recommend using char arrays (C-style strings) instead of Strings.

To check this out, you might want to try making calls from a few places to the following routine. I can't take credit for this. I read it in one of the threads here, I think. Try it with your old code, too.

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

Instead of wasting the memory and overhead of putting everything into a temporary string (time_now), print out each element of that string with individual print statements.

float StrToFloat(String Str_Raw_Data){
  float x;
  char carray[Str_Raw_Data.length() + 1]; //determine size of the array
  Str_Raw_Data.toCharArray(carray, sizeof(carray)); //put str into an array
  x=atof(carray);
  return x;
}

Whoa.

How about:

float StrToFloat(String Str_Raw_Data)
  {
  return atof (Str_Raw_Data.c_str ());
  }

And then you don't need the function at all, right? Just to call another one?

Better read this:

Thank you very much for the guidance. A Small change “delay(10);” in RS485 data acquisition correct the data order.

#include <SoftwareSerial.h>
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <LCD5110_Basic.h>

SoftwareSerial mySerial(8, 9); // RX, TX
LCD5110 myGLCD(5,6,7,3,2);

extern uint8_t SmallFont[];//LCD
tmElements_t tm;//time

int t_second,V=230,I=5;
String time_now;



void setup() {
  myGLCD.InitLCD();
  myGLCD.setFont(SmallFont);
  pinMode(A0,OUTPUT);
  Serial.begin(9600);
  mySerial.begin(9600);

  delay(1000);
   if (!SD.begin(4)) 
      {
        myGLCD.clrScr();
        myGLCD.print("SD failed", CENTER, 16);
        delay(2000);
      }
    else 
      {
        myGLCD.clrScr();
        myGLCD.print("Status OK", CENTER, 16);
        delay(1000);
      }
}

void loop() {

 if (RTC.read(tm)) 
  {
   if (t_second != tm.Second )
     {
       t_second = tm.Second;
       SaveData();
       //Serial.println(t_second);
     }
  }
}
//-----------------------------SD card Save---------------------------------------------
void SaveData(){
     String VC_Data,E_Data;
     
     time_now =String(tmYearToCalendar(tm.Year))+"-"+c2d(tm.Month)+"-"+c2d(tm.Day) + " " + c2d(tm.Hour)+ ":" + c2d(tm.Minute)+":"+ c2d(tm.Second);
     
     
     
     File dataFile = SD.open("data.txt", FILE_WRITE);
         if (dataFile) 
              {
             if(SD.exists("data.txt")){
                 VC_Data =RS485_All();
                 E_Data=RS485_Energy();
                 
                 dataFile.println(time_now+VC_Data+E_Data);
                 dataFile.close(); 
                 
              
                 myGLCD.clrScr();
                 myGLCD.print("A: "+ String(StrToFloat(VC_Data.substring(1,8))*V)+" V", LEFT, 0);
                 myGLCD.print(" : "+ String(StrToFloat(VC_Data.substring(9,14))*I)+" A", LEFT, 8);
                 //myGLCD.print("B: "+ String(StrToFloat(VC_Data.substring(15,22))*V)+" V", LEFT, 16);
                 //myGLCD.print(" : "+ String(StrToFloat(VC_Data.substring(23,29))*I)+" A", LEFT, 24);
                 //myGLCD.print("C: "+ String(StrToFloat(VC_Data.substring(30,37))*V)+" V", LEFT, 32);

             } 
            else 
             {
                 myGLCD.clrScr();
                 myGLCD.print("Insert SD", CENTER, 8);
                 //myGLCD.print("SD Card", CENTER, 24);
             } 
            }
}
//-----------------------------------String To Float --------------------------------
float StrToFloat(String Str_Raw_Data)
  {
   return atof (Str_Raw_Data.c_str ());
  }
//-----------------------------------Convert two Digit number------------------------
String c2d(int x){
 String conv;
 if (x < 10) { 
  conv ="0" + String(x);
  }
  else
  {
   conv= String(x);
  }
 return conv;
}

//----------------------------------Get data from RS485 ASCII-------------------------

String RS485_All(){
  String a;
  char data_byte;
  
  
  digitalWrite(A0, HIGH);
  mySerial.write("#01A\r");
  digitalWrite(A0, LOW);
  delay(10);
        
  while(mySerial.available())
  {
    data_byte=mySerial.read();
    a=a+(String)data_byte;
  }
  
  return a;
}
//-----------------Data02-----------------------------
 String RS485_Energy(){ 
  String b;
  char Energy;
  
  digitalWrite(A0, HIGH);
  mySerial.write("#01W\r");
  digitalWrite(A0, LOW);
  delay(10);
        
  while(mySerial.available())
  {
    Energy=mySerial.read();
    b=b+(String)Energy;
  }
  
  return b;
}

But when I try to display in the LCD I encounter some issues, I suspect that it’s about Flash Memory and once it exceed 85%, mysterious characters appear again.
I cannot uncomment following lines in SaveData() (same result can observe though I add a code other than this if it exceed 85% (27,600 bytes) )

      myGLCD.clrScr();
                 myGLCD.print("A: "+ String(StrToFloat(VC_Data.substring(1,8))*V)+" V", LEFT, 0);
                 myGLCD.print(" : "+ String(StrToFloat(VC_Data.substring(9,14))*I)+" A", LEFT, 8);
                 //myGLCD.print("B: "+ String(StrToFloat(VC_Data.substring(15,22))*V)+" V", LEFT, 16);
                 //myGLCD.print(" : "+ String(StrToFloat(VC_Data.substring(23,29))*I)+" A", LEFT, 24);
                 //myGLCD.print("C: "+ String(StrToFloat(VC_Data.substring(30,37))*V)+" V", LEFT, 32);
  • To get rid of this, how could I modify SD library (I don’t want other than write to SD card) and NOKIA-5110 LCD library (I just need simple font only)?

  • Does this approach feasible?

I have attached the libraries.
I tried to get rid of String library, but It seems cannot eliminate completely…

LCD5110_Basic.zip (388 KB)

SD.zip (57.9 KB)

I tried to get rid of String library, but It seems cannot eliminate completely…

You can do it. Why cannot you eliminate it? Is your program infested with String?

kasun:
I use MAX485 chip as shown in the fig with softwareSerial library , Sometimes reading going wrong and it contain some mysterious characters.

Which circuit are you using, the one in the photograph or the one in the schematic (which is
lacking the bias network).

I'm using the one in the photograph.

Good, that seems to have enough resistors to have a proper bias network - three
resistors in a chain to bias the lines in the absence of active drive. You RS485 cable is
of course twisted-pair?

Yes, length is less than 1 feet.
................................................................
Thought to start this from Zero. ..I’m trying to re-write this again by avoiding String libraries.
I have two functions, one is using char and other one using string (just as reference) both use same sensor command.

#include <SoftwareSerial.h>

SoftwareSerial mySerial(8, 9); // RX, TX

void setup() {
pinMode(A0,OUTPUT);
Serial.begin(9600);
mySerial.begin(9600);

}

void loop() {
 //Serial.println(RS485_char());
 Serial.println(RS485_string());
 
 delay(1000);
}

//------------------------Char------------------------
char* RS485_char(){
  char data_byte_a[71];
  int x=0;
      
  digitalWrite(A0, HIGH);
  mySerial.write("#01A\r");
  digitalWrite(A0, LOW);
  delay(10);
  
  while(mySerial.available())
  {
    data_byte_a[x]=mySerial.read();
    x++;
  }
    return data_byte_a;
}
//---------------------------String---------------------
String RS485_string(){
  String data;
  char a;
      
  digitalWrite(A0, HIGH);
  mySerial.write("#01A\r");
  digitalWrite(A0, LOW);
  delay(10);
  
  while(mySerial.available())
  {
    a=mySerial.read();
    data+=String(a);
  }
    Serial.println(data.length());
    return data;
}

Once I call RS485_string() , output prints correctly ( 71 ->> Serial.println(data.length()) )

Once I call RS485_char() -> wrong output with mysterious characters and it completely holds the void loop()

sensor gives an output with 71 characters (length is fixed).. Any idea? :cold_sweat:

Any idea?

Yes. Returning a pointer to an array on the stack, that is subject to destruction at any time, is a bad idea. Pass an array to store the data in to the function.

As PaulS said.