Software Serial Rx/Tx (Tx not providing useful data)

This simplified code:

#include <SoftwareSerial.h>

SoftwareSerial SSerial(10, 11); // RX, TX

void setup() {
  SSerial.begin(9600);
  Serial.begin(9600);
}


void loop() {
  String content = "";
  char character;

  while(SSerial.available()) {
    character = SSerial.read();
    content.concat(character);
  }

  if (content != "") {
    Serial.print(content);
  }
}

The pins are rx:10, tx:11, because it’s a Mega ADK:

Not all pins on the Mega and Mega 2560 support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69

Produces sensible GPS data (although no fix as it can't see sky):

$GPRMC,141227.080,V,,,,,0.00,0.00,080318,,,N44
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N
32
$GPGGA,141228.080,,,,,0,0,,,M,,M,,4C
$GPGSA,A,1,,,,,,,,,,,,,,,1E
$GPRMC,141228.080,V,,,,,0.00,0.00,080318,,,N
4B
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N
32
$GPGGA,141229.080,,,,,0,0,,,M,,M,,4D
$GPGSA,A,1,,,,,,,,,,,,,,,1E
$GPRMC,141229.080,V,,,,,0.00,0.00,080318,,,N
4A
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N
32
$GPGGA,141230.080,,,,,0,0,,,M,,M,,45
$GPGSA,A,1,,,,,,,,,,,,,,,1E
$GPRMC,141230.080,V,,,,,0.00,0.00,080318,,,N
42
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N
32
$GPGGA,141231.080,,,,,0,0,,,M,,M,,44
$GPGSA,A,1,,,,,,,,,,,,,,,1E
$GPRMC,141231.080,V,,,,,0.00,0.00,080318,,,N
43
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N
32

If I change it to the following (add 'SSerial.print(content);' after the hardware serial print to console):

#include <SoftwareSerial.h>

SoftwareSerial SSerial(10, 11); // RX, TX

void setup() {
  SSerial.begin(9600);
  Serial.begin(9600);
}


void loop() {
  String content = "";
  char character;

  while(SSerial.available()) {
    character = SSerial.read();
    content.concat(character);
  }

  if (content != "") {
    Serial.print(content);
    SSerial.print(content);
  }
}

It produces this:

G MY⸮ 9&⸮Sj
$⸮5 ⸮⸮.S⸮&LU⸮⸮0⸮b⸮ i K⸮⸮2 HGPVTG,0.00,T,,M,0.00,N,\⸮-⸮⸮⸮⸮⸮$G ⸮њ⸮⸮ &⸮⸮⸮⸮ &%SK⸮X⸮5":A M ⸮A⸮bĉ⸮⸮⸮⸮JL
$AI ⸮⸮ r⸮‚b⸮⸮,,⸮⸮ ⸮⸮NKN4 ⸮AYu &U⸮⸮0.9⸮r )⸮Ji⸮j $⸮G ⸮h⸮⸮r⸮⸮ ⸮⸮⸮ &%S⸮⸮,,*4B $G⸮ ⸮⸮⸮⸮⸮⸮⸮JL⸮ $GPRMC,141359.ᱱbb &&LK⸮⸮18X⸮D⸮H⸮ ⸮K⸮0Q⸮j⸮ ⸮br⸮0.00,K,N*32 $G ⸮⸮т⸮ &⸮⸮⸮⸮ ⸮K⸮ !!TP⸮,1,,,,⸮⸮bbbĉ9LQ $GI5 ⸮⸮ ⸮r⸮‚b⸮⸮,X⸮⸮ ⸮ ⸮'KN*n) AEu L⸮⸮M,⸮⸮r⸮r )Ji⸮j $G ⸮Ѣ⸮⸮ &⸮⸮⸮⸮ &⸮K⸮SA!TP⸮,1,,,,⸮⸮bbb⸮⸮9LQ $GI5 ⸮⸮ ⸮r⸮‚b⸮⸮,X⸮⸮ ⸮ ⸮'KN*l) AEu L⸮⸮,0⸮⸮r Ji⸮j
$G ⸮⸮т⸮ '⸮⸮⸮⸮ ⸮⸮⸮⸮2 HGPGSA,A,⸮bbĉ⸮⸮⸮9LQ

Both outputs are from the IDE monitor, I can understand if the output (tx) is not in the correct format but I can’t see why the serial monitor output is affected by the change above. Can you see what I’m missing?

The requirement is send non-GPS data through an existing RF system. To read GPS data on softwareserial rx, substitute a sensor reading into the lat/log values in the data, then send the substituted data out on tx. The sensor read, NMEA decode and substitution bit is all working.

At this stage I want to receive the NMEA data on rx and forward it straight out on tx. Thank you for advice.

software serial ?? why ?
Don't your mega adk have many hardware serial ports ?

Software Serial does not buffer incoming characters.

So when you do a SSerial.read() it starts reading from a pin, not from a buffer.

When the sender is halfway a byte, you read half a byte == corrupted data.

SoftwareSerial is a crippled piece of software. During the send and reception of a complete byte (!) all interrupts are blocked (remember that the reception of a byte depends on an interrupt to happen at the correct time). As you don't receive single bytes but a complete string and then send that complete string using the same crippled SoftwareSerial the start point in time of a byte from the GPS will almost never be hit and all bytes are garbage.

To sum it up: as knut_ny already pointed out, it's stupid to use a badly written software emulation if you have 4 hardware serial interface available.

Thanks for your replies, and understood. Got used to interrogation/response/move-on type sensors, should've thought.

The megaADK was handy. The plan, for size mainly, was to run an attiny84 with a load of LowPower.powerDown sleeps to keep the battery use around half a mA.

I will go up to atmega328 and use the hardware serial, it should still fit. And, as you say, it won't work the other way.

Assuming the Mega328 doesn't mind if rx and tx are to different devices, can't see why it would, its hardware serial should do. Just need disconnect GPS/radio to update script. Will move testing to Uno so I can take the Mega328 out and put it in the breadboard when the rest is ready.

Will do some reading on how to Serial.read from buffer so I can do other things.

Thanks.

robtillart:
Software Serial does not buffer incoming characters.

So when you do a SSerial.read() it starts reading from a pin, not from a buffer.

When the sender is halfway a byte, you read half a byte == corrupted data.

Sorry, that's not correct. Just like HardwareSerial, it buffers incoming characters (code here). Internally, it "reads" a pin during a Pin Change ISR. Externally, calling read() accesses the RX buffer, not the pin.

Like others have said, use Serial1 (pins 18 & 19), Serial2 (pins 16 & 17) or Serial3 (pins 14 & 15) on the Mega ADK. On an UNO (ATmega328), you can connect the GPS to RX pin 0, and the receiver to RX pin 1. On an ATtiny84, you would have to use a USI Serial library to get UART functionality. It might fit.

And Don't use String™. There are lots of reasons. The Serial Input Basics tutorial on the Useful Links page shows one way to accumulate a character array containing one line.

...it seems to be working, atmega328 forwarding data from gps to radio with the subst. code. Will readup on character arrays and swap out the string. Thank you for the links.

Hardware serial read and write:

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

void loop() {
  String content = "";
  char character;
  
  while(Serial.available()) {
    content.concat((char)Serial.read());
  }
  if (content != "") {
    Serial.print(content);
  }
}