Skip to content

- Programming for Final Project, 1-3

This page is the process of Programming for my final Project.
This week, Thirdly, I tried "RFID2 + SSR + LCD + DFplayer mini".

Notes:
When installing "Board Manager esp32" in the Arduino IDE, selecting version 2.0.8 caused an RFID-related compile error, so Please install "Board Manager esp32" version 2.0.7 or lower. (As of 2-May-2023)

1-3: RFID2 + SSR + LCD + DFplayer mini

Next, I add "a program that uses serial communication and plays an audio file depending on the situation" with ChatGPT (GPT-4).

alt text

  • What I used
    • Items used in 1-2, and add DFplayer mini(DFR0299)
    • Others: Speaker (8Ω 0.5W), MicroSDcard
    • Library:
      • Wire (for I2C communication)
      • RFID_MFRC522v2 (for RFID reader)
      • Wifi (for wireless connectivity)
      • time (for time-related processing)
      • ESPSoftwareSerial (for DFplayer mini)
      • DFRobotDFPlayerMini (for DFplayer mini)
    • Voice file generation: VOICEVOX:ZUNDAMON(Japanese)

Main instructions for ChatGPT (GPT-4)
- Add DFPlayer to the original code generated by 1-2
- Using software serial
- RX pin is 20, TX pin is 21
- Loop the initialization until DFPlayer Mini responds
- Play audio files depends on the status
  1. Play song number 1 at system startup.
  2. If the card is read and the UID is registered, song number 2 is played.
  3. If the card is read and no UID is registered, play song number 3.
  4. If the card is removed, play song number 4.
- The original code must be adhered to and additional modifications must be made without changing the structure as much as possible.

The completed code is as follows.

Programming code

#include <Wire.h>
#include <MFRC522v2.h>
#include <MFRC522DriverI2C.h>
#include <MFRC522Debug.h>
#include <WiFi.h>
#include <time.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>

const uint8_t RFID_Address = 0x28;
const uint8_t LCD_Address = 0x3E;

MFRC522DriverI2C driver{RFID_Address, Wire};
MFRC522 mfrc522{driver};

const char* registeredUids[] = {
  "5E4ABC3E",
  "DEE6B43E"
};

const char* registeredUserNames[] = {
  "HIROE TAKEDA",
  "KAZUNARI TAKEDA"
};

bool soundPlayed = false;
const uint8_t ssr = 8;

enum CardStatus {
  NO_CARD,
  REGISTERED_CARD,
  UNREGISTERED_CARD
};

CardStatus currentStatus = NO_CARD;

char lastUid[9] = "";
char lastUserName[17] = "";
bool countTime = false;
time_t cardAuthStartTime;

SoftwareSerial mySoftwareSerial(20, 21); // RX, TX
DFRobotDFPlayerMini myDFPlayer;

bool uidMatches(MFRC522::Uid *uid1, const char *uid2) {
  if (uid1->size != 4) {
    return false;
  }

  for (uint8_t i = 0; i < uid1->size; i++) {
    char buf[3] = {uid2[i * 2], uid2[i * 2 + 1], '\0'};
    uint8_t uid2Byte = strtol(buf, nullptr, 16);
    if (uid1->uidByte[i] != uid2Byte) {
      return false;
    }
  }
  return true;
}

const char* formatUid(MFRC522::Uid *uid) {
  static char buf[9];
  for (uint8_t i = 0; i < uid->size; i++) {
    snprintf(&buf[i * 2], 3, "%02X", uid->uidByte[i]);
  }
  return buf;
}

void printCardDetails(MFRC522::Uid *uid) {
  Serial.print("Card UID: ");
  for (uint8_t i = 0; i < uid->size; i++) {
    if (uid->uidByte[i] < 0x10) {
      Serial.print("0");
    }
    Serial.print(uid->uidByte[i], HEX);
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);
  while (!Serial);

  Wire.begin();

  mfrc522.PCD_Init();
  MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial);
  Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));

  pinMode(ssr, OUTPUT);

  init_LCD();

  const char* ssid = "your wifi id";// Input your wifi id
  const char* password = "your wifi password";// Inpur your wifi password
  connectToWifi(ssid, password);
  obtainTime();

  // DFPlayer setup
  mySoftwareSerial.begin(9600);
  Serial.println(F("Initializing DFPlayer..."));
  while (!myDFPlayer.begin(mySoftwareSerial)) {
    Serial.println(F("Unable to begin. Retrying..."));
delay(300);
}
Serial.println(F("DFPlayer Mini initialized."));
myDFPlayer.setTimeOut(500); // Set serial communication time out 500ms
myDFPlayer.volume(30); // Set volume value. From 0 to 30
myDFPlayer.play(1); // Play the first mp3
delay(2000);
}



void loop() {
  bool cardPresent = mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial();
  CardStatus newStatus;

  if (cardPresent) {
printCardDetails(&(mfrc522.uid));

bool isRegistered = false;

for (uint8_t i = 0; i < sizeof(registeredUids) / sizeof(registeredUids[0]); i++) {
  if (uidMatches(&(mfrc522.uid), registeredUids[i])) {
    isRegistered = true;
    strncpy(lastUid, registeredUids[i], sizeof(lastUid));
    strncpy(lastUserName, registeredUserNames[i], sizeof(lastUserName));
    break;
  }
}

    if (isRegistered) {
  digitalWrite(ssr, HIGH);
  Serial.println("Access granted.");
  newStatus = REGISTERED_CARD;
  if (!soundPlayed) { 
    myDFPlayer.play(2);
    soundPlayed = true; 
  }
  delay(2000);

  while (mfrc522.PICC_IsNewCardPresent()) {
    delay(100);
  }
    } else {
      digitalWrite(ssr, LOW);
      Serial.println("Access denied.");
      newStatus = UNREGISTERED_CARD;
      myDFPlayer.play(3);
      delay(4000);
      updateLCD("Card is not", "authorized"); 
    }
  } else {
  digitalWrite(ssr, LOW);
  newStatus = NO_CARD;
  soundPlayed = false; 
  if (currentStatus != newStatus) {
  myDFPlayer.play(4);
  delay(2000);
  }
 }

if (newStatus != currentStatus) {
currentStatus = newStatus;

switch (currentStatus) {
  case NO_CARD:
    if (countTime) {
      time_t elapsedTime = time(nullptr) - cardAuthStartTime;
      unsigned long hours = elapsedTime / 3600;
      unsigned long minutes = (elapsedTime % 3600) / 60;
      unsigned long seconds = elapsedTime % 60;
      char elapsedTimeStr[17];
      snprintf(elapsedTimeStr, sizeof(elapsedTimeStr), "%luh %lum %lus", hours, minutes, seconds);
      updateLCD(elapsedTimeStr, lastUserName);
      countTime = false;
    } else {
      updateLCD("Put your", "members card");
      delay(2000);
    }
    break;
  case REGISTERED_CARD:
    updateLCD("Welcome FabLab", lastUserName);
    cardAuthStartTime = time(nullptr);
    countTime = true;
    break;
  case UNREGISTERED_CARD:
    updateLCD("Card is not", "authorized");
    delay(4000);
    break;
    }

  }

}


void updateLCD(const char* line1, const char* line2) {
  writeCommand(0x01); // Clear Display

  // Write first line
  for (int i = 0; line1[i] != '\0' && i < 16; i++) {
    writeCommand(0x80 + i);
    writeData(line1[i]);
  }

  // Write second line
  for (int i = 0; line2[i] != '\0' && i < 16; i++) {
    writeCommand(0xC0 + i);
    writeData(line2[i]);
  }
}


void writeData(byte toSend) {
Wire.beginTransmission(LCD_Address);
Wire.write(0x40);
Wire.write(toSend);
Wire.endTransmission();
}

void writeCommand(byte toSend) {
Wire.beginTransmission(LCD_Address);
Wire.write(0x00);
Wire.write(toSend);
Wire.endTransmission();
}

void init_LCD() {
writeCommand(0x38);
writeCommand(0x39);
writeCommand(0x14);
writeCommand(0x79);
writeCommand(0x50);
writeCommand(0x6C);
delay(250);
writeCommand(0x38);
writeCommand(0x0C);
writeCommand(0x01);
delay(2);
}

void connectToWifi(const char* ssid, const char* password) {
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}

void obtainTime() {
Serial.println("Obtaining time from NTP");

configTime(0, 0, "pool.ntp.org");

time_t now = time(nullptr);
while (now < 1510644967) { // wait until the current time is later than Nov 14, 2017
delay(500);
Serial.print(".");
now = time(nullptr);
}

Serial.println("");
Serial.print("Current time: ");
Serial.println(ctime(&now));
}

Why I use Software Serial?

I use Software Serial for the following reason.
1. DFRobot is the official Manufacturer of DF Player mini.
2. The sample code in DFRobot site use software serial.

The relevant codes for DFplayer

This piece of code is intended to control DFRobot's DFPlayer Mini (MP3 module) that allows you to play and control audio files. The relevant parts are described below:

  • Initialization of DFPlayer Mini:
    • These lines use the SoftwareSerial library to set up the Arduino digital pins 20 and 21 as RX and TX. This allows these pins to be used for serial communication with the DFPlayer Mini module.
SoftwareSerial mySoftwareSerial(20, 21); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
  • DFPlayer mini setup:
    • These lines initiate serial communication and attempt to initialize the DFPlayer Mini module. This process is repeated many times until the module is available. Once the module is successfully initialized, the communication timeout is set to 500 ms, the volume is set to 30, and the first MP3 file is played.
    • The speed of the serial communication for DFPlayer Mini: 9600 bps
mySoftwareSerial.begin(9600);
Serial.println(F("Initializing DFPlayer..."));
while (!myDFPlayer.begin(mySoftwareSerial)) {
    Serial.println(F("Unable to begin. Retrying..."));
    delay(300);
}
Serial.println(F("DFPlayer Mini initialized."));
myDFPlayer.setTimeOut(500); // Set serial communication time out 500ms
myDFPlayer.volume(30); // Set volume value. From 0 to 30
myDFPlayer.play(1); // Play the first mp3
delay(2000);
  • Playback control of DFPlayer Mini:
    • Various parts of the code use DFPlayer to play specific audio files, as follows.
myDFPlayer.play(2); // Play the second mp3
myDFPlayer.play(3); // Play the third mp3
myDFPlayer.play(4); // Play the fourth mp3

This is the explanation of the main parts related to DFPlayer Mini.


Transfer audio files to micro SD card

  1. Preparation of audio files:
  2. Rename audio files:
    • Renamed the files with sequential numbers, such as "0001.wav", "0002.wav", etc.
  3. Format the micro SD card:
    • FAT32 format, in my case.
  4. Transfer audio files to micro SD card:
    • Insert the micro SD card into the computer's card reader.
    • Open the micro SD card on the computer and copy the audio file you just renamed to the card. Save the file to the root directory of the micro SD card.
    • My Micro sd card tree
      alt text
  5. Insert a micro SD card into the DFPlayer Mini:
    • The micro SD card to which the audio file was transferred is inserted into the SD card slot of the DFPlayer Mini. The DFPlayer Mini will now be able to play the audio file.

Datasheet of DFplayer mini(DFR0299)

Pinout
alt text
alt text
Serial communication connect
alt text

Connect

I connect as follows image.
alt text

Library installed

Open Arduino IDE, installed below Libraries.
- ESPSoftwareSerial
alt text
-DFRobotDFPlayerMini
alt text

Upload

Open Arduino IDE, choose "board ESP32C3". (Tools > Board > ESP32 Arduino > XIAO_ESP32C3)
Port is "/dev/cu.usbmodem1101" in this time, Then Upload the code.

I verified that the device works as programmed!!

Data file

  • audio file made by VOICEVOX's character ZUNDAMON