doubt about SoftwareSerial, communication between 2 serial ports in 1 arduino

Hi everyone,

I have a question about SoftwareSerial,
I can not make my code work, I tried everything that I know, but still I have not managed to get my code to work, I think the problem with the code will be very simple, but I can not decipher it, I'll add my code, who can help me?

that is my code:

#include <SoftwareSerial.h>

SoftwareSerial portOne(16, 10);
SoftwareSerial portTwo(14, 15); // RX, TX

const int BTest = 3;
const int LedOn = 9;
const int LedP = 8;
bool estadoActual = false, estadoUltimo = false, contador = false;

char a, b;

void setup()
{
Serial.begin(9600);
portOne.begin(9600);
portTwo.begin(9600);
pinMode(BTest, INPUT);
pinMode(LedOn, OUTPUT);
pinMode(LedP, OUTPUT);
}

void loop()
{
estadoActual = digitalRead(BTest);
delay(50);

if (estadoActual && !estadoUltimo)
{
contador = !contador;

if (contador)
{
Serial.println("ON");
Serial.println(contador);
portOne.listen();
portOne.print("2");

digitalWrite(LedP, HIGH);

a = portOne.read();
if (a == '1')
{
digitalWrite(LedOn, LOW);
}
}
else
{
Serial.println("OFF");
Serial.println(contador);
portTwo.listen();
portTwo.print("1");
digitalWrite(LedP, LOW);

b = portTwo.read();
if (b == '2')
{
digitalWrite(LedOn, HIGH);
}
}
}
estadoUltimo = estadoActual;
}

In the arduino connections, I connected 15Tx (portTwo) with 16Rx (portOne) and 10Tx (portOne) with 14Rx (portTwo).

I am using an arduino Pro Micro.

thanks and regards.

I think the problem with the code will be very simple

It is. You haven't a clue how software serial works. You can NOT listen on one port while another port is talking. You can't listen to two ports simultaneously, either.

So, what goes out portOne falls on deaf ears.

You should NEVER call read() without having called available() first, to make certain that there is stuff to read.

But how would it be?

Could you show me an example please?

Thanks ):

To make it easy for people to help you please modify your post and use the code button </>

so your code looks like this

and is easy to copy to a text editor. See How to use the Forum

Your code is too long for me to study quickly without copying to a text editor.

Also please use the AutoFormat tool to indent your code for easier reading.

As @PaulS has said it is not practical to use 2 instances of SoftwareSerial. If you need that many Serial connections you should really use an Arduino Mega which has 3 spare HardwareSerial ports.

You may be able to use one instance of SoftwareSerial alongside AltSoftSerial or NeoSWSerial.

...R
Serial Input Basics - simple reliable ways to receive data.

You should NEVER call read() without having called available() first, to make certain that there is stuff to read.

I do and it works! Hint = Serial.read returns an int even though the char is only a byte. If you use (for example) stdio,h you will find the equivalent of read also returns an int and it does so for the same reason.

Mark

I think the point is that you need to make sure that you are actually reading data and not an empty serial line.

Yes that is the point. But there are is more than one way to skin a cat, and many IO interfaces do not support anything like "available".

Worth a good look is the peek method.

Mark

holmes4:
I do and it works! Hint = Serial.read returns an int even though the char is only a byte. If you use (for example) stdio,h you will find the equivalent of read also returns an int and it does so for the same reason.

Yup. Many other interfaces have the same semantics (even if they don't return an int). Rather than the "is something available? ok, give it to me" idiom that is encouraged by Serial.available(), most C and C++ interfaces are of the form "give me something if it's available or an invalid value if it's not". It's usually better (more elegant, less code) to try something without asking for permission to do it first.

See fopen(), getchar(), fgets(), scanf(), std::getline() (C++), etc.

It's usually better (more elegant, less code) to try something without asking for permission to do it first.

That may be true (and I do NOT concede that it is) ONLY if you test that you got something usable afterwards. Since you need to perform a test anyway, I see no advantage in having tried to do something that you could have known, in advance, would fail to produce useful results.

christop:
Rather than the "is something available? ok, give it to me" idiom that is encouraged by Serial.available(), most C and C++ interfaces are of the form "give me something if it's available or an invalid value if it's not". It's usually better (more elegant, less code) to try something without asking for permission to do it first.

I can't imagine how there can be less code if you have the check the received data to see if it is valid. That sounds like just as much effort as checking in advance.

And IMHO the human-logic of the problem is easier to see if you check first - if (Serial.available() ... is very obvious.

...R

PaulS:
You should NEVER call read() without having called available() first, to make certain that there is stuff to read.

If using void serialEvent() subroutine to read data from a UART Port, do we still need to execute the Serial.available() before executing the byte x = Serial.read() instruction? The serialEvent() subroutine is automatically called upon (provided it has been defined) when a databyte (character) arrives at the UART Port?

If using void serialEvent() subroutine to read data from a UART Port, do we still need to execute the Serial.available() before executing the byte x = Serial.read() instruction?

Yes.

The serialEvent() function will (uselessly) be called when there is at least one byte of serial data to be read, at the end of loop(). If your serialEvent() function needs to read more than one byte, it needs to make sure that there IS data to read (at least check that what it read was usable).

PaulS:
That may be true (and I do NOT concede that it is) ONLY if you test that you got something usable afterwards. Since you need to perform a test anyway, I see no advantage in having tried to do something that you could have known, in advance, would fail to produce useful results.

Robin2:
I can't imagine how there can be less code if you have the check the received data to see if it is valid. That sounds like just as much effort as checking in advance.

And IMHO the human-logic of the problem is easier to see if you check first - if (Serial.available() ... is very obvious.

...R

Alright, I admit it's not less code to do it the idiomatic C/C++ way:

int c;
if ((c = Serial.read()) != -1) {
    // do something with c
}
if (Serial.available()) {
    byte c = Serial.read();
    // do something with c;
}

But Serial.read() already checks if any data is available, so calling Serial.available() beforehand is redundant.

It's also far more idiomatic in C/C++ to try an operation and check if it failed than to ask for permission before trying:

FILE *fp = fopen("file.txt", "r");
if (fp) {
    // do something with fp
}
int c;
if ((c = getchar()) != EOF) { // EOF is usually defined as -1
    // do something with c
}
std::string line;
if (getline(std::cin, line)) {
    // do something with line
}

christop:
But Serial.read() already checks if any data is available, so calling Serial.available() beforehand is redundant.

Is the execution of Serial.available() function really redundant?

1. If we look at the architecture of the UART Port of the ATmega328P MCU, we observe that the arrival of a character at the receiver section (Receiver Data Register) is indicated by putting Logic High at the RXC0 bit of the UCSR0A Register.

Therefore, we must be sure that there is a data in the data register before we make a read operation on the data register. This can only be known by reading RXC0 bit of the UCSR0A Register. That means that we have to execte the following instructions:

if(bitRead(UCSR0A, 7) == HIGH)
{
   byte x = UDR0;
}

The Arduino equivalent above codes could be conceptually related with the following Arduino Codes: for the above are: Edited

void loop()
{
   if(Serial.available()>0)
   {
      byte x = Serial.read():
   }
}

OR

void serialEvent()
{
   byte x = Serial.read();
}

The MCU calls upon the serialEvent() subroutine (provided it has been defined) at the end of loop() function whenever a character arrives at the receiver section of the UART Port.

@Delta_G

I have the understanding that the high level representation of a process has a relationship with the activities that is going on at the hardware level. If RXENO bit of the UCSR0B Register is made active, the RXC0 flag bit will generate an interrupt indicating that a valid character is present in the UDR0 Register. The high level codes bring it into the Circular Buffer (which I see as a FIFO Buffer). If interrupt is not used, the high level codes must poll the RXCO bit to bring in the character from the UDR0 Register into the Circular Buffer.

You have exposed the essence of the Serial.avaiable() function, which has acted as a tonic (at least to me) for correcting my misunderstanding. However, this is not fair to accuse me that I have been spreading misinformation; people always apply their common sense, and they react accordingly. I have expressed what I have thought to be conceptually correct; if incorrect, it can always be corrected by the veterans of the Forum.

When someone says that the Serial.read() function checks the availability of character and the use of Serial.available() is redundant, we don't see much reaction.

GolamMostafa:
The MCU calls upon the serialEvent() subroutine (provided it has been defined) at the end of loop() function whenever a character arrives at the receiver section of the UART Port.

Nope. It calls serialEvent when is data available, not when it became available.

GolamMostafa:
However, this is not fair to accuse me that I have been spreading misinformation;

I think it's a fair accusation.

@Delta_G

I think you accidentally pulled the wrong function from HardwareSerial, availableForWrite instead of available.

int HardwareSerial::available(void)
{
  return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
}

Delta_G:
I was looking at the right function and somehow copied the wrong one and didn't look back.

Why? Because, @GolamMostafa is supposed to know it! So much anger fused with so much affection that the Wallet is lost!

The second most useful method of the HardwareSerial class, after read, is peek()

This allows you to look and the next byte/char in the buffer, this can be very very useful when parsing.

Mark

Delta_G:
The only difference is that read is only seeing that something is there, while available() is actually getting a number of how many things there are.

To read a character from the InputBox of the Serial Monitor, I played with the following three block of codes. Codes of Block-A and Block-B have correctly caught the character coming from the Serial Monitor; but, not the codes of Block-C. The result of this observation had led me to align the role of the Serial.available() function with that of the Receive Complete (RXC0 bit of UCSR0A Register) signal. Not every questioner/poster possesses the ability to go through the cryptic/bureaucratic styled documents of the Library File(s). The respected veterans are there to fill up this gap.

Block-A Codes:

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

void loop()
{
  if(Serial.available()>0)
  {
    byte x = Serial.read();    //correctly catches the character A coming from SM
    Serial.print(x, HEX);     //prints 41 (ASCII Code of A)
  }
}

Bock-B Codes:

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

void loop()
{

}

void serialEvent()
{
  byte x = Serial.read();    //correctly catches the character A coming from SM
  Serial.print(x, HEX);     //prints 41 (ASCII Code of A)
}

Block-C Codes:

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

void loop()
{
  byte x = Serial.read();  //does not catch the character A Coming from SM
  Serial.print(x, HEX); //keeps printing FFs
}

Can we say that codes of Block-A and Block-B are equivalent as they are producing the same result?

GolamMostafa:
The result of this observation had led me to align the role of the Serial.available() function with that of the Receive Complete (RXC0 bit of UCSR0A Register) signal.

You missed the mis in misled.

Why are you still distributing your misconceptions?