Pages: [1]   Go Down
Author Topic: SoftwareSerial reads mysterious characters.  (Read 744 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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   smiley-sad due to this issue and I believe that issue is with SoftwareSerial Library  and it interfered by other libraries.

* How can I solve this issue?
* Any Alternative to SoftwareSerial that work with RS485(Max485) ?
* can I use AltSoftSerial library  with this setup?
  (http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html)

 smiley-sad  please help...



« Last Edit: October 09, 2013, 12:03:16 am by kasun » Logged

Saskatchewan, Canada
Offline Offline
Edison Member
*
Karma: 49
Posts: 1397
Coding Geezer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?

Logged

There are 10 kinds of people in the world,
those who understand binary, and those who don't.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I was wondering where the code was.

Plus what you said. smiley
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Code:
#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

Code:
#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 ?
« Last Edit: October 09, 2013, 06:15:47 am by kasun » Logged

Saskatchewan, Canada
Offline Offline
Edison Member
*
Karma: 49
Posts: 1397
Coding Geezer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

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

There are 10 kinds of people in the world,
those who understand binary, and those who don't.

Austin, TX
Offline Offline
Faraday Member
**
Karma: 71
Posts: 6141
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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:

Code:
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:

http://www.gammon.com.au/forum/?id=12153#trap23
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:
#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) )

Code:
     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 (387.61 KB - downloaded 11 times.)
* SD.zip (57.86 KB - downloaded 11 times.)
« Last Edit: October 12, 2013, 12:54:48 am by kasun » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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?
Logged

0
Offline Offline
Shannon Member
****
Karma: 200
Posts: 11730
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

[ I won't respond to messages, use the forum please ]

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using the one in the photograph.
Logged

0
Offline Offline
Shannon Member
****
Karma: 200
Posts: 11730
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

[ I won't respond to messages, use the forum please ]

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
#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?  smiley-roll-sweat
« Last Edit: October 12, 2013, 01:43:31 pm by kasun » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48556
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

http://www.gammon.com.au/forum/?id=12153#trap18

As PaulS said.
Logged

Pages: [1]   Go Up
Jump to: