Help required with creating RFID library

Hello, I'm trying to create an UHF RFID library based on the following attached vendor communication protocol. Not having any luck as my level of programming is quite basic.
Communication Protoco -V4.2 EN.pdf (271.3 KB)

The reader is connected to D2 D3 of the Leonardo board.

so far my code only has this and it's already working by printing the Hello World after i send a character.

int delayTime=1000;
long lastExec=0;

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

void loop()
{ long t = millis();
if (t - lastExec >= delayTime){
  if (Serial.available() >0{
    Serial.println("Hello World");}
lastExec=t;
}
}

Appreciate all help.

Welcome to the forum

Your topic was MOVED to its current forum category as it is more suitable than the original as it is not an Introductory Tutorial

Are you really trying to create a library or are you just trying to read the UHF RFID using an Arduino sketch ?

Bearing in mind that you say

then writing a library is probably quite ambitious

Although it passes syntax rules, this formatting is not easy to read. Please try to learn and obey some standard indentation and formatting system of your choice. Especially if you are making your code public. There are several out there. The Arduino IDE can auto format code, but it can't re-organize it. What you have written would normally be represented something similar to:

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

or even:

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

When you are first starting out developing a library you can start with a simple demonstration sketch that shows what you want the library to do. Let's make a library that blinks an LED at a specified rate. We can start with something like File->Examples->02.Digital->BlinkWithoutDelay (I am removing most of the comments for compactness.)

const int ledPin =  LED_BUILTIN;
int ledState = LOW;
unsigned long previousMillis = 0;
const long interval = 1000; 

void setup() 
{
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  unsigned long currentMillis = millis();
  
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

The next step is to move the part you want the library to do into one or more functions. This sketch will do exactly the same thing as before but with very little in setup() and loop() and most code in a function:

const int ledPin =  LED_BUILTIN;
int ledState = LOW;
unsigned long previousMillis = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);
}

void blink(unsigned long interval)
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

void loop()
{
  blink(1000);
}

Now comes the 'library' split. You start by creating a new tab. At the right end of the bar just above the sketch is a little triangle in a square. Click on that and select "New Tab". Name the new tab "BlinkLib.cpp". Now cut the 'blink' function out of the main tab and paste it into the new tab.

If you try to Verify your sketch now you will find some errors. The first is:

BlinkLib.cpp:3:33: error: 'millis' was not declared in this scope
   unsigned long currentMillis = millis();
                                 ^~~~~~

This is because, unlike the '.ino' files, the '.cpp' files don't automatically get
#include <Arduino.h>
inserted at compile time. Add that line to the top of BlinkLib.cpp and do another Verify.

The next error is:

BlinkLib.cpp:6:23: error: 'previousMillis' was not declared in this scope
   if (currentMillis - previousMillis >= interval)
                       ^~~~~~~~~~~~~~

This is because that global variable declaration didn't get moved to the library. In this case, only the library needs it so move the declaration to the top of BlinkLib.cpp. While you're at it, move 'ledState' and 'interval', too. Then try another Verify.

Now you get the error:

sketch_jan05a:13:3: error: 'blink' was not declared in this scope
   blink(1000);
   ^~~~~

That's because the main sketch no longer contains a declaration for the blink() function. This is a good time to create another tab to share declarations between the library and the sketch. Create a new tab named BlinkLib.h (h for 'header'). In that new tab, put the line:
void blink(unsigned long);
Then in the main sketch, add the line:
#include "BlinkLib.h"
This will allow the main sketch to see a declaration of "blink()".

That leads you to the next error:

BlinkLib.cpp:21:18: error: 'ledPin' was not declared in this scope
     digitalWrite(ledPin, ledState);
                  ^~~~~~

We used 'ledPin' in setup() so we left the declaration there, but now BlinkLib.cpp needs the declaration. We need a way for setup() to set the pin mode so we create another function in BlinkLib.cpp:

void setPin(int pin)
{
  ledPin = pin;
  pinMode(ledPin, OUTPUT);
}

Put the declaration of setPin() into BlinkLib.h so the sketch can use it:
void setPin(int);
Move the declaration of 'ledPin' into BlinkLib.cpp. Now you can have setup() call setPin().

All-together you have:
Main Sketch:

#include "BlinkLib.h"

void setup()
{
  setPin(LED_BUILTIN);
}

void loop()
{
  blink(1000);
}

Library header:

void blink(unsigned long);
void setPin(int);

Library source:

#include <Arduino.h>
#include "BlinkLib.h"

int ledState = LOW;
unsigned long previousMillis = 0;
int ledPin =  LED_BUILTIN;

void setPin(int pin)
{
  ledPin = pin;
  pinMode(ledPin, OUTPUT);
}

void blink(unsigned long interval)
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

Your library is complete! Now you can move the files out of the sketch directory and into a library folder. In your sketchbook directory (see Preferences if you don't know where that is) find (or create) a subdirectory names 'libraries'. That is where all your third-party (not built-in) libraries are kept. In the 'libraries' directory, create a directory named BlinkLib and move BlinkLib.h and BlinkLib.cpp to there.

Now you can delete those two tabs from your sketch and the sketch will still Verify! The compiler will find the BlinkLib directory and make those files part of the Verify process.

Now you can turn your sketch into a library example. Move the .ino file to libraries/BlinkLib/examples/test/test.ino. It will show up in the IDE under: File->Examples->BlinkLib->test

Ah, but there is one small problem. Now you want to blink multiple LEDs at different rates! There is only one "ledPin" variable so if you call "setPin()" a second time, the first pin number is replaced by the second pin number, and blink() will only blink the second pin. Also the "ledState" and "previousMillis" globals are shared.

To fix that, we are going to 'encapsulate' the functionality of the library into an 'object'. You can then make multiple 'instances' of the object, each with its own variables.

Let's create an object class named 'Blinker'. This goes into BlinkLib.h in place of the shared function prototypes.

class Blinker
{
  public:
    Blinker(const byte pin);  // "Constructor" called when the object is defined
    
    void blink(const unsigned long interval);

  private:
    const byte ledPin;
    int ledState;
    unsigned long previousMillis;
};

Now we can change the test sketch to blink two LEDs:

#include "BlinkLib.h"

Blinker blinker(LED_BUILTIN);  // Blink the built-in LED
Blinker blinker2(9);  // Blink the LED on Pin 9

void setup()
{
}

void loop()
{
  blinker.blink(1000);
  blinker2.blink(750);
}

We can try to Verify the test sketch but we have not defined the functions ("member functions" or "methods") declared in the class yet. We get undefined reference errors for Blinker::Blinker() (the constructor) and Blinker::blink() (the function that does stuff!). The second one is easy to fix because we just have to change the declaration of 'blink' from:
void blink(unsigned long interval)
to
void Blinker::blink(unsigned long interval)
That tells the compiler that we are not defining just a function, but a function that is a member ("member function" or "method") of the object class "Blinker". Nothing else about 'blink()' has to be changed because the blink() "method" is perfectly happy to use the "member variables" of its class in place of the old globals. We can remove the globals and the setPin() function from BlinkLib.cpp because they are no longer used:

#include <Arduino.h>
#include "BlinkLib.h"

void Blinker::blink(unsigned long interval)
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

Now that "Blinker::blink()" is taken care of, we need to define Blinker::Blinker(). This is the "constructor": the function automatically called when an object of this class (an "instance") is created ("instantiated"). It is a good place to do some initialization. We can put this function in BlinkLib.cpp:

Blinker::Blinker(const byte pin)
{
  ledPin = pin;
  ledState = LOW; 
  previousMillis = 0;
  
  pinMode(ledPin, OUTPUT);
  previousMillis = millis();
}

The only problem is, "ledPin" is declared with the keyword 'const' so it can't be assigned a value inside the constructor. It has to be given a value BEFORE the body of the constructor so we have to use some special syntax:

Blinker::Blinker(const byte pin) : ledPin(pin)
{
  ledState = LOW; 
  previousMillis = 0;
  
  pinMode(ledPin, OUTPUT);
  previousMillis = millis();
}

Yay! The sketch compiles without any errors or warnings!

Except for one thing. A thing the compiler can't warn you about because it doesn't know. The Arduino library isn't initialized until just before your setup() function is called. That is AFTER all of the global variables are initialized. That includes calling the constructor of every global object instance. In other words, your object class can't safely call any Arduino functions (like "pinMode()" or "millis()") in the constructor! You may have wondered why some Arduino library objects have a 'begin()' method that you have to call from setup(). That's why.

To make our object safe to use we add a 'begin()' method (the name is just an Arduino convention) and call the Arduino functions from there.

void Blinker::begin()
{
  pinMode(ledPin, OUTPUT);
  previousMillis = millis();
}

That goes in BlinkLib.cpp and we call it in setup().

We have to add the "void begin();" declaration to the class (in BlinkLib.h) and we're ready to go!

All-together you have:
Main Sketch:

#include "BlinkLib.h"

Blinker blinker(LED_BUILTIN);  // Blink the built-in LED
Blinker blinker2(9);  // Blink the LED on Pin 9

void setup()
{
  blinker.begin();
  blinker2.begin();
}

void loop()
{
  blinker.blink(1000);
  blinker2.blink(750);
}

Library header:

class Blinker
{
  public:
    Blinker(const byte pin);  // "Constructor" called when the object is defined
    void begin(); // A function to call to do initialization

    void blink(const unsigned long interval);

  private:
    const byte ledPin;
    int ledState;
    unsigned long previousMillis;
};

Library source:

#include <Arduino.h>
#include "BlinkLib.h"

Blinker::Blinker(const byte pin) : ledPin(pin)
{
  ledState = LOW;
  previousMillis = 0;
}

void Blinker::begin()
{
  pinMode(ledPin, OUTPUT);
  previousMillis = millis();
}

void Blinker::blink(unsigned long interval)
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

yeah i just want my rfid to read the tags. doesn't seem to work with many of the libraries i tried out there. figured i need to write my own

thank you. have edited post

thank you so much for your explanation. I understand about libraries now. Let me try and create one for the rfid.

You don't actually need to write a library. What you need to do is to write the code to read the RFID. Then, as @johnwasser has shown, you could turn it into a library but the first step is to write the normal code

What problems did you have with existing RFID libraries ?

Mainly because the tag number wasn't shown on the Serial Monitor or no information is show.

I've tried to experiment with pagemac's code and RFID library but i'm begining to think maybe i should try to use a similar UART example as per the protocol i attached.

I've tried the below example and tried to get a Byte but nothing appears only Hello World

int incomingByte;

void setup()
{
  Serial.begin(9600);
  //myserial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
}

void loop()
{
  long t = millis();
  if (t - lastExec >= delayTime) {
    if(Serial.available() > 0){
      Serial.println("Hello world");
      incomingByte = Serial.read();
    }  
    lastExec = t;
  }
}

You are reading a byte from Serial but not printing it. It is also not a good idea to use the Serial interface to read data from the RFID because it is also used by the Serial monitor and to upload code

Try this

#include <SoftwareSerial.h>

SoftwareSerial RFID(10, 11);  //Rx pin, Tx pin

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

void loop()
{
  if (RFID.available())
  {
    Serial.println(RFID.read());
  }
}

Choose your own baud rate for Serial and pin numbers for Rx and Tx Make sure that you connect Rx on the Arduino to Tx on the RFID and vice versa

No luck still. Not sure if it's worth mentioning that it's a 12V powered RFID reader with it's own power supply. So the only 2 wires goes into the Pin 2 and 3 of my leonardo. Using softwareSerial packages tend to yield no results.

So you have no common GND connection. Correct that and try my sketch again

I tried with a common gnd. my wiring is now like this.

GND: From leonardo splice with the black wire of the 12v power supply for the RFID reader

2 wires going into D0 D1 of the leonardo. According to the schematic of leonardo found online, the D0 and D1 are the RX and TX ports.

No luck from Serial output on rfid tags though. I tried the softwareserialexample and was only able to print goodnight mooon

Please post the sketch that you tried when using pins D0 and D1 on the Leo connected to the RFID reader


#include <SoftwareSerial.h>

SoftwareSerial RFID(0,1);  //Rx pin, Tx pin

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

void loop()
{
  if (RFID.available())
  {
    Serial.println(RFID.read());
  }
}

Why use SoftwareSerial when the Leo has 2 Serial interfaces ? Communication with the PC does not use pins 0 and 1 unlike the Uno.

Just connect pins 0 and 1 to the RFID device and refer to the interface as Serial1 in the sketch

ok so for uniformity purposes, I went out and purchase another RFID reader this time with a RS232 connection. I went to purchase a arduino UNO and a RS232-TTL Converter that uses MAX232 chip.

My current code is as follows. IT only prints the line in setup function but not in the loop function. Where else can i diagnose. The RFID reader is now set to baud rate 9600 via the vendor's software. TTL converter is connected to 5v and GND in addition to pins 0,1 for the RX, TX on the UNO. It prints "Entered2" only when i key in something into the serial monitor and throws out some random values but not detecting the rfid card. I have also tried pins 2 and 3 but to no avail

  #include <SoftwareSerial.h>
 
 SoftwareSerial RFID(0, 1);  //Rx pin, Tx pin
 
 void setup()
 {
   Serial.begin(9600);
   RFID.begin(9600);
   Serial.println("Entered1");
 }
 
 void loop()
 {
   if (RFID.available())
   {
     Serial.print("Entered2\n");
     Serial.println(RFID.read(), HEX);
   }
 }

I see that you are still using SoftwareSerial on the Leo. You never did answer why when the Leo interface to the PC is separate from the Serial1 interface on pins 0 and 1

That brings us to the second point as you are now using the hardware Serial1 pins (0 and 1) as SoftwareSerial pins

Try this

Connect the RFID reader to pins 0 and 1 then use

 void setup()
 {
   Serial.begin(9600);  //Serial monitor
   Serial1.begin(9600);  //RFID
   Serial.println("Entered1");
 }
 
 void loop()
 {
   if (Serial1.available())
   {
     Serial.print("Entered2\n");
     Serial.println(Serial1.read(), HEX);
   }
 }

I actually am not using the LEO, Have moved on to try on an UNO to get consistent results. however Entered 2 is still not being print. After reading online documentation about the UNO, I've left pins 0,1 empty and put RX TX on 3 and 4.

Still nothing gets printed though.

To be clear, you are now using a Uno and have the RFID reader connected to pins 3 and 4 ?

Is the RFID reader powered from the Uno and is Rx on the reader connected to the SoftwareSerial Tx pin and vice versa ?