How to programme a RFID-RC522 module on an ESP32

Im trying to get a PN532 to work with an ESP32.

I have used an I2C scanner an it dettected it at 0x3c

The I2c jumper is toggled correctly.

I have VCC to 3.5v, GND to GND, SDA to d17 and SCL D5

If I use GPIO 22 (SCL) and GPIO 21 (SDA) it works correctly. so I can only assume im defining the pins incorrectly?

My problem is I dont want to use my NFC on 22 and 21 as I have another device on there and it fails if they are both on the same pins

any advice appreciated

#include <Wire.h>
#include <Adafruit_PN532.h>

#define SDA_PIN 17
#define SCL_PIN 5

Adafruit_PN532 nfc(SDA_PIN, SCL_PIN);

void setup(void) {
  Serial.begin(115200);
  Serial.println("Hello!");

  nfc.begin();
  Serial.println("PN532 initialized");

  // Configure the PN532 to read RFID cards
  nfc.SAMConfig();
  Serial.println("Waiting for an NFC card...");
}

void loop(void) {
  uint8_t success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
  uint8_t uidLength;

  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  if (success) {
    Serial.println("Found an NFC card!");

    Serial.print("UID Length: "); Serial.print(uidLength); Serial.println(" bytes");
    Serial.print("UID Value: ");
    for (uint8_t i = 0; i < uidLength; i++) {
      Serial.print(" 0x"); Serial.print(uid[i], HEX);
    }
    Serial.println(""); 

    delay(1000); // Delay to avoid flooding the serial monitor
  } else {
    Serial.println("No card detected. Waiting...");
    delay(1000); // Delay to avoid flooding the serial monitor
  }
}

If you want to use different pins for I2C, you have to call Wire.setPins() before Wire.begin().

GPIO Matrix and Pin Mux - - — Arduino ESP32 latest documentation)%3B%20function%20before%20calling%20Wire.

Also, your nfc declaration is wrong. If you look at the library, these are the different constructors:

public:
  Adafruit_PN532(uint8_t clk, uint8_t miso, uint8_t mosi,
                 uint8_t ss);                          // Software SPI
  Adafruit_PN532(uint8_t ss, SPIClass *theSPI = &SPI); // Hardware SPI
  Adafruit_PN532(uint8_t irq, uint8_t reset,
                 TwoWire *theWire = &Wire);              // Hardware I2C
  Adafruit_PN532(uint8_t reset, HardwareSerial *theSer); // Hardware UART

so you are using #3 and telling the nfc object that SDA_PIN is the irq pin and SCL_PIN is the reset pin. Probably not what you intended based on the variable names.

thankyou very much for your reply.

this is my updated code but im still having not much luck (im new to all of this)

#include <Wire.h>
#include <Adafruit_PN532.h>

Adafruit_PN532 nfc(-1, -1, &Wire);  // Use -1 for IRQ and RESET since we're using I2C

void setup(void) {
  int sda_pin = 17;
  int scl_pin = 5;
  Serial.begin(115200);
  Serial.println("Hello!");

  // Set custom SDA and SCL pins for I2C
  Wire.setPins(sda_pin, scl_pin);
  Wire.begin();

  nfc.begin();
  Serial.println("PN532 initialized");

  // Configure the PN532 to read RFID cards
  nfc.SAMConfig();
  Serial.println("Waiting for an NFC card...");
}

void loop(void) {
  uint8_t success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
  uint8_t uidLength;

  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  if (success) {
    Serial.println("Found an NFC card!");

    Serial.print("UID Length: "); Serial.print(uidLength); Serial.println(" bytes");
    Serial.print("UID Value: ");
    for (uint8_t i = 0; i < uidLength; i++) {
      Serial.print(" 0x"); Serial.print(uid[i], HEX);
    }
    Serial.println(""); 

    delay(1000); // Delay to avoid flooding the serial monitor
  } else {
    Serial.println("No card detected. Waiting...");
    delay(1000); // Delay to avoid flooding the serial monitor
  }
}

Be aware, that once you reach the success to control NFC on alternative Wire pins, your "another device" will stops working on standard pins 22 and 21.
To run it both you will need to setup a second Wire bus:

Thankyou for all your help. Ive decided to go more simple as this was just confusing me and ive got the NFC to work on the standard i2c pins.

The problem im having is that the NFC is breaking my button code now and im not sure how.... this is my original code which worked just fine......

void loop() {
  server.handleClient();

  unsigned long currentTime = millis();

  bool parkButtonState = digitalRead(buttonPark);
  if (parkButtonState == LOW && lastButtonParkState == HIGH && (currentTime - buttonPressTime >= DEBOUNCE_DELAY)) {
    currentPark = (currentPark + 1) % 4;
    currentRide = 0;
    currentLand = 0;
    parkChanged = true;
    displayWaitTimes();
    buttonPressTime = currentTime;
    displayingWaitTime = true;
    lastUpdateTime = currentTime;
  }
  lastButtonParkState = parkButtonState;

  bool rideButtonState = digitalRead(buttonRide);
  if (rideButtonState == LOW && lastButtonRideState == HIGH && (currentTime - buttonPressTime >= DEBOUNCE_DELAY)) {
    currentRide = (currentRide + 1) % getRideCount();
    parkChanged = true;
    displayWaitTimes();
    buttonPressTime = currentTime;
    displayingWaitTime = true;
    lastUpdateTime = currentTime;
  }
  lastButtonRideState = rideButtonState;

  bool landButtonState = digitalRead(buttonLand);
  if (landButtonState == LOW && lastButtonLandState == HIGH && (currentTime - buttonPressTime >= DEBOUNCE_DELAY)) {
    currentLand = (currentLand + 1) % getLandCount();
    parkChanged = true;
    displayWaitTimes();
    buttonPressTime = currentTime;
    displayingWaitTime = true;
    lastUpdateTime = currentTime;
  }
  lastButtonLandState = landButtonState;

  if (currentTime - lastUpdateTime >= (displayingWaitTime ? DISPLAY_DURATION : UPDATE_INTERVAL)) {
    updateDisplay();
    lastUpdateTime = currentTime;
  }
}

this is my new code including the nfc... the nfc works but the buttons no longer do

void loop() {
  server.handleClient();

  unsigned long currentTime = millis();

  // Button Handling
  bool parkButtonState = digitalRead(buttonPark);
  if (parkButtonState == LOW && lastButtonParkState == HIGH && (currentTime - buttonPressTime >= DEBOUNCE_DELAY)) {
    currentPark = (currentPark + 1) % 4;
    currentRide = 0;
    currentLand = 0;
    parkChanged = true;
    displayWaitTimes();
    buttonPressTime = currentTime;
    displayingWaitTime = true;
    lastUpdateTime = currentTime;
  }
  lastButtonParkState = parkButtonState;

  bool rideButtonState = digitalRead(buttonRide);
  if (rideButtonState == LOW && lastButtonRideState == HIGH && (currentTime - buttonPressTime >= DEBOUNCE_DELAY)) {
    currentRide = (currentRide + 1) % getRideCount();
    parkChanged = true;
    displayWaitTimes();
    buttonPressTime = currentTime;
    displayingWaitTime = true;
    lastUpdateTime = currentTime;
  }
  lastButtonRideState = rideButtonState;

  bool landButtonState = digitalRead(buttonLand);
  if (landButtonState == LOW && lastButtonLandState == HIGH && (currentTime - buttonPressTime >= DEBOUNCE_DELAY)) {
    currentLand = (currentLand + 1) % getLandCount();
    parkChanged = true;
    displayWaitTimes();
    buttonPressTime = currentTime;
    displayingWaitTime = true;
    lastUpdateTime = currentTime;
  }
  lastButtonLandState = landButtonState;

  // Update Display
  if (currentTime - lastUpdateTime >= (displayingWaitTime ? DISPLAY_DURATION : UPDATE_INTERVAL)) {
    updateDisplay();
    lastUpdateTime = currentTime;
  }

  // NFC Reading
  static unsigned long lastNFCCheckTime = 0;
  if (currentTime - lastNFCCheckTime >= 500) { // Check NFC every 500 ms
    lastNFCCheckTime = currentTime;
    
    uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
    uint8_t uidLength;

    if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
      Serial.println("Found an NFC card!");

      Serial.print("UID Length: "); Serial.print(uidLength, DEC); Serial.println(" bytes");
      Serial.print("UID Value: ");
      for (uint8_t i = 0; i < uidLength; i++) {
        Serial.print(" 0x"); Serial.print(uid[i], HEX);
      }
      Serial.println("");
    }
  }
}

thankyou so much for everyones helo

update to this... it seems the buttons only work when the nfc card is held to the reader... how could i fix this please?

I see nothing in this code snippet that could interact with buttons. The problem should be elsewhere.
Please show your full code.

If both devices are truly I2C-compatible, there's no reason they couldn't share a common bus.

1 Like

What is that other device you have on DPin-21 & 22?

#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>

// NFCNFCNFC
#include <Wire.h>
#include <Adafruit_PN532.h>
// END NFCFCNFC

// OLED display width and height
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
#define OLED_ADDRESS  0x3C

// NFCNFCNFC
#define SDA_PIN 21  // Change if using a different pin
#define SCL_PIN 22  // Change if using a different pin
#define I2C_ADDRESS 0x24  // Default address of PN532
// end NFCNFCNFC


Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// NFCNFCNFC
Adafruit_PN532 nfc(SDA_PIN, SCL_PIN);
// END NFCFCNFC


// Define button pins
const int buttonPark = 12; 
const int buttonRide = 14; 
const int buttonLand = 27; 

// Park and ride selection variables
int currentPark = 0;
int currentRide = 0;
int currentLand = 0; 
bool parkChanged = false;

// Button state tracking
bool lastButtonParkState = HIGH;
bool lastButtonRideState = HIGH;
bool lastButtonLandState = HIGH; 

// Debounce delay in milliseconds
const unsigned long DEBOUNCE_DELAY = 50;

// Park API URLs
const char* parks[] = {
  "https://queue-times.com/en-US/parks/6/queue_times.json",
  "https://queue-times.com/en-US/parks/5/queue_times.json",
  "https://queue-times.com/en-US/parks/8/queue_times.json",
  "https://queue-times.com/en-US/parks/7/queue_times.json"
};
const char* parkNames[] = { "MK", "EP", "AK", "HS" };

// WiFi setup
const char* apSSID = "Setup-AP";
const char* apPassword = "123456789";

// Default WiFi credentials
const char* defaultSSID = "wifi2g";
const char* defaultPassword = "qwerty12";

WebServer server(80);

// Define EEPROM addresses
const int SSID_ADDR = 0;
const int PASSWORD_ADDR = 32;

// Timer variables
unsigned long buttonPressTime = 0;
unsigned long lastUpdateTime = 0;
const unsigned long DISPLAY_DURATION = 5000;
const unsigned long UPDATE_INTERVAL = 300000;
bool displayingWaitTime = false;
int currentWaitTime = 0;

DynamicJsonDocument parkData(8192); 

// Forward declarations for functions
void displayError(const char* message);
void displayWaitTimes();
void updateDisplay();
int getRideCount();
int getLandCount();
void displayStartupMessage();
void handleRoot();
void handleWiFiSetup();
void saveWiFiCredentials(String ssid, String password);

void setup() {
  Serial.begin(115200);
  Serial.println("Hello!");
  EEPROM.begin(512);
// NFCNFCNFC
  // Initialize I2C communication
  Wire.begin(SDA_PIN, SCL_PIN);

  // Initialize the PN532
  nfc.begin();

  // Configure PN532 to read RFID tags
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (!versiondata) {
    Serial.print("Could not detect PN532. Please check wiring.");
    while (1);
  }
  
  Serial.println("Found PN532!");
  
  // Configure PN532 to read RFID tags
  nfc.SAMConfig();
  Serial.println("Waiting for an NFC card...");

  // end NFCNFCNFC
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
    Serial.println("SSD1306 allocation failed");
    for (;;);
  }

  displayStartupMessage();

  pinMode(buttonPark, INPUT_PULLUP);
  pinMode(buttonRide, INPUT_PULLUP);
  pinMode(buttonLand, INPUT_PULLUP);

  // Setup Wi-Fi
  WiFi.softAP(apSSID, apPassword);
  server.on("/", HTTP_GET, handleRoot);
  server.on("/setup", HTTP_POST, handleWiFiSetup);
  server.begin();
  Serial.println("HTTP server started");

  // Try to connect to Wi-Fi using stored credentials or default credentials
  String storedSSID = EEPROM.readString(SSID_ADDR);
  String storedPassword = EEPROM.readString(PASSWORD_ADDR);

  if (storedSSID.length() > 0 && storedPassword.length() > 0) {
    WiFi.begin(storedSSID.c_str(), storedPassword.c_str());
    Serial.print("Connecting to ");
    Serial.print(storedSSID);
    int attempts = 0;
    while (WiFi.status() != WL_CONNECTED && attempts < 20) {
      delay(500);
      Serial.print(".");
      attempts++;
    }
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected to WiFi");
      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(SSD1306_WHITE);
      display.setCursor(0, 0);
      display.print("Connected to ");
      display.println(storedSSID);
      display.setCursor(0, 16);
      display.println("Press park selection button");
      display.display();
    } else {
      Serial.println("Failed to connect to WiFi. Connecting with default credentials.");
      WiFi.begin(defaultSSID, defaultPassword);
      int defaultAttempts = 0;
      while (WiFi.status() != WL_CONNECTED && defaultAttempts < 20) {
        delay(500);
        Serial.print(".");
        defaultAttempts++;
      }
      if (WiFi.status() == WL_CONNECTED) {
        Serial.println("Connected to WiFi with default credentials");
        display.clearDisplay();
        display.setTextSize(1);
        display.setTextColor(SSD1306_WHITE);
        display.setCursor(0, 0);
        display.print("Connected to ");
        display.println(defaultSSID);
        display.setCursor(0, 16);
        display.println("Press park selection button");
        display.display();
      } else {
        Serial.println("Failed to connect to WiFi");
        displayError("No Wi-Fi");
      }
    }
  } else {
    Serial.println("No Wi-Fi credentials stored. Connecting with default credentials.");
    WiFi.begin(defaultSSID, defaultPassword);
    int defaultAttempts = 0;
    while (WiFi.status() != WL_CONNECTED && defaultAttempts < 20) {
      delay(500);
      Serial.print(".");
      defaultAttempts++;
    }
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected to WiFi with default credentials");
      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(SSD1306_WHITE);
      display.setCursor(0, 0);
      display.print("Connected to ");
      display.println(defaultSSID);
      display.setCursor(0, 16);
      display.println("Press park selection button");
      display.display();
    } else {
      Serial.println("Failed to connect to WiFi");
      displayError("No Wi-Fi");
    }
  }

  lastUpdateTime = millis(); 


}
void loop() {
  server.handleClient();

  unsigned long currentTime = millis();

  // Button Handling
  bool parkButtonState = digitalRead(buttonPark);
  if (parkButtonState == LOW && lastButtonParkState == HIGH && (currentTime - buttonPressTime >= DEBOUNCE_DELAY)) {
    currentPark = (currentPark + 1) % 4;
    currentRide = 0;
    currentLand = 0;
    parkChanged = true;
    displayWaitTimes();
    buttonPressTime = currentTime;
    displayingWaitTime = true;
    lastUpdateTime = currentTime;
  }
  lastButtonParkState = parkButtonState;

  bool rideButtonState = digitalRead(buttonRide);
  if (rideButtonState == LOW && lastButtonRideState == HIGH && (currentTime - buttonPressTime >= DEBOUNCE_DELAY)) {
    currentRide = (currentRide + 1) % getRideCount();
    parkChanged = true;
    displayWaitTimes();
    buttonPressTime = currentTime;
    displayingWaitTime = true;
    lastUpdateTime = currentTime;
  }
  lastButtonRideState = rideButtonState;

  bool landButtonState = digitalRead(buttonLand);
  if (landButtonState == LOW && lastButtonLandState == HIGH && (currentTime - buttonPressTime >= DEBOUNCE_DELAY)) {
    currentLand = (currentLand + 1) % getLandCount();
    parkChanged = true;
    displayWaitTimes();
    buttonPressTime = currentTime;
    displayingWaitTime = true;
    lastUpdateTime = currentTime;
  }
  lastButtonLandState = landButtonState;

  // Update Display
  if (currentTime - lastUpdateTime >= (displayingWaitTime ? DISPLAY_DURATION : UPDATE_INTERVAL)) {
    updateDisplay();
    lastUpdateTime = currentTime;
  }

  // NFC Reading
  static unsigned long lastNFCCheckTime = 0;
  if (currentTime - lastNFCCheckTime >= 500) { // Check NFC every 500 ms
    lastNFCCheckTime = currentTime;
    
    uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
    uint8_t uidLength;

    if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
      Serial.println("Found an NFC card!");

      Serial.print("UID Length: "); Serial.print(uidLength, DEC); Serial.println(" bytes");
      Serial.print("UID Value: ");
      for (uint8_t i = 0; i < uidLength; i++) {
        Serial.print(" 0x"); Serial.print(uid[i], HEX);
      }
      Serial.println("");
    }
  }
}



void handleRoot() {
  server.send(200, "text/html", R"(
    <!DOCTYPE html>
    <html>
    <body>
      <h1>WiFi Setup</h1>
      <form action="/setup" method="post">
        SSID: <input type="text" name="ssid"><br>
        Password: <input type="password" name="password"><br>
        <input type="submit" value="Save">
      </form>
    </body>
    </html>
  )");
}

void handleWiFiSetup() {
  String ssid = server.arg("ssid");
  String password = server.arg("password");
  saveWiFiCredentials(ssid, password);
  server.send(200, "text/html", "<h1>WiFi credentials saved. Please restart the device.</h1>");
}

void saveWiFiCredentials(String ssid, String password) {
  EEPROM.writeString(SSID_ADDR, ssid);
  EEPROM.writeString(PASSWORD_ADDR, password);
  EEPROM.commit();
}

void displayError(const char* message) {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(message);
  display.display();
}

void displayWaitTimes() {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin(parks[currentPark]);
    int httpCode = http.GET();

    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      Serial.println("Received JSON payload:");
      Serial.println(payload);

      deserializeJson(parkData, payload);

      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(SSD1306_WHITE);
      display.setCursor(0, 0);

      display.println(parkNames[currentPark]);

      JsonArray lands = parkData["lands"].as<JsonArray>();
      if (currentLand < lands.size()) {
        JsonObject land = lands[currentLand].as<JsonObject>();
        JsonArray rides = land["rides"].as<JsonArray>();
        if (currentRide < rides.size()) {
          JsonObject ride = rides[currentRide].as<JsonObject>();
          Serial.println("Ride object:");
          serializeJson(ride, Serial);
          Serial.println();

          if (ride.containsKey("wait_time")) {
            currentWaitTime = ride["wait_time"].as<int>();
          } else {
            Serial.println("No 'waitTime' field found in ride object");
            currentWaitTime = 0;
          }

          display.setCursor(0, 16);
          display.print("Land: ");
          display.println(land["name"].as<String>());

          display.setCursor(0, 32);
          display.print("Ride: ");
          display.println(ride["name"].as<String>());

          display.setCursor(0, 48);
          display.print("Wait Time: ");
          display.print(currentWaitTime);
          display.print(" min");

          display.display();
        } else {
          displayError("Ride Error");
        }
      } else {
        displayError("Land Error");
      }
    } else {
      displayError("Hot Dog");
    }
    http.end();
  } else {
    displayError("No Wi-Fi");
  }
}

void updateDisplay() {
  if (displayingWaitTime) {
    display.clearDisplay();
    display.setTextSize(6);
    display.setTextColor(SSD1306_WHITE);

    String waitTimeStr = String(currentWaitTime);
    int16_t x1, y1;
    uint16_t textWidth, textHeight;
    display.getTextBounds(waitTimeStr, 0, 0, &x1, &y1, &textWidth, &textHeight);
    int x = (SCREEN_WIDTH - textWidth) / 2;

    int yOffset = 4;
    int y = (SCREEN_HEIGHT - textHeight) / 2 + yOffset;

    display.setCursor(x, y);
    display.print(currentWaitTime);
    display.display();
  } else {
    displayWaitTimes();
  }
}

int getRideCount() {
  if (currentLand < parkData["lands"].size()) {
    JsonArray rides = parkData["lands"][currentLand]["rides"].as<JsonArray>();
    return rides.size();
  }
  return 0;
}

int getLandCount() {
  return parkData["lands"].size();
}

void displayStartupMessage() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Magic Forge Wait Times");
  display.display();
  delay(2000); 
}

its very strange that it works fine if a NFC is tapped and remains tapped

https://vi.aliexpress.com/item/1005006827999782.html?spm=a2g0o.order_list.order_list_main.5.45e01802hqXoTt&gatewayAdapt=glo2vnm

an i2c oledd

1 Like

Of course yes.
But sometimes you come across incorrectly designed modules that cannot properly share the bus with other devices. From the OP's explanation, I decided that this was his case.

Can you please, show the I2C Bus wiring of your RFID-RC522 with ESP32 MCU?

OLED -
SDA to d21 esp32
SCL to d22
vcc to 3.3v
gnd to gnd

RFID

SCL to d22
SDA to d21
vcc to 3.3v
gnd to gnd

Then 3 buttons into d12/14/27 and the other legs going to gnd.

@adamandkate83
Why do you again pass SCL SDA pins to the NFC object?

Didn't @blh64 wrote you already that such declaration is wrong?

I think this error can block the display.

So your problem with the buttons is not really related to the buttons at all, the problem is that the incorrect initialization of the NFC causes the display not to show the messages from the buttons and therefore you think the buttons are not working.

If you are using the following RFID-RC522 device (Fig-1), then you have shown connection of only 4 pins for I2C Bus. What are about the connections of other 4 pins? Will they remain unconnected or requires some terminations (NC, HIGH, LOW).
image
Figure-1:

ok im sorry and i realise ive wasted a lot of your time but i just realised thats not the moddule im using. im using a PN532. i got my names confused

Are you not using RFID-RC522 mentioned in your thread Title? Pease, post the picture of your PN532 Module and edit the Title of the thread.

sorry i made a mistake in the title. this is the module
Screenshot 2024-09-11 130050

so how do i change the declaration please? ive tried 3 different ways and all produce errors

i thought i corrected it but obvioulsy not