Pages: [1]   Go Down
Author Topic: multiple softwaresSerial inputs  (Read 747 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 1
Posts: 27
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
I am trying to get 2 software serial inputs to work. One inputs tag data from an rfid reader and the other outputs this data to a serial LCD. I cant use the hardware serial port as this will be used for a uart SD card. For now it used to display tag data for testing.

I realize that i have to close one software serial port before i open another by using the .end() method however this does not seem to be working .

The code i am using is below. It looks like when the LCD port is opened the rfid port does not accept any data from the tag reader. The first reference to the LCD works fine and displays "testing" as it should but the second reference to the LCD displays nothing. If i take out any references to the LCD it works fine although a bit slow when the .end() is used which is a bit odd.

Can anybody see what i have done wrong here.

Any help is much appreciated.

Cheers.

Code:
#include <SoftwareSerial.h>

SoftwareSerial rfid = SoftwareSerial(5, 6,true);
SoftwareSerial lcd = SoftwareSerial(2,3);

String tagString = "";    // string to hold input

void setup(){
  // setup the software serial pins
  pinMode(5, INPUT);
  pinMode(2, INPUT);
  pinMode(6, OUTPUT);
  pinMode(3, OUTPUT);
 
  Serial.begin(9600);  // Hardware serial for Monitor 9600bps
  Serial.println("Tag reader");

  lcd.begin(9600);       //open lcd port
  lcd.write(12);
  lcd.print("testing");
  lcd.end();       //close the port
 
  delay(1000);
}


void loop() {
  rfid.begin(38400);    //open the reader port at 38400 baud
  while (rfid.available() > 0) {
    char inByte = rfid.read();   
    if (inByte == 'L') {
      while(true) {
        inByte = rfid.read();
        tagString += inByte;
        if (inByte == '\n') {
          rfid.flush();       //flush the input buffer
          rfid.end();        //close the reader port
          lcd.begin(9600);      //open lcd port again to display the tag string
          lcd.write(12);        //cls
          lcd.print(tagString);
          lcd.end();             //close teh port
          rfid.begin(38400);      //open the rfid port
          tagString = "";
          break;
        }
      }
    }
  }
  rfid.end();
}

 
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't think you should be calling .end(), I think you should be calling .listen() when you want to switch.  This came from the "two port receive" example program in the library:

Code:
In order to listen on a software port, you call port.listen().
 When using two software serial ports, you have to switch ports
 by listen()ing on each one in turn. Pick a logical time to switch
 ports, like the end of an expected transmission, or when the
 buffer is empty.

EDIT:  You should only need to call .begin() once for each port you want.  You shouldn't have to keep opening and closing like that, just use .listen() to listen on another port.  I don't think you'll need to do anything to write to any open port other than to call .write(), .print() ...
« Last Edit: March 21, 2013, 12:42:56 am by afremont » Logged

Experience, it's what you get when you were expecting something else.

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Theoretically you can use one SoftwareSerial port because to the LCD you're writing only and from the RFID reader you're reading only. This way you can eliminate the switch between the two instances. If you want to use both (for whatever reason), call the begin() method only once per instance and define with the listen() method which instance is the listener at the moment. You can have multiple instances writing to each of them but only one instance can read at a given point.
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 27
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
And thanks for the replies. I have taken the advice and moved to the .listen() method but are still having a few issues getting tag data to appear on the LCD.

The following code;
Code:
#include <SoftwareSerial.h>

SoftwareSerial rfid = SoftwareSerial(5, 6,true);
SoftwareSerial lcd = SoftwareSerial(2,3);

void setup() {
 
  Serial.begin(9600);
  Serial.println("Tag reader");

  lcd.begin(9600);
  lcd.write(12);
  lcd.print("testing");
 
  delay(1000);
 
  rfid.begin(38400);
}

void loop() {
  rfid.listen();    //listen on the reader port
  while (rfid.available() > 0) {
    char inByte = rfid.read();
    Serial.write(inByte);
    lcd.write(12);      //cls
    lcd.write(inByte);
  }
}

Gives the following output on the Serial monitor nad nothing on the lcd after "testing".
Code:
Tag reader
LR 0000 0000000174825496
S*$&&&&$&&&&.lLL’ª¢Ê²jRþ¤@``aáÁÁƒ‚‚‚‚Šº¢Â’ª¢Ê²j¦ü3nlLLLL’ª¢Ê²j¦üR 0000 0000000174825496
IÁÁÁÁÁÁƒ‚‚‚‚Šº¢Â’ª¢Ê²j¦*$&&&&$&fLLLL\L’R 0000 00000001748“‚‚‚‚‚‚‚‚‚‚Šº¢Â6&$&&&&&&¦¦’R 0000 00000001748%‚‚‚‚‚‚‚‚‚‚‚Šº¢Â*$&&&&$&fLLLܘL’ª¤@````AáÁƒ‚‚‚‚Šº¢7fLLLLLL’©˜¸00 00000001748%‚‚‚‚‚‚‚‚‚‚‚Šº¢Â*$&&&&$&&&&.lÌL’¤@`aáÁÁÁÁÁÁÁÁÅÝÑá*$&&&&$&fLLLLLL“’R 0000 00000001748%‚‚‚‚‚‚‚‚‚‚Šº¢Â*$&&&&$&fLLLܘL’R 0000 00000001748µ‚‚‚‚‚‚‚‚‚‚Šº¢Â6&&&$&&&&&&¦¦’R 0000 00000001748%‚‚‚‚‚‚‚‚‚‚‚Šº¢Â*$&&&&$&&&&&lÌL’­ÁÁÁÁÁÁÁÁÁÁÁÁÅÝÓâ*$&&&&$&&&&&&îì’¤@`aaÁÁÁÁÁÁÁÁÅÝÑá*$&&&&$&&&&.lÌL’¤@````AáÁÁÁÁÁÁÅÝÑá*$&&&&$&&.lLLLL’¤@`aaáÁÁƒ‚‚‚‚Šº¢Â7$&fLLLLLL’R 0000 00000001748—‚‚‚‚‚‚‚‚‚‚Šº¢Â:$&&&&$&fLLLLLL’©˜¸00 00000001748%‚‚‚‚‚‚‚‚‚‚‚Šº¢Â*$&&&&$&&&&&lÌL’þ
LR 0000 0000000174825496
)*$&&&&$&&&&.lÌL’ª¢Ê²jRþR 0000 0000000174825496


And this code;
Code:
#include <SoftwareSerial.h>

SoftwareSerial rfid = SoftwareSerial(5, 6,true);
SoftwareSerial lcd = SoftwareSerial(2,3);

void setup(){
  Serial.begin(9600); 
  Serial.println("Tag reader");
  lcd.begin(9600);
  lcd.write(12);
  lcd.print("testing");
 
  delay(1000);
 
  rfid.begin(38400);
}

void loop() {
  rfid.listen();    //listen on the reader port
  while (rfid.available() > 0) {
    char inByte = rfid.read();
    Serial.write(inByte);
    lcd.listen();
    lcd.write(12);      //cls
    lcd.write(inByte);
   
    rfid.listen();
  }
}

gives this output in the serial monitor and nothing on the LCD after "testing".
Code:
Tag reader
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
Logged

Netherlands
Offline Offline
God Member
*****
Karma: 7
Posts: 642
A naughty mind is a joy forever.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

By looking at the best output I guess (!!!) the info on the RFID-tag you're using is LR 0000 0000000174825496. The data is about  24 characters long, but there's a bug in your code when you send the RFID-code to LCD.

Code:

while (rfid.available() > 0) {  // checks for available new info and enters the while loop when true
    char inByte = rfid.read(); // Reads 1 character of data
    Serial.write(inByte);        // sends that data to PC
    lcd.write(12);                 // clears LCD screen. (previous part of the RFID info is immediately erased)
    lcd.write(inByte);            // sends 1 character just received by RFID to lcd.
}                                    // go back to the start of the loop to see whether there's more data

In this part of code, you read ~24 bytes, but before each individual byte is displayed on LCD, you clear the screen. When you receive the second byte, you erase the first from screen. After receiving the third, you're erasing the second byte, after receiving the fourth, you're erasing the third etc. etc. etc. That way you'll never see the complete RFID, but only the last character received. Displaying the info happens at 9600 baud, which isn't super fast. Our eyes are much slower though and can only detect ~25 frames per second. The chance is big you're erasing and displaying all characters before your eyes notice it's done.

I must say I have little experience with RFID, but like I already wrote you in answer to your message in the guidance section, what if the last character sent is not visible ? There's a whole range of characters in the ascii-table that aren't visible and it's not strange for rs232 devices, like your rfid reader, to send a non visible carriage return or linefeed as last character.
Then you'll only see a blank screen with a non-visible  last character.

In Setup() you've printed "testing" and waited a second before going to the main loop, which is long enough to see. But after that second the screen blanks and only seems... to do nothing from a human perspective.

I can't promise you you won't see strange characters since you seem to receive strange ones, but this should at least display some... info to lcd.

Code:

If (rfid.available()>0) {           // check whether new RFID info is available
  lcd.write(12);                     // If so, Clear the screen once, before displaying the info
  while (rfid.available() > 0) {  // Is last character already read/displayed yet ?
      char inByte = rfid.read(); // If not, read 1 character of data
      Serial.write(inByte);        // sends that character to PC
      lcd.write(inByte);            // sends that character to LCD as well.
   }                                    // go back to the start of the loop to see whether there's still data not displayed.
}


In your last code you use lcd.listen() while rfid.available() isn't 0 yet. That causes problems.
If... you want to receive characters from the lcd and use lcd.listen(), it's best to read your rfid port untill there are no characters left.
With multiple standard hardware-serialports like the mega2560 has, it's easier to switch ports. Each port has it's own buffer where it stores info.  After switching to a second/third/fourth port, remaining characters (if existing) in the first port will still be available as if you never accessed another port.

I haven't read all code of the softwareserial-library to know how it exactly works, but it wouldn't surprise me it only uses one buffer of 64 bytes for all software-ports to use as little ram as possible. An Atmega328 only has 2 KB RAM and the less ram a library uses the better.
That in return makes it a bit harder to read different software-ports in a sketch, but it's not impossible.
You can send info to whatever port you want since all bytes sent are always sent immediately, but be sure the receiving buffer is empty before reading another port. If you don't do that you get errors like the "LLLLLLLLLLLLLLLL..." part you're receiving now.

Can you tell us anything about the reader and rfid-tags you're using ?
I know tags can store an amount of data varying from a few bytes up to several kilobytes. From my perspective, it could for example be a 32byte tag containing "LR 0000 0000000174825496" as info, but if it is one of several kilobytes, the gobbledygook info you're reading now might.... be correct as well.
 
« Last Edit: March 24, 2013, 09:58:36 pm by Simpson_Jr » Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 27
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Simpson_Jr,
And thanks for the detailed response. I will make the suggested changes and see if that makes any difference.

With reference to the odd characters after the tag (LR 0000 0000000174825496) these should not be there only a carriage return. If i remove references in void loop() to the LCD the tag displays correctly in the serial monitor (see below);
Code:
Tag reader
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496
LR 0000 0000000174825496

With reference to the LCD; The lcd does not blank after displaying "testing" for a second it just keeps displaying "testing" which indicates that the LCD is not receiving any further data even though it should be at least, receiving the lcd.write(12) command to blank the screen.

Any help is much appreciated.

Cheers.
Logged

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

Code:
void loop() {
  rfid.listen();    //listen on the reader port
  while (rfid.available() > 0) {
    char inByte = rfid.read();
    Serial.write(inByte);
    lcd.write(12);      //cls
    lcd.write(inByte);
  }
}
The first thing that happens in loop() is to make rfid the active listener. Any incoming serial data will be buffered for rfid.

As soon as a byte is read, the lcd instance is made active. Then, if there were buffered characters, you read from an inactive instance, making it active and write to an inactive instance, making it active. Only while the rfid instance is active can data be buffered for it. As soon as data arrives for that instance, you start toggling which instance is active.

You have, in my opinion, two choices. First, get a Mega with 4 hardware serial ports, and quit using SoftwareSerial.

Second, read the WHOLE tag BEFORE printing any part of it.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
As soon as a byte is read, the lcd instance is made active.

What do you mean by "active"? Making that instance the listener? Only calling the listen() method changes the active listener.
But sending something on a SoftwareSerial instance while the other instance should be receiving is a bad idea because the data is shifted out with delay loops and interrupts are turned off during that. So the conclusion of PaulS is absolutely correct: get a Mega with 4 hardware serial ports or change your setup to use the hardware serial (TX to the LCD, RX from the RFID reader) and buy a USB2Serial to use SoftwareSerial for debugging.
Logged

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

Quote
Only calling the listen() method changes the active listener.
This is a change from Mikal's design. I was going to contest your statement, but I went and looked at the code first. I see that you are right. Reading from a non-active instance does nothing. Writing does not change the active listener. But it does, as you note, cause problems with the listener.
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

One thing to be aware of is that there is only one receive buffer and that calling the .listen method clears that buffer.  So you want to be careful about when and how often it's called and not just call it arbitrarily.
Logged

Experience, it's what you get when you were expecting something else.

Pages: [1]   Go Up
Jump to: