How can I mimic reading multiple RFID readers through Softwareserial library in

I am working on a project that requires reading from six ID-12LA RFID readers simultaneously.

I’ve tried setting up readings from six channels through the Sparkfun Analog/Digital MUX Breakout board (CD74HC4067), but without luck. I don’t know if it is capable of serial communication, even though I read that on Bildr.org.

However, I am now trying to emulate reading from multiple serial ports through the SoftwareSerial library. I have read that it is not capable of reading simultaneously, but maybe a loop can simulate simultaneous listening. I have tried to do so by listening to the the first serial, then initializing readTag(), and then after that function has finished, begin listening to the second serial and then initialize the second function.

The readTag() function is capable of reading on its own, when only on RFID reader is connected, so that is not the problem.

Below is the code.

What would be the correct way to go about and simulate simultaneous reading through the loop function?

Any help would be appreciated.

void setup() {
  Serial.begin(9600);
  ourSerial1.begin(9600);
  ourSerial2.begin(9600);

  pinMode(RFIDResetPin, OUTPUT);
  digitalWrite(RFIDResetPin, HIGH);
}

void loop() {

  ourSerial1.listen();
  readTag1();
  ourSerial2.listen(); 
  readTag2(); // Only this function works right now, because it is the last serial that was initiated in setup.

}

void readTag1() {

  char tagString[13];
  int index = 0;
  boolean reading = false;

  while (ourSerial1.available()) {

    int readByte = ourSerial1.read();

    if (readByte == 2) reading = true; // Beginning of tag
    if (readByte == 3) reading = false; // End of tag

    if (reading && readByte != 2 && readByte != 10 && readByte != 13) {
      //store the tag
      tagString[index] = readByte;
      index ++;
    }
  }

  checkTag(tagString); // Check if it is a match
  clearTag(tagString); // Clear the char of all value
  resetReader(); // Reset the RFID reader
}

void readTag2() {

  char tagString[13];
  int index = 0;
  boolean reading = false;

  while (ourSerial2.available()) {

    int readByte = ourSerial2.read();

    if (readByte == 2) reading = true; // Beginning of tag
    if (readByte == 3) reading = false; // End of tag

    if (reading && readByte != 2 && readByte != 10 && readByte != 13) {
      //store the tag
      tagString[index] = readByte;
      index ++;
    }
  }

  checkTag2(tagString); // Check if it is a match
  clearTag(tagString); // Clear the char of all value
  resetReader(); // Reset the RFID reader
}

I am working on a project that requires reading from six ID-12LA RFID readers simultaneously.

Not on any Arduino I know of. For that, you need 6 hardware serial ports.

I have read that it is not capable of reading simultaneously, but maybe a loop can simulate simultaneous listening.

Since the class is not capable of reading multiple devices simultaneously, I can't imagine how calling functions of instances of the class in a loop will make the class be able to do something it is not capable of.

How long do you think each instance will spend listening? How much of the data from each device will be captured? What will happen to the rest of the data?

PaulS:
Not on any Arduino I know of. For that, you need 6 hardware serial ports.

he said he is using SoftwareSerial...

I think this is possible, and I hashed out what may work for you… although the non-blocking function for your specific parsing requirement would need to be put together. This example parses messages looking for an end marker, but I adapted for you to see how you might approach this using SoftwareSerial.

this is cool, so I’d like to see you do it so I hope you understand how it attempts to work.

#include <SoftwareSerial.h>
#define  MAX_MESSAGE_LENGTH 12

struct Parse{
  char incomingMessage[MAX_MESSAGE_LENGTH];
  byte idx = 0;
  const char endMarker = ';';
};

SoftwareSerial mySerial[] = {{9,10}, {11, 12}}; // you need the right pin definitions here

Parse message[sizeof(mySerial)/sizeof(mySerial[0])];

void setup() 
{
  for(byte i = 0; i < sizeof(mySerial)/sizeof(mySerial[0]); i++)
  {
    mySerial[i].begin(9600);
  }
}

void loop() 
{
  for(byte i = 0; i < sizeof(mySerial)/sizeof(mySerial[0]); i++)
  {
    char* newMessage = checkForNewMessage(mySerial[i], message[i]);
    if(newMessage)
    {
      Serial.print("New Message on SoftwareSerial:");
      Serial.print(i);
      Serial.print("\t");
      Serial.println(newMessage);
    }
  }

}

char* checkForNewMessage(SoftwareSerial& stream, Parse& mssg)
{
  if(stream.available())
  {
    mssg.incomingMessage[mssg.idx] = stream.read();
    if(mssg.incomingMessage[mssg.idx] == mssg.endMarker)
    {
      mssg.incomingMessage[mssg.idx] = '\0';
      mssg.idx = 0;
      return mssg.incomingMessage;
    }
    else
    {
      mssg.idx++;
      if(mssg.idx > MAX_MESSAGE_LENGTH - 1)
      {
        Serial.println(F("{\"error\":\"message too long\"}"));
        mssg.idx = 0;
        mssg.incomingMessage[mssg.idx] = '\0';
      }
    }
  }
  return NULL;
}

BulldogLowell:
he said he is using SoftwareSerial...

I know that. The issue is that data arriving on a pin associated with an instance of SoftwareSerial that is not the active (listening) instance will be discarded.

Unless OP can figure out a way to make the correct instance of SoftwareSerial listen when a tag is scanned, the data will almost certainly be discarded.

Your solution will not work, since you never change the active instance, AND you can not predict, either, which device the SoftwareSerial class should listen to.

PaulS:
I know that. The issue is that data arriving on a pin associated with an instance of SoftwareSerial that is not the active (listening) instance will be discarded.

I see, perhaps Paul Stoffregen's AltSoftSerial...

seems to maybe fit the use case.

BulldogLowell:
seems to maybe fit the use case.

nope, only one instance :roll_eyes:

bummer...

Hey! Like you guys said, it didn’t make much sense to use SoftwareSerial.

Now we are attempting to read from our multiple ID-12 RFID’s with the 16 Channel CD74HC4067 multiplexer again. First we need to be able to just read from two RFID-readers hooked up to this multiplexer. I know that with a multiplexer, I am still only able to serial-read one input at a time.

Right now, with this code, I can only read from the first channel (and one RFID) and not from the second channel (no matter which channels we address).

We want our code to loop through these channels and when it has found a tag, move on to the next channel, find a tag, move on to the next channel. If there is no tag, it should still loop through channels.

Do you guys have any idea how to read from multiple RFIDs with this?

#include <SoftwareSerial.h>

#define READERNUM 2

SoftwareSerial ourSerial1(8, 13); // RX, TX

// Mux control pins
int s0 = 5;
int s1 = 4;
int s2 = 9;
int s3 = 10;

// RFID reset pin no.
const int RFIDResetPin = 6;

// Register RFID tags
char tag1[13] = "31002E5AF0B5"; //A
//etc...//


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

  pinMode(RFIDResetPin, OUTPUT);
  digitalWrite(RFIDResetPin, HIGH);

  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);

  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
}


void loop() {

  // check RFID readers
    readTag1();
    readTag2();
}

void readChannel1() {

  // Setting Mux board with channel number
  setMux(0);

  // Reset reader
  resetReader();
  // delay(0); // Can be used for delaying signal input

  // Wait until getting 14 chars from RFID tags
  if (ourSerial1.available() >= 14) {

    // Proces at a 2 as it marks the tag begining
    while (ourSerial1.read() != 2);

    // Temporal buffer to hold our tag
    char tagString[13];

    // Read the serial until we get a 3, the end of the tag
    int charactersRead = ourSerial1.readBytesUntil(3, tagString, 13);

    ourSerial1.println("Tag: ");
    ourSerial1.println(tagString);

    // Clear the char of all value
    clearTag(tagString);
  }

}

void readChannel2() {

  setMux(1);

  resetReader();

  if (ourSerial1.available() >= 14) {

    while (ourSerial1.read() != 2);

    char tagString[13];

    int charactersRead = ourSerial1.readBytesUntil(3, tagString, 13);

    ourSerial1.println("Tag: ");
    ourSerial1.println(tagString);
    
    clearTag(tagString);
  }

}


void resetReader() {
  digitalWrite(RFIDResetPin, LOW);
  digitalWrite(RFIDResetPin, HIGH);
  delay(150);
}

void clearTag(char one[]) {
  for (int i = 0; i < strlen(one); i++) {
    one[i] = 0;
  }
}

void setMux (int channel) {
  int controlPin[] = {s0, s1, s2, s3};

  int muxChannel[16][4] = {
    {0, 0, 0, 0}, //channel 0
    {1, 0, 0, 0}, //channel 1
    {0, 1, 0, 0}, //channel 2
    {1, 1, 0, 0}, //channel 3
    {0, 0, 1, 0}, //channel 4
    {1, 0, 1, 0}, //channel 5
    {0, 1, 1, 0}, //channel 6
    {1, 1, 1, 0}, //channel 7
    {0, 0, 0, 1}, //channel 8
    {1, 0, 0, 1}, //channel 9
    {0, 1, 0, 1}, //channel 10
    {1, 1, 0, 1}, //channel 11
    {0, 0, 1, 1}, //channel 12
    {1, 0, 1, 1}, //channel 13
    {0, 1, 1, 1}, //channel 14
    {1, 1, 1, 1} //channel 15
  };

  //loop through the 4 sig
  for (int i = 0; i < 4; i ++) {
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }

}

What happens when data arrives at the multiplexer, and you are not actively reading it?

I do not believe that you can use a multiplexer to read serial data.

PaulS:
What happens when data arrives at the multiplexer, and you are not actively reading it?

I do not believe that you can use a multiplexer to read serial data.

what about an interrupt that would move a pointer to the instance of software serial attached to that “channel” and then block until the data/message is received.

You would only not be able to simultaneously process tags…

void Pin4_ISR(void)
{
  if(!activeParsing) . //EDITED
  {
    activeSerial = serial4;
    activeParsing = true;
  }
}

and

void loop()
{
  while(activeSerial.available())
  {
    blockAndParseTheMessage();
  }
  activeParsing = false;  //EDITED

kind of thing…

PaulS:
What happens when data arrives at the multiplexer, and you are not actively reading it?

I do not believe that you can use a multiplexer to read serial data.

Hi Paul.

We did not think so either but then we read an article about this device (bildr Muxing Around With The CD74HC4067 + Arduino - bildr) where the author writes:
"It also works with serial. So… if you had 16 RFID readers that output serial, you could connect the SIG pin of the CD74HC4067 to digital 0 on the arduino (Serial RX pin) and the serial out of an RFID reader to one of the channels and be able to read from all 16 RFID readers". This is why we acquired this multiplexer. But yeah, it does not seem to work when we set it up with this code, perhaps because I don't know how to loop it correctly and read one channel at a time.

Hello guys!

I have the same issue. I want to have 6 RFID ID-12LA readers and I want to store the data and use it as identifiers. Although I am using a Controllino MAXI the same principles applies to its ATmega 2560 processor.

What I have found out that placing the RFID readers in close range will cause interference in the generated electromagnetic field which will block all the data that the readers send.
Got it from this article: How to Set Up Multiple RFID Readers in Close Range | Phidgets
Also it says something of an alternative of muxing and software serial and I think it worth a try.

I have tried SoftwareSerial which is a pain in the butt, it is slow and you do not always get the results you want or at least not for me.

I try to double my efforts with SS and in the meantime I would appreciate hearing from your experiments with muxing and I hope we can share our finding. :slight_smile:

Have a nice day and happy tinkering!