How to call different "Serial" in the same function ?

how would i call different serial (Serial1, Serial2 , Serial3) in the same function

i have tried different things with more or less success , but i need to use ".parseInt() , so the code below doesnt work !

just an exemple

void SerialIn(byte Port, char Input) {
   SerialBuffer[Port][index[Port]] = Input;
   Index[Port]++;
  if (Input == '}') {   // end of message received by serail1 or 2 or3
    Serial.println(SerialBuffer[Port]);
    Index[Port] = 0;
    // not possible to do ".parseInt()" on the serialbuffer right ?
  }
}

void loop() {
  if (Serial1.available() > 0) { SerialIn(0, Serial1.read()); }
  if (Serial2.available() > 0) { SerialIn(1, Serial2.read()); }
  if (Serial3.available() > 0) { SerialIn(2, Serial3.read()); }
}

this other code work with parseint , but i can't "compact" it in a single function , i would have to write the same thing 3 times but replacing "Serial1 , Serial2 , Serial3"

int ReceivedNumber[6];

void SerialIn2() {
  while (Serial2.available() > 0) {
    if (Serial2.read() == '{') {    // start of message received by serial2
      for (byte i = 0; i < 6; i++) {
        ReceivedNumber[i] = Serial2.parseInt();
        if (Serial2.read() == '}') {     // end of message received by serial2
          break;
        }
      }
    for (byte i = 0; i < 6; i++) {
      Serial.println(ReceivedNumber[i]);
    }
  }
}

void loop() {
  if (Serial2.available() > 0) { SerialIn2(); }
}

so the main question , is how would i replace SerialX in the function SerialIn2 above

The basic idea would be like below

void setup()
{
readSerial(Serial1);
readSerial(Serial2);
readSerial(Serial3);

}

void loop()
{
  // put your main code here, to run repeatedly:

}

void readSerial(HardwareSerial &port)
{
  port.read().
}

Be aware that sharing buffers to store the data might not be advisable. structs or classes come to mind to solve that.

1 Like

You handover a pointer to either Serial1, Serial2 or Serial3

additionally you should descripe what happens in your code
you receive characters from different ports
what kind of data?
only numerical digits?
very mixed stuff
with or without start/endmarker

assuming the function works how is the function used in the rest of your code?

1 Like

An example


void setup()
{
    Serial.begin(115200);
    getInt(Serial);
}

void loop()
{
}

void getInt(Stream &serialPort)
{
    serialPort.println("enter a number ");
    while (serialPort.available() == 0)
        ;

    int input = serialPort.parseInt();
    serialPort.println(input);
}

1 Like

i receive data from electrical powermeter that are always sending the same message with just different integer value.

message format is :

 _a,int1,int2,int3,int4,int5!

only int1 to int5 can change
and sometimes if error happen on the sender side i receive only

_a,int1!

int1 beeing the error code

the code to handle the received data already work and do exactly what i want to

my question was more about learning new things and reducing the amount of lines in the sketch by not having a function writen 3 time for almost the same thing

Thanks

Serial.parseInt() will lock you in the function until an integral number is received or a time out occurs

so if you use this function (or any similar function provided by arduino where there is a timeout) then you won't be able to listen to multiple Serial lines at the same time

ideally you would create a class buffering the input for you and that you can ask if you received a new message

does your message format have a trailing end mark like a \n ?

this is why i break out of the for loop by reading the next character to see if this is end of line

      for (byte i = 0; i < 6; i++) {
        ReceivedNumber[i] = Serial2.parseInt();
        if (Serial2.read() == '!') {     // end of message received by serial2
          break;
        }
      }

yes , not CR of LF , but "!"

i dont know much about "class" or how to do that :frowning:

i already had a version of the sketch where i had multiple char serialbuffer that get filled up individualy by each serial port

but once any of my buffer got my full message like so

_a,int1,int2,int3,int4,int5!

i have no idea how i can trick .parseInt() to read my buffer, or if this is even possible :frowning:

Sorry, but that won't work because the code will stay in the parseInt() function until a non numeric character is received or the serial timeout occurs

Your messages always have an endmarker the "!"

and it seems that you messages even have start-marker "_a"

normal message: _a,int1,int2,int3,int4,int5!

error-message: _a,int1!

and you have value-separators the comma.
This means you can write yur own receive-function that starts storing the characters
after receiving "_a" and goes on with receiving until the "!" is received

Then a flag completeMessageReceived is set true
and you can go on processing the integers
the length already tells you normal data or error

doing it this way enables to receive as fast as you can in a non-blocking way
and still receive everything

read this tutorial. See example 3 of this tutorial

1 Like

it's not too complicated, may be something like that will do

I just typed it into wokwi to ensure it was compiling and did not test it, so you might have to tailor it a bit

click to see the code
/* ============================================
  code is placed under the MIT license
  Copyright (c) 2023 J-M-L
  For the Arduino Forum : https://forum.arduino.cc/u/j-m-l

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/



const size_t bufferSize = 64;
const byte wrongMessageFormat = 0x42;

class PowerMetter {
  public:
    PowerMetter(const char * name, HardwareSerial &s) : name(name), comPort(s), currentPos(0) {}

    void begin(unsigned long baud, byte config) {
      comPort.begin(baud, config);
    }

    void begin(unsigned long baud) {
      comPort.begin(baud, SERIAL_8N1);
    }

    bool messageReady() {
      bool ready = false;
      if (comPort.available()) {
        char r = comPort.read();
        if (r == '!') {
          messageBuffer[currentPos] = '\0';
          ready = true;
          currentPos = 0;
        } else {
          if (currentPos < bufferSize) {
            messageBuffer[currentPos++] = r;
            messageBuffer[currentPos] = '\0'; // always maintain a cString
          }
        }
      }
      return ready;
    }

    bool parseMessage(long longArray[5]) {
      if (sscanf(messageBuffer, "_a,%ld,%ld,%ld,%ld,%ld", longArray, longArray + 1, longArray + 2, longArray + 3, longArray + 4) == 5) {
        return true;
      } else {
        if (sscanf(messageBuffer, "_a,%ld", longArray) == 1) {
          for (int i = 1; i < 5; ++i) longArray[i] = 0; // empty the other values
          return false;
        }
      }

      for (int i = 0; i < 5; ++i) longArray[i] = wrongMessageFormat; // all data set to wrongMessageFormat would mean wrong input
      return false;
    }

    const char * message() {
      return messageBuffer;
    }

    const char * meterName() {
      return name;
    }

  private:
    const char * name;
    HardwareSerial& comPort;
    char messageBuffer[bufferSize + 1]; // +1 for the trailing null
    byte currentPos;

};

PowerMetter meters[] = {{"PW1", Serial1}, {"PW2", Serial2}, {"PW3", Serial3}};

void setup() {
  Serial.begin(115200);
  for (auto& aMeter : meters) aMeter.begin(9600); // whatever baud rate is used by your Power Meter
}

void loop() {
  for (auto& aMeter : meters) {
    if (aMeter.messageReady()) {
      Serial.print(F("Message from ")); Serial.print(aMeter.meterName());
      Serial.print(F(" => ")); Serial.println(aMeter.message());

      long results[5];
      if (aMeter.parseMessage(results)) {
        Serial.print(F("int1="));    Serial.print(results[0]);
        Serial.print(F(" and int5=")); Serial.println(results[4]);
      } else {
        if (results[1] != wrongMessageFormat) {
          Serial.print(F("Error code: ")); Serial.println(results[0]);
        } else {
          Serial.print(F("wrong message format."));
        }
      }
    }
  }
}

(you might make the parsing more robust in storing the bang also in the messageBuffer in which case you need to add one extra byte to the buffer and modify the sscanf accordingly)

1 Like

are you sure about that ?

according to my analyze it would go like that

maybe i am wrong , tell me what you think

int ReceivedNumber[9];

  while (Serial2.available() > 0) {
    if (Serial2.read() == '_') {    // start of message received by serial2
      for (byte i = 0; i < 9; i++) {
        ReceivedNumber[i] = Serial2.parseInt();
        if (Serial2.read() == '!') {     // end of message received by serial2
          break;
        }
      }
  }

My mistake. I had misunderstood what you were trying to do and your code looks like it should work. Personally I would be tempted to parse the incoming string into the array using the strtok() function, but that is a matter of personal choice

You are making an assumption that the whole buffer has arrived or second guessing the asynchronous nature of the Serial line.

This could timeout if for some reason some data takes time to arrive

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.