Softwareserial

Hi,

I am wondering now if there is a nice way to make the softwareSerial.read() call non-blocking.
I mean, this is its major weakness as I see it, and I believe that if it were easy to do it then it would have already been done in the IDE distribution.

Still, does anyone know a workaround for this, such as using an interrupt or (as I think maybe more simple) subtituting the "while (digitalRead(rx));" by a timeout?

Greets to all the Arduinoers out there! :wink:

Hey all. I'm having an odd problem with my Arduino Diecimila. If I try the Software Serial example on pins 0 and 1 and use the arduino IDE to send a character, it works fine. However, if I use any other two pins (2 and 3 for example, softwareserial.read() doesn't wait for a byte to be sent. It just automatically reads in a 0, which means that nothing is ever actually read. I can have the pins not plugged into anything and the software serial read() function will still automatically read in a 0. Anyone have a similar problem? (Using Arduino 10, btw)

Check this thread, there's another library for Diecimila somewhere in here:-

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1202245205/0

It's a common problem, here's my solution:-

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1205243372

Awesome. I guess I'll try out the library as soon as I get home from work. As for your solution, well, I haven't yet graduated to straight AVR programming yet. Thank you very much for your help :slight_smile:

Awesome. I guess I'll try out the library as soon as I get home from work. As for your solution, well, I haven't yet graduated to straight AVR programming yet. Thank you very much for your help :slight_smile:

There's no straight AVR programming involved or required.

The IC's are programmed using the Arduino10 IDE, they are just ultra stripped down and use the mini USB adapter rather than having one inline, like the NG.

The ATMEGA168's are supplied with the Adaboot already installed by The Modern Device Company, so they're shipped ready to accept programs, like an NG, but with less parts.

So it's still an Arduino, but with 2 serial buffers and less components, and more I/O's, for less than the cost of an NG if you've got a mini-USB adapter laying around.

The designs an elaboration on this:-

http://art364.pbwiki.com/Standalone+Arduino

To stress test the shared resonator and find out if anything "flaky" happens, we've had the 2 IC's running now constantly for 3 days, and they're still ticking along quite happily in perfect synchronization. We didn't expect anything weird to happen, but it's worth knowing for certain because it hadn't been done before.

I see. I suppose it's worth looking into then, since I happen to have an adapter lying around. But a question about the AFSoftSerial lib... if I use the example posted in that thread (which uses pins 2 and 3) and bridge pins 2 and 3, shouldn't pin two send the bytes to pin three, which will then spit them back out at me through Serial.print((char)mySerial.read()) ? mySerial.available() never returns true.

Edit: I was just looking at the source and it says that it stops interrupts while it's transmitting, so I guess this would imply that it cannot send and receive at the same time?

Edit2: Okay, I guess if I had just read the thread like an attentive person, I would have known that without looking at the source. Sorry : /

Modified the code a bit and came up with this for the Parallax RFID reader.

// RFID reader for Arduino
// Wiring version by BARRAGAN http://people.interaction-ivrea.it/h.barragan
// Modified for Arudino by djmatic
// And pieces from Arduino Playground http://www.arduino.cc/playground/Learning/PRFID
// And then modified again by thekidd

#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3
#define ledPin 13

// set up a soft serial port
SoftwareSerial mySerial(rxPin, txPin);

int val = 0;
char code[10];
int bytesread = 0;

void setup() {
// define pin modes for tx, rx, led pins:
pinMode(rxPin, INPUT); // Set rxPin as INPUT to accept SOUT from RFID pin
pinMode(txPin, OUTPUT); // Set txPin as OUTPUT to connect it to the RFID /ENABLE pin
pinMode(ledPin, OUTPUT); // Let the user know whats up

// set the data rate for the serial ports
mySerial.begin(2400); // RFID reader SOUT pin connected to Serial RX pin at 2400bps
Serial.begin(9600); // Serial feedback for debugging in Wiring

// say something
Serial.println("Hello World!");
}

void loop() {
digitalWrite(txPin, LOW); // Activate the RFID reader
digitalWrite(ledPin, LOW); // Turn off debug LED

if((val = mySerial.read()) == 10) { // check for header
bytesread = 0;

while(bytesread<10) { // read 10 digit code
val = mySerial.read();

if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading
break; // stop reading
}

code[bytesread] = val; // add the digit
bytesread++; // ready to read next digit
}

if(bytesread == 10) { // If 10 digit read is complete
digitalWrite(txPin, HIGH); // deactivate RFID reader
digitalWrite(ledPin, HIGH); // activate LED to show an RFID card was read
Serial.print("TAG code is: "); // possibly a good TAG
Serial.println(code); // print the TAG code
}

bytesread = 0;
delay(2000); // wait for a second to read next tag
}
}

Now I want to integrate this with a Purdy LCD, a Parallax GPS, and Xbee! I'll post what I find out for those interested.

Glad I found this post to integrate SoftwareSerial. I thought I was running out of Serial pins. Kudos to whoever wrote the SoftwareSerial library.

Also posted at: http://www.tekcrack.com/interfacing-arduino-with-parallax-rfid-reader-using-softwareserial.html

--thekidd

Modified the code a bit and came up with this for the Parallax RFID reader.

// RFID reader for Arduino
// Wiring version by BARRAGAN http://people.interaction-ivrea.it/h.barragan
// Modified for Arudino by djmatic
// And pieces from Arduino Playground http://www.arduino.cc/playground/Learning/PRFID
// And then modified again by thekidd

#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3
#define ledPin 13

// set up a soft serial port
SoftwareSerial mySerial(rxPin, txPin);

int val = 0;
char code[10];
int bytesread = 0;

void setup() {
// define pin modes for tx, rx, led pins:
pinMode(rxPin, INPUT); // Set rxPin as INPUT to accept SOUT from RFID pin
pinMode(txPin, OUTPUT); // Set txPin as OUTPUT to connect it to the RFID /ENABLE pin
pinMode(ledPin, OUTPUT); // Let the user know whats up

// set the data rate for the serial ports
mySerial.begin(2400); // RFID reader SOUT pin connected to Serial RX pin at 2400bps
Serial.begin(9600); // Serial feedback for debugging in Wiring

// say something
Serial.println("Hello World!");
}

void loop() {
digitalWrite(txPin, LOW); // Activate the RFID reader
digitalWrite(ledPin, LOW); // Turn off debug LED

if((val = mySerial.read()) == 10) { // check for header
bytesread = 0;

while(bytesread<10) { // read 10 digit code
val = mySerial.read();

if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading
break; // stop reading
}

code[bytesread] = val; // add the digit
bytesread++; // ready to read next digit
}

if(bytesread == 10) { // If 10 digit read is complete
digitalWrite(txPin, HIGH); // deactivate RFID reader
digitalWrite(ledPin, HIGH); // activate LED to show an RFID card was read
Serial.print("TAG code is: "); // possibly a good TAG
Serial.println(code); // print the TAG code
}

bytesread = 0;
delay(2000); // wait for a second to read next tag
}
}

Now I want to integrate this with a Purdy LCD, a Parallax GPS, and Xbee! I'll post what I find out for those interested.

Glad I found this post to integrate SoftwareSerial. I thought I was running out of Serial pins. Kudos to whoever wrote the SoftwareSerial library.

Also posted at: http://www.tekcrack.com/interfacing-arduino-with-parallax-rfid-reader-using-softwareserial.html

--thekidd

Software serial hangs your loop until a TAG is received.

So for example:-

void loop() {
blinkLED();
upDateLED();
readRFID();
getGPS();
}

As soon as the loop gets to readRFID(); it "hangs" so other functions in the loop, like reading gps updates every second, and displaying them on an LCD, won't resume until a TAG is scanned.

If no TAG is presented, then the loop hangs until one does.

Do a search for SoftwareSerial2, I think there's a interrupt hack in it that provides a "way out".

Thanks for pointing this horrible failure out to me before I ran into it. I couldn't find any reference to SoftwareSerial2 so I read up on interrupts on the Arduino. I didn't even realize hanging code would happen so I'm glad you pointed it out.

I ended up looking through the forums and found this post: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1207173276/0#0

The code I found ended up working out great after I read a bit about attachInterrupt(). Edited the code and moved some things around and now I believe its working great.

Code:

// RFID reader for Arduino
// Wiring version by BARRAGAN http://people.interaction-ivrea.it/h.barragan
// Modified for Arudino by djmatic
// And pieces from Arduino Playground http://www.arduino.cc/playground/Learning/PRFID
// And then modified again by thekidd
// 12.04.2008 - Added interrupt to ensure program does not hang on RFID reader.

#include <avr/interrupt.h>
#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3
#define ledPin 13

// set up a soft serial port
SoftwareSerial mySerial(rxPin, txPin);

int val = 0;
char code[10];
int bytesread = 0;

void setup() {
// define pin modes for tx, rx, led pins:
pinMode(rxPin, INPUT); // Set rxPin as INPUT to accept SOUT from RFID pin
pinMode(txPin, OUTPUT); // Set txPin as OUTPUT to connect it to the RFID /ENABLE pin
pinMode(ledPin, OUTPUT); // Let the user know whats up

// set the data rate for the serial ports
mySerial.begin(2400); // RFID reader SOUT pin connected to Serial RX pin at 2400bps
Serial.begin(9600); // Serial feedback for debugging in Wiring

// say something
Serial.println("Hello World!");

attachInterrupt(0, readRFID, CHANGE); // Setup interrupt for SOUT on RFID reader
digitalWrite(txPin, LOW); // Activate the RFID reader
}

void loop() {
// Do Something
}

void readRFID() {
digitalWrite(ledPin, LOW); // Turn off debug LED - Event triggered!
if((val = mySerial.read()) == 10) { // check for header
bytesread = 0;

while(bytesread<10) { // read 10 digit code
val = mySerial.read();

if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading
break; // stop reading
}

code[bytesread] = val; // add the digit
bytesread++; // ready to read next digit
}

if(bytesread == 10) { // If 10 digit read is complete
digitalWrite(txPin, HIGH); // deactivate RFID reader
digitalWrite(ledPin, HIGH); // activate LED to show an RFID card was read
Serial.print("TAG code is: "); // possibly a good TAG
Serial.println(code); // print the TAG code
}

bytesread = 0;
digitalWrite(txPin, LOW); // Activate the RFID reader
}
}

I hope this accomplishes what you brought up as I am still trying to grasp C/Wiring.

Now I'm wondering if I can do the same thing with the GPS. I guess not since its always sending in NEMA mode. Maybe using Parallax GPS' smart mode is the way to go but I'm going to guess that smart mode isn't integrated on all GPS units.

I know for sure that I do not want to set it up on hardware serial. I thinking I need the serial port for Xbee. Any ideas how the GPS could be setup on software serial without creating the hang ups you mentioned John? Oh and does anyone see any problems with the code?

Help is much appreciated!

Hiya, after searching and searching Im trying to figure out how to add the proper code to turn a pin on or off. ideally i'd like to control a solenoid with the correct tag, but i am brand spanking new to arduino and coding and am facing a learning curve. What I'm trying to add is something like:

if(code == 0415ED297EE)
{ // if 10 digit code is round tag
digitalWrite(ledPin, HIGH);
delay(200)
digitalWrite(ledPin, LOW);
delay(1000)
}

Any advice or suggestions on where and how to insert this are welcome.

Thanks

Nate

This will compare the first 10 characters in code to "0415ED297E"

  if( strncmp(code,"0415ED297E", 10) == 0) 
  {
     // if 10 digit code equals "0415ED297E" 
     digitalWrite(ledPin, HIGH); 
     delay(200); 
     digitalWrite(ledPin, LOW); 
     delay(1000); 
  }

Thanks for the code mem.

I have a really odd situation occurring when I use the above code I posted. If I try to use delay(); in the main loop or any of my functions with the attachInterrupt function in use, the Arduino locks up when it hits the delay code.

Is this normal? Should I be using a different way to delay events?

 // RFID reader for Arduino
// Wiring version by BARRAGAN <http://people.interaction-ivrea.it/h.barragan>
// Modified for Arudino by djmatic
// And pieces from Arduino Playground <http://www.arduino.cc/playground/Learning/PRFID>
// And then modified again by thekidd

#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3
#define ledPin 13

// set up a soft serial port
SoftwareSerial mySerial(rxPin, txPin);

int val = 0;
char code[10];
int bytesread = 0;
int speakerPin = 7;
byte names[] ={ 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C'};  
int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956};

int serByte = -1;
int ledState = LOW;
int count = 0;

void setup() {
// define pin modes for tx, rx, led pins:
pinMode(rxPin, INPUT); // Set rxPin as INPUT to accept SOUT from RFID pin
pinMode(txPin, OUTPUT); // Set txPin as OUTPUT to connect it to the RFID /ENABLE pin
pinMode(ledPin, OUTPUT); // Let the user know whats up
pinMode(speakerPin, OUTPUT); // Make a sound too

// set the data rate for the serial ports
mySerial.begin(2400); // RFID reader SOUT pin connected to Serial RX pin at 2400bps
Serial.begin(9600); // Serial feedback for debugging in Wiring

// say something
Serial.println("Hello World!");
}

void loop() {
digitalWrite(txPin, LOW); // Activate the RFID reader
digitalWrite(ledPin, LOW); // Turn off debug LED

if((val = mySerial.read()) == 10) { // check for header
bytesread = 0;

while(bytesread<10) { // read 10 digit code
val = mySerial.read();

if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading
break; // stop reading
}

code[bytesread] = val; // add the digit
bytesread++; // ready to read next digit
}

if( strncmp(code,"0415ED297E", 10) == 0) 
  {
      // if 10 digit code equals "0415ED297E" 
      digitalWrite(ledPin, HIGH); 
      delay(200); 
      digitalWrite(ledPin, LOW); 
      delay(1000);
        digitalWrite(speakerPin, HIGH);
        delayMicroseconds(tones[count]);
        digitalWrite(speakerPin, LOW);
        delayMicroseconds(tones[count]);
  }

bytesread = 0;
delay(2000); // wait for a second to read next tag
}
}

I added a piezo element to it (it's very quiet (code taken from the soundserial code from todbot bionic arduino)) to try and make a noise when the right card is passed in front. Works but could use some improvement.

BTW Thanks for the help!

Is the SoftwareSerial code dependent on the clock frequency being 16MHz, I am using a ATmega32 using the internal clock at 4MHz, but this doesnt affect the Hardware Serial

I'd like to use Softwareserial to talk to 8 different MIDI ports at the same time. MIDI is at 31,250bps, one-way serial, so only one pin per interface is required. Do you think this is possible?

Thanks a lot in advance!

I have a serial lcd that I cannot send the correct characters to. It is the DataVision A267592. 16 x 4 LCD Display Kit Cable, Display & Instructions x [Heated Area] - $9.99 : Al-Tech Electronics
It requires a odd parity data connection unless some solder that I cannot find on mine is removed. Anyone else got one of these to work?
It has a 80C51 microcontroller on it.

sounds like a "posted on the wrong spot" problem. try reposting in the hardware interfacing section...

and try a less general subject line.

I have written a piece of code that interfaces an Arduino with a Skyetek M1 mini RFiD reader. I have been developing it using a Diecimila and everything is working fine.

I want to miniturise the system now, and replace the Diecimila with an Arduino Mini Pro. When I plug the hardware into the Mini and upload the code the two devices do not appear to be interfacing correctly.

The code uses the Software Serial function to allow two of the Arduino digital pins to be used as a secondary serial port. In an attempt to debug the problem, i replaced the Skyetek M1 RFID reader with a BlueSMIRF to allow me to check to see if the code was in fact sending the data down the software serial port.

This proved to be all working and correct. So I can only assume it is a problem with either the SkyeTek M1 talking back down the software serial line, or with the code that receives the data from the Skyetek M1 and it not outputting it to the hardware serial correctly.

I have included the code I am using below, can anyone please offer any advice? I am really stuck with this!!

// File......RFiD Read - Code for IE5 to talk to Software interface
// Version 1.0
// Author Ian Culverhouse
// Date 13th July 2009
// Purpose - To implement the SkyeTek M1 RFiD Module with the Arduino to read 13.56mhz RFiD IC


// Revision History -

// Imports --------------------------------------------------------------

#include <SoftwareSerial.h>                       // Initialise Software Serial


// I/O Definitions ------------------------------------------------------

#define txPin 5                                   // Software serial tx pin
#define rxPin 4                                   // Software serial rx pin
#define ledPin 13                                 // LED pin
#define successRead 9                             // Indicate successfull read.

// Initialise the Software serial port ----------------------------------

SoftwareSerial mySerial(rxPin, txPin);
#define d_size 64                                 // create some space for receiving data from tag reader
byte readerData[ d_size];                         // Sets up Array for the tag ID to be held in

// Setup the Pins & Ports -----------------------------------------------

void setup()  {
                                                   // define pin modes for tx, rx, led pins:
pinMode(rxPin, INPUT);                             // pin mode for the software serial rx pin
pinMode(txPin, OUTPUT);                            // pin mode for software serial tx pin
pinMode(ledPin, OUTPUT);                           // pin mode for the ledpin
pinMode(successRead, OUTPUT);                     // pin mode for successfull read


mySerial.begin(9600);                              // set the data rate for the serial ports
Serial.begin(9600);                                // sets data rate for the hardware serial port
Serial.println("Initialised Serial");                          //prints the word begin to the hardware serial port as a trace that the system is working
digitalWrite(ledPin, HIGH);                        // Sets the ledpin to high, indicating the system is active

}

//  Program code ----------------------------------------------------------

void loop(){

  // first step is to query the reader for a tag.  Send a 001400 command to it.  If no tag is found then it will lopp back
  // and try again.  When a tag is found the code will store the entire response from the reader.

 int in_count;                                      // defines variable in_count
 mySerial.print( 0x0d, BYTE);                       //send CR
 mySerial.print("001400");                          // Send read command to M1 mini
 mySerial.print( 0x0d, BYTE);                       //send CR


 byte ch = mySerial.read();                         // get first byte of answer from reader


                                                   // if it was not a LF (0x0a), send read command again if it was,
                                                   // store all bytes until ending LF was received
 if (ch == 0x0a)                                   // if first byte received is a line feed enter if statement
 {
   ch = mySerial.read();                           // read the first byte into the variable ch
   in_count = 0;                                   // set in_count to 0 - used as a counter for the array
       while( (ch != 0x0a) && ( in_count < d_size))// while the byte being received is not a line feed and the eeprom is not full enter while loop
         {
            readerData[in_count] = ch;             // the array dta is filled with the value of ch
            in_count++;                            // in_count is increased by 1
            ch = mySerial.read();                  // the next character from the serial port is read in and ch is assigned the value

         }
  }

  //if (readerData[0] != '9') {                  // check to see if first byte of data is a 9.  If it is then
                                                    // error code 94 has been sent from reader, indicating that there is no
                                                    // in range of reader, go back and try again.

        for ( int i = 0; i < in_count; i++) Serial.print(readerData[i], BYTE);

        Serial.println();

  //}


}

Try NewSoftSerial instead.