Pages: [1]   Go Down
Author Topic: SoftwareSerial in Arduino IDE V1.0  (Read 1779 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So I have been working on this project for a few weeks now and it contains 2 arduinos and an ethernet shield.  Long story short I am very close to running out of room on the arduino with the ethernet shield and need to send a string containing information for more functionality to another arduinio.  I intend on doing this with softwareSerial.  However, I cannot seem to get it to function.  I have tried many other workarounds such ass Easy Transfer and I2C, but none of these work. 

The first arduino has an Ethernet shield and has its own power source.  Pin 2 is connected to Pin 3 of the second arduino, Pin 3 is connected to Pin 2 of the other arduino and the arduinos are connected with a common ground.  The second arduino also has its own power source.  (I have also tried powering the second arduino with the first, but it produces the same result.)

basically whenver I attempt to send a char array from the first arduino to the second, the second does not recgonize that there is incoming data.  Can anyone help me with this bug?  Code below (ethernet code removed).



Arduino 1
Code:
#include <SoftwareSerial.h>
char sBuffer[50];
SoftwareSerial ss(2,3);

void setup()
{
  Serial.begin(9600);
  ss.begin(9600);
 
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();

  //Start SD
  pinMode(10, OUTPUT);
  SD.begin(4);
}

loop()
{
//do stuff with the ethernet lib...
//generate sBuffer char array.....
sendMessage();
}

void sendMessage()
{
  for(i=0;i<50;i++)
  {
    ss.write(sBuffer[i]);
  }
 
  //this was also attempted
  //sbuffer is null terminated...
  /*
  ss.write(sBuffer[i]);
  */
}



Arduino 2
Code:
#include <SoftwareSerial.h>
void setup() {
  // begin serial:
  Serial.begin(9600);
  ss.begin(9600);
}

loop()
{
if(ss.available())
{
Serial.write(ss.read());
}
}


In both cases the baud rate of 4800 was also attempted.
the char array that I am passing looks like this:

"?house=A&dev=00&ctrl=1"

(P.S. If you guessed x10, you are correct! smiley)

I cannot use the onboard serial because I also need to interface to a computer.
Any help would be great!
Thanks
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 74
Posts: 2209
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

When talking tbetween arduinos, using small nibbles of bits and bytes to send binary type data is far more efficient. Less to send & less room needed in ram. An arduino doesn't read text so the receiving end still has to interpret the data,

also sBuffer is empty, you initialise it and send it with out defining any content. If variables are defaulted to 0 then the first character is the terminator.

Edit: hmmm,just read your post over again, if you were sending valid string data that is terminated properly, you only should be sending the actual data length, not the entire array as previous data could be in the buffer after the null.

I'm not familiar with the arduino serial library, but the library code doesn't seem to be the problem.

Specify a type for the loop variable also. ( char, int, unsigned, signed... )

Code:
 for( char i=0;i<50;i++)
  {
    ss.write(sBuffer[i]);
  }

If your code compiled this probably isn't your bug tho.

Post your actual code if the above post isn't it too. Removing stuff to make it smaller for the forum may have actually removed your bug.

Off topic:  Check out this thread for a different serial library http://arduino.cc/forum/index.php/topic,85207.0.html
« Last Edit: January 14, 2012, 04:31:22 am by pYro_65 » Logged


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

Code:
    ss.write(sBuffer[i]);
Code:
Serial.write(ss.read());
Why are you using write() instead of print()?

Is sBuffer properly NULL terminated? If not, why not? If it is, why are you looping sending one character at a time, instead of sending the whole array at once?

How do you know that the receiver is not receiving anything?
Logged

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

Here is the full code as requested.
The sBuffer is being filled previously in the code on Arduino 1 (around line 190) and right before I send it over serial, it is printed to the SerialMonitor over USB.  This is how I know its terminated properly due to the fact that I dont get garbage in the Serial Monitor.

The serial sending is at the bottom of Arduino 1 code and in a function called sendMessgeToSlave.

Arduino 1
Code:
/*
  Web Server
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * SD on 4
 * connect ground to ground
 Pin 2 connected to Pin 3, Pin 3 connected to pin 2 on other arduino
 */
#define DEBUG
#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
#include <SoftwareSerial.h>

#define resetRelay 7
#define zcPin 9
#define dataPin 8
//MAC ADDRESS CHANGED FOR ONLINE POSTING
byte mac[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
IPAddress ip(192,168,1, 62);

EthernetServer server(80);
//vars to parse http request

//HTTP request Buffer
int _readRequestSize = 50;
char readRequest[50] = "";
int requestPos = 0;
int validPage = 0;

//default URL
char baseURL[10] = "index.htm";

//Serial Buffer
int _sBufferSize=50;
char sBuffer[50];
int realSBufferSize=0;
int sendCommand=0;

//generic loop var
int i = 0;

//parsing variables
int spaceIndex = -1;
int slashIndex = -1;
int dotIndex=-1;

int lockSlash= 0;
int lockDot=0;
int lockSpace=0;

//mode for reset var.
int mode =0;


SoftwareSerial ss(2,3);

void setup()
{
  Serial.begin(9600);
  ss.begin(9600);
 
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();

  //Start SD
  pinMode(10, OUTPUT);
  SD.begin(4);

  //relay Reset
  pinMode(resetRelay,OUTPUT);
  digitalWrite(7,LOW);
  Serial.print("init Done");
}

void loop()
{
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("Client Connected\nReading Request");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;

    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //start to copy request into buffer
        if(requestPos < _readRequestSize)
        {
          readRequest[requestPos] = c;

          requestPos++;
        }

        if (c == '\n' && currentLineIsBlank) {
          //start response to client
          //reset counter
          requestPos=0;

          Serial.println("Begin Request Parser");
          //readRequest Parser
          for(i=4;i<_readRequestSize;i++)
          {
            if(readRequest[i]=='/'&&!lockSlash)
            {
              slashIndex=i;
              lockSlash=1;
            }
            else if(readRequest[i]=='.'&&!lockDot)
            {
              dotIndex=i;
              lockDot=1;
            }
            else if(readRequest[i]==' '&&!lockSpace)
            {
              //space index
              spaceIndex=i;
              lockSpace=1;
              break;
            }
          }//end for

#ifdef DEBUG
          Serial.println("Slash : Dot : Space");
          Serial.print(slashIndex);
          Serial.print(" : ");
          Serial.print(dotIndex);
          Serial.print(" : ");
          Serial.println(spaceIndex);
#endif

          //requestPos = urlLength
          if(dotIndex==-1)
          {
            Serial.println("NO URL -> Pushing Index");
            //no url given
            requestPos=10;
          }
          else
          {
            requestPos = (dotIndex+3)-(slashIndex);
          }

          //create url charArray
          char url[requestPos];

          if(dotIndex==-1)
          {
            for(i=0;i<requestPos;i++)
            {
              url[i] = baseURL[i];
            }
          }
          else
          {
            for(i=0;i<requestPos;i++)
            {
              url[i] = readRequest[i+slashIndex+1];
            }
          }

          //add null term
          url[requestPos]=NULL;
#ifdef DEBUG
          Serial.print("\nURL: ");
          Serial.println(url);
#endif


          if((dotIndex != -1)&&(spaceIndex != (dotIndex+4)))
          {
            Serial.println("Grabbing Env Vars");
            //grab rest of message
            requestPos = (spaceIndex) - (dotIndex+4);

            //flag to send
            Serial.println("Setting sendCommand");
            sendCommand=1;

            //copy over buffer
            for(i=0;i<requestPos;i++)
            {
              sBuffer[i] = readRequest[i+dotIndex+4];           
            }
            realSBufferSize=requestPos;
           
            //add null termination
            sBuffer[requestPos]=NULL;
          }//end if dotIndex

          //parsing for URL
          requestPos=0;
          String URL = String(url);
          URL.trim();
          if(URL.equals("resetServer.htm"))
          {
            URL = String("index.htm");
            mode=-1;
          }
 
          Serial.println("Checking for file");
          char file[URL.length()+1];
          URL.toCharArray(file,URL.length()+1);
          Serial.print(file);
          //parse here
          File doc = SD.open(file);
          if(doc)
          {
            // send a standard http response header
            Serial.println("File Found");
            client.println("HTTP/1.1 200 OK\nContent-Type: text/html\n");
            validPage=1;
            while (doc.available())
            {
              client.print((char)doc.read());
            }
            doc.close();
            if(validPage && sendCommand) sendMessageToSlave();
          }
          else
          {
            Serial.println("File not found");
            client.println("HTTP/1.1 404 Not Found");
            validPage=0;
          }

          //exit client loop
          break;
        }

        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }

    // give the web browser time to receive the data
    delay(1);
    // close the connection:
#ifdef DEBUG
    Serial.println("\nClient disconnected");
#endif
    client.stop();

    resetGlobalVars();
  }//end client

  //reset
  if(mode==-1)
  {
    mode=0;
    digitalWrite(resetRelay,HIGH);
  }
}

void resetGlobalVars()
{
  Serial.print("Resetting Golbal Vars");
  for(i=0;i<_readRequestSize;i++)
  {
    readRequest[i]=NULL;
  }

  for(i=0;i<_sBufferSize;i++)
  {
    sBuffer[i]=NULL;
  }

  spaceIndex=slashIndex=dotIndex=-1;
  lockSlash=lockDot=lockSpace=0;
  requestPos=validPage=sendCommand=0;
}

void sendMessageToSlave()
{
  //implement soft serial to other device
  Serial.println("Send Message To Slave!");
  Serial.print("sBuffer:\n\t");
  Serial.println(sBuffer);
  //See aprrox Line 193 for termination
  for(i=0;i<50;i++)
  {
    ss.print(sBuffer[i]);
    ss.write(sBuffer[i]);
  }
}


Arduino 2
Code:
// include the X10 library files:
#include <x10.h>
#include <x10constants.h>
#include <SoftwareSerial.h>

#define zcPin 9         // the zero crossing detect pin
#define dataPin 8       // the X10 data out pin
#define repeatTimes 3   // how many times each X10 message should repeat

x10 myHouse =  x10(zcPin, dataPin);
SoftwareSerial ss(2,3);

void setup() {
  // begin serial:
  Serial.begin(9600);
  ss.begin(9600);
 
  //set internal pullup
  pinMode(zcPin, INPUT);
  digitalWrite(zcPin, HIGH);

  // Turn off all lights:
  myHouse.write(A, ALL_UNITS_OFF,repeatTimes);
}

void loop()
{
  Serial.println("loop");
  if(ss.available())
  {
     Serial.print("Message Avail");
     Serial.print(ss.read());
     Serial.write(ss.read());
  }
}

An example of what the first arduino gets is
"http://192.168.1.62/lights.htm?house=A&dev=02&ctrl=0" --from web browser
It then extracts the url and checks for special cases and to see if the file exists on sd.. if it does it will return it to the client....
then the rest of the input containing "?house=A&dev=02&ctrl=0" is then parsed out and stored in sBuffer.  I then calculate the length of the string and add in the null terminator being sBuffer[end] = NULL;  This is around line 193 on arduino 1.

**The other thing that I may be causing the issue, but I cannot seem to find if it actually is, and I dont believe it is, is the var requestPos.  I use this var to store different things at different times as a work around to help with the flash storage issue I am having.  But like I said, I could not find anything wrong with it.

I do know that more or less I will actually be getting ascii encoding over this line and reading on arduino 2.  I have managed this before.  My issue is that the Message Avail is never actually printed, thus the second arduino is not getting the message. So this means, to me at least, that I am not getting softSerial to work properly.

Thanks
Logged

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

Quote
An example of what the first arduino gets is
A link on your local network is pretty much useless to the rest of us...

Code:
  Serial.println("Send Message To Slave!");
  Serial.print("sBuffer:\n\t");
  Serial.println(sBuffer);
  //See aprrox Line 193 for termination
  for(i=0;i<50;i++)
  {
    ss.print(sBuffer[i]);
    ss.write(sBuffer[i]);
  }
The Serial print is not printing the whole array. Why are you ss printing and writing the whole array?

Code:
  if(ss.available())
  {
     Serial.print("Message Avail");
     Serial.print(ss.read());
     Serial.write(ss.read());
  }
If there is a byte to read, read both of them. Well, that's not how it's usually done. Rather, that's not how it's correctly done.

Logged

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

There is noting I can really do about the link....  That how this project works.. it uses the ethernet shield.  That url is read in from the client as a HTTP request..... i could post that

the Serial.print is printing the whole array (up until the NULL termination)  that is how the Serial Print in arduino IDE 1.0 (and if i remember most standard c libs) work.  It is printing what I expect: "?house=A&dev=02&ctrl=0" after the zero there is a null termination.  This causes the char array to act like (how i see it) a streaming string.  It will stop at the Null termination.

As for the 2nd arduino read, one of those are supposed to be commented out as well as the same version in the arduino 1 code.  I dont know why the comment didnt copy.  but they essentially should be XOR'd.


Below is the http request that the ethernet server will get... the lights.htm is indeed located on the sd card and the client receives the HTTP 200 version of the request

Quote
GET /lights.htm?house=A&dev=02&ctrl=1 HTTP/1.1
Ho

That is the readRequest buffer after it fills.. and was generated but the URL:
Quote
192.168.1.62/lights.htm?house=A&dev=02&ctrl=1

Let me know if any more clarity is needed.

Thanks

Logged

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

Quote
the Serial.print is printing the whole array (up until the NULL termination)  that is how the Serial Print in arduino IDE 1.0 (and if i remember most standard c libs) work.  It is printing what I expect: "?house=A&dev=02&ctrl=0" after the zero there is a null termination.  This causes the char array to act like (how i see it) a streaming string.  It will stop at the Null termination.
That was my point. The printing stops at the NULL. But, that is NOT haw you are sending serial data. You are sending the entire array - all 50 elements.

If you comment out the x10 stuff on Arduino 2, does that change the behavior of Arduino 2?

If you connect Arduino 1 to the hardware serial pins on Arduino 2, and blink and LED when you get serial data, does the LED ever blink?
Logged

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

I am sending all 50 chars to try to save some consistency between the 2 sketches. this way I know that I always need to read 50 chars and I dont need to send a msg head...

for some odd reason it started to work and the message is now going across the softSerial.  I think what might have happened as Paul S commented on commenting out the x10.  This gave me the idea to connect the x10 transceiver up to the wall outlet.  Whet i didn''t know was that the x10 transceiver needed to be connected in order to actually execute the lib code.  I thought there was a timeout associated with the x10 lib.  At the time of posting this I did not have x10 transceiver powered up.  I had the cables in place, but the x10 transceiver was not plugged in.  Therefore the command in the setup was never being executed and was halting the sketch.

Also.  Paul S... do you think I should only send up to the NULL terminator in the sBuffer to the other arduino?  It would make the code a little bit more robust.  This being stated... is there some type of malloc that I could use to dynamically handle the char array. or should I just make my buffers on the first Arduino larger?

Thanks for all of your help
Logged

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

First off, I'm glad that things are working (better) for you.

As far as sending the whole array, there are a couple of ways to deal with that. You could send the length first, then the valid data. Less data is transmitted this way, which makes the process faster. The only potential issue with this is that serial data transmission is not guaranteed, so the number of characters actually received will not necessarily the number sent.

The other way is to not worry about the length. Start and end the packet sent with some markers. Read and store the data starting when the start marker arrives, and ending when the end marker arrives. Some sample code to read delimited packets:
Code:
#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

Quote
is there some type of malloc that I could use to dynamically handle the char array. or should I just make my buffers on the first Arduino larger?
There are two problems with trying to dynamically allocate data on the first Arduino. The first is that the data is coming from an ethernet connection, and you have no ideal, before the data starts to arrive, how much there is going to be. Even if you did, there is not a lot of memory available on the Arduino, so memory fragmentation is a real problem when dynamic memory allocation occurs. There is no easy way to rearrange the dynamically allocated memory, to reclaim small fragments.

Properly sizing the static array on the Arduino is the best approach.
Logged

Pages: [1]   Go Up
Jump to: