Simply trying to send an int through SoftwareSerial

Hi! I’m working on this code simply for learning how to use SoftwareSerial. I’m at the point where I’m trying to send an int from an Arduino to another as a low and high bytes, but it simply doesn’t work

My transmitter code:

/*Test 2 instances with Same TX on the receiver arduino.
   The Transmitter arduino  will send data to both instances
   and it needs to listen() to each by turn.
*/
#include<SoftwareSerial.h>


byte info1 = 0B101;
int info2 = 300;

SoftwareSerial soft1(8, 9);
SoftwareSerial soft2(5, 6);


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  soft1.begin(9600);
  soft2.begin(9600);
}


void loop() {
  //SEND SOFT1 DATA
  soft1.println(info1);
  Serial.println(info1);
  delay(2000);

  //SEND SOFT2 DATA
  byte h = highByte(info2);
  byte l = lowByte(info2);
  soft2.print(h, BIN);
  soft2.print(l, BIN);
  Serial.println(h, BIN);
  Serial.print(l, BIN);
  Serial.println();
  delay(2000);

}

My receiver code:

#include <SoftwareSerial.h>


SoftwareSerial portOne(8, 9);

SoftwareSerial portTwo(5, 6); //FONCTIONNNE AVEC LES 2 TX À 9.

int c;

void setup() {

  Serial.begin(9600);
  portOne.begin(9600);
  portTwo.begin(9600);
}

void loop() {
  
/* Data receiving on portOne masked until I figure out how to make portTwo work.
  portOne.listen();
  while (portOne.available() == 0) {}
  while (portOne.available() > 0) {
    Serial.println("Data from port one:");
    char inByte = portOne.read();
    Serial.print(inByte);
    Serial.println();
  }*/
  
  portTwo.listen();
  while (portTwo.available() < 1) {}

  if (portTwo.available() > 1) {
    Serial.println("Data from port two:");
    byte h = portTwo.read();       //read those two bytes back to back!
    byte l = portTwo.read();
    c = (h << 8) + l;
    Serial.println(c);
  }

}

Here is the output on the Serial monitor… I expected 300 to be printed (value of int info2 on the transmitting Arduino) but I receive a batch of huge numbers every 4 seconds (the low and high bytes of info2 are supposed to be sent only once every 4 seconds). Looks like something’s really wrong, I even had a ‘‘Daa’’ spelled instead of ‘‘Data’’ on the serial monitor as you can see down here. Also, I wonder why they are printed as batches of 3 Data from port two: number, since from what I understand, I should be reading only 2 bytes every 4 seconds.

Daa from port two:
12337
Data from port two:
12592
Data from port two:
12593
Data from port two:
12337
Data from port two:
12592

There might be more wrong (in transmitter and receiver) but the transmitter sends a binary text representation of the data.

Try the write() method to just send the bytes; e.g.

soft1.write(h);
soft1.write(l);

@OP

1. This is the setup of UNO+NANO using Soft UART Ports
suart-2.png

2. Your codes are modified as per Post#1 and executed. Data exchange happens as expected.
Transmitter/UNO Codes

#include<SoftwareSerial.h>
byte info1 = 0B101; //0x05
int info2 = 300;//0x012C : 0000 0001 0010 1100

SoftwareSerial soft1(8, 9);
SoftwareSerial soft2(5, 6);


void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  soft1.begin(9600);
  soft2.begin(9600);
}


void loop() 
{
  //SEND SOFT1 DATA
  soft1.println(info1);
  Serial.println(info1);//5
  delay(2000);

  //SEND SOFT2 DATA
  byte h = highByte(info2);
  byte l = lowByte(info2);
  soft2.write(h); //soft2.print(h, BIN);
  soft2.write(l);//soft2.print(l, BIN);
  Serial.println(h, BIN);//1 = 0000 0001 
  Serial.println(l, BIN);//101100 = 00101100 = 2C
  Serial.println();
  delay(2000);

}

Receiver/NANO Codes:

#include <SoftwareSerial.h>
SoftwareSerial portOne(8, 9);
SoftwareSerial portTwo(5, 6); //FONCTIONNNE AVEC LES 2 TX À 9.
int c;

void setup() 
{
  Serial.begin(9600);
  portOne.begin(9600);
  portTwo.begin(9600);
}

void loop() 
{
  portTwo.listen();
  while (portTwo.available() < 1) {}

  if (portTwo.available() > 1) 
  {
    Serial.println("Data from port two:");
    byte h = portTwo.read();       //read those two bytes back to back!
    byte l = portTwo.read();
    c = (h << 8) + l;
    Serial.println(c);
  }
}

sm-9.png

suart-2.png

sm-9.png

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino communication

You can send data in a compatible format with code like this

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

…R

SoftwareSerial can only receive from one instance (at a time). You cannot simply read from one and then the other. To switch back and forth between which instance to wish to read from. you must use the functions listen and stopListening. If in doubt, there's another function called isListening that will tell you who's got control of the receive capabilities.

It never hurts to learn about the libraries you choose to use.

GolamMostafa:
@OP

1. This is the setup of UNO+NANO using Soft UART Ports
suart-2.png

2. Your codes are modified as per Post#1 and executed. Data exchange happens as expected.
Transmitter/UNO Codes

Yes it works!! I can't believe I didn't try this I must have tried it on the receiver code only.. But everything's fine now thanks a lot!

DKWatson:
SoftwareSerial can only receive from one instance (at a time). You cannot simply read from one and then the other. To switch back and forth between which instance to wish to read from. you must use the functions listen and stopListening. If in doubt, there's another function called isListening that will tell you who's got control of the receive capabilities.

It never hurts to learn about the libraries you choose to use.

Isn't this what I've done in my code?

Ok now it might be more of a feasibility question, but I’ve brought this code we just corrected to a real project. The objective is to always be listening to another Arduino via softwareSerial, because someone will be able to input data to the receiver through the transmitter Arduino. However, there is a SONAR sensor in this project that requires serial comm. We wanted to keep the hardware serial for debugging/comm with the computer, so I would need to switch between softwareserial ports to listen to the transmitter Arduino and to listen to the SONAR. I’ve tried to make the lapse during which I listen to the SONAR as short as possible, but still half the data I receive is “altered”. Note that I kept the same practice transmitter code and I’m supposed to receive 300 every 4 seconds

Here is the function to read the Sonar which switches listen()ing. The rest of the program is just declaring the 2 softwareSerial instances and running this function in the loop + a PID and other sensors, which have nothing to do with softSerial.

void readSonar() {

  /*  delay(90); // debug only
     altitude = 123;  // debug only */

  const int BUFF_SIZE = 8;  // Set buffer size for data from Ping. 8 is the number of bytes to read from the Altimeter on each reading
  char ASCII_Altitude[BUFF_SIZE];  //this is the buffer to store incoming bytes in with readBytesUntil(). 8 bytes of data come from altimeter as ASCII.

  //MAKE SURE IT'S EMPTY BEFORE LISTENING TO SONAR
  if (toBoatSerial.available() != 0) {  //boat arduino sends ints so 2 bytes must be available
    while (toBoatSerial.available() < 2) {}
    Serial.println("Data from the boat");
    byte h = toBoatSerial.read();       //read those two bytes back to back!
    byte l = toBoatSerial.read();
    setPoint = (h << 8) + l;
 
    Serial.print(" ");
    Serial.println(setPoint);
  }

  altimeter.listen();  //When using two software serial ports, you have to switch ports by listen()ing on each one in turn
  //while(altimeter.available()) {}  //wait for data
  if (altimeter.available() > 0) {
    //Variable types:   readBytesUntil(char, char[] or byte[], int);  
    altimeter.readBytesUntil('\n', ASCII_Altitude, BUFF_SIZE); // '\n' means: LF (meaning line feed) char at end
    altitude = atoi(ASCII_Altitude); //We want to convert the string ASCII_Altitude into integer, to store it in the altitude variable and send it to the other Arduino via Serial
  }
  toBoatSerial.listen();
  
  //SEND DATA TO BOAT ARDUINO
  toBoatSerial.print(altitude);
}

Here’s what I’m receiving:

Data from the boat
 300.00
Data from the boat
 16385.00
Data from the boat
 -511.00
Data from the boat
 300.00
Data from the boat
 -30471.00
Data from the boat
 300.00
Data from the boat
 300.00

So I just want to know if this is as good as it gets and my only option is using the hardware serial or there’s some coding gymnastics I could do to optimize this? Thanks again folks

I think I haven't been clear enough on my last post. My problem is by listening to the altimeter softwareserial, i often miss incoming data from the software serial toboatserial. I tried to minimize the time during which I stop lisyening to the boar serial and start listening to the altimeter, but I still miss like half of the information coming from toboatserial. Should I resign to connecting the altimeter to the hardeare serial? Thanks

I wasn't aware that you could listen to another port without stopListening to the previous. So if it works, thanks for that. There are many other issues with SoftwareSerial, mostly the fact that it takes ownership of all the PCINT vectors which prohibits other functions/libraries from using them. Some time ago I chopped the library into three pieces, one for each of PORTs B, C and D on the 328. These work independent of each other and only bogart the one port. As long as your Tx/Rx pins are on the same port you can have the three instances running concurrently, all able to be monitoring for receive. The way SoftwareSerial works however, is that it still blocks while receiving data so there's no way around that.

You can however, write your own non-blocking, interrupt-driven version that uses timer2 to trigger bit read/write. This works fine for multiple ports (up to about 3/4 at 38400), but its a bit of work.

A final option I'll mention is to mirror the receive pins onto unused pins and monitor these for when the signal goes low (start bit) and trigger your listen to the port that needs attention.

DKWatson:
A final option I'll mention is to mirror the receive pins onto unused pins and monitor these for when the signal goes low (start bit) and trigger your listen to the port that needs attention.

That looks easier than writing my own library (I will read on how to write libraries and ser if some versions of softserial that xould help me exist, is there a data bank of custom libraries of some sort)
anyway, im not sure how to mirror the rx. Some wire would go from arduino to another and digitalwrite as I serial.print?

I'm thinking you could save yourself a lot of grief by moving to a platform that supports multiple Hardware Serial ports. Maybe a Mega. Or, a Teensy 3.2 for some real processing power.