IsoFace爱招飞 发表于 2022-8-26 14:45:52

RC522 RFID 模块上手,由浅入深,探索一下整合(持续更新)

本帖最后由 IsoFace爱招飞 于 2022-8-26 14:51 编辑

  近期入手了一套 RC522 的 RFID 模块,现在把我近期把玩这个模块的经历分享给大家,大家可以参照这个过程,上手这个模块的玩法。



  刚到手的 RFID 模块与排针是分开的,需要自己焊上,焊什么的不用多说了吧,来这看贴文的应该都要会这个技能。选择焊直排针还是弧排针就看自己的需求了。

  RC522 RFID 的板子大概都是下面这个样子的。



  翻出吃灰已久的焊枪,一番操作后排针就焊上了,下面是找了一张已经焊好的板子的图。



  焊接的地方有一排引脚说明。我查了[相关资料](https://github.com/miguelbalboa/rfid#pin-layout),下面整理出来各引脚的定义说明。

|   SDA    |           SCK   |               MOSI       |              MISO      |         IRQ |         GND |         RST |         3.3V |
| -------- | ----------- | ----------------- | ----------------- | ------- | ----- | ----- | ------ |
| 选择设备 |         时钟信号 |         主出从入(数据) |         主入从出(数据) |         中断 |         接地 |         置位 |         电源|


  接下来将 RC522 与 Arduino 连接,以下使用 Arduino Uno 进行连接。连接的对照表格示意如下:

| MFRC522针脚 | Arduino Uno 针脚 |
| ----------- | ---------------- |
| 3.3V      | 3.3V             |
| GND         | GND            |
| RST         | 9                |
| SDA/SS      | 10               |
| MOSI      | 11               |
| MISO      | 12               |
| SCK         | 13               |

  范例需要使用到 `MFRC522` 的库,我们可以在库管理器中搜索到这个库,安装即可。



&emsp;&emsp;库文件的来源:<https://github.com/miguelbalboa/rfid>

&emsp;&emsp;安装完成后,在 Arduino IDE 菜单栏中选择 `文件` - `示例` -`第三方示例 - MFRC522` - `DumpInfo`打开示例。

&emsp;&emsp;将 Arduino 连接至电脑,配置开发板选项为 `Arduino Uno`。



&emsp;&emsp;端口是否已选择 Arduino Uno 所在的端口。



&emsp;&emsp;点击烧录按钮,将程序烧录至 Arduino 开发板中。

&emsp;&emsp;打开串口监视器,查看运行情况。这个时候可以把卡片放到RFID模块上,看到读取的信息。



&emsp;&emsp;通过上述过程,我们已经调试测试了 MFRC522 模块,接下来还会有更多精彩的使用方法与整合运用方式。后续会在本贴陆续更新,请大家持续关注。

IsoFace爱招飞 发表于 2022-8-29 13:52:22


&emsp;&emsp;前面使用了 Arduino 来连接 MFRC522 ,现在我打算用 ESP8266 来试一下,当然我还要加上亿点点内容,再加一块显示屏,再加两个继电器,再加两个 LED 发光二极管指示灯。

&emsp;&emsp;下面我把需要用到的零件列一下,方便制作收集:

| 序号 |               零件名称               |            数量            |
| ---- | ----------------------------------- | -------------------------- |
| 1    | NodeMCU ESP8266 Lua WIFI V3 开发板   | 1                        |
| 2    | 2 路 5V/12V 继电器模块 高低电位触发    | 1                        |
| 3    | MFRC-522 RC522 RFID IC 卡感应 附白卡 | 1                        |
| 4    | I2C LCD1602 液晶显示屏               | 1                        |
| 5    | LED 发光二极管                     | 红色、绿色各 1 个,共计 2 个 |
| 6    | 220Ω 电阻                            | 2                        |
| 7    | 蜂鸣器模块                           | 1                        |

&emsp;&emsp;接下来,就可以准备开始玩一波了!

&emsp;&emsp;首先要准备将各零件连接起来,连接完成后的图示就是下面显示的这样子:



&emsp;&emsp;连接连好了,Arduino 代码在哪里?别急,马上给你。

&emsp;&emsp;在使用以下代码前,请先下载并配置以下的库。

* ESP8266开发板的专用库。 <http://arduino.esp8266.com/stable/package_esp8266com_index.json>

Arduino IDE 安装完成以后,进入首选项(Preferences),找到附加开发板管理器地址(Additional Board Manager URLs),并在其后添加如下信息:http://arduino.esp8266.com/stable/package_esp8266com_index.json



&emsp;&emsp;保存后重启 Arduino IDE,点击菜单栏 工具 - 开发板 - 开发板管理器,找到 `esp8266` 安装即可。



&emsp;&emsp;然后点击 `工具-开发板-ESP8266` 在目录中选择对应的型号。这样开发板就切换完成了。这个示例使用的代码如下:

```C
//购买之 RFID-522 脚位顺序
//RFID脚位   NodeMCU脚位

//MISO      GPIO12   D6
//SCK         GPIO14   D5
//SS(SDA)   GPIO4      D2有的会连 D8配合 LCD 使用改为 D4
//MOSI      GPIO13   D7
//GND
//3.3V
//RST         GPIO5      D1配合 LCD 使用改为 D3
//接无源蜂鸣器,负极接地,信号接 D8 控制输出 3V 或 0V 控制生成长短哔声
//NodeMCU 开发板偏好设置如下
// http://arduino.esp8266.com/stable/package_esp8266com_index.json
//
//LCD脚位接法NodeMCU
//GND         GND
//VSS         Vin/5V
//SCL         D1
//SDA         D2

//蜂鸣器发出声音
//需要pitches文件
//https://gitee.com/isoface-iot/Smart/blob/master/demo/iot/s-eq-dem-2209_rfid_mqtt_relay/esp8266_ino/pitches.h
#include "pitches.h"
//创建要发音的音色数组
int Music = {
NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4,
NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5,
NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5
};

#include <stdio.h>
#include <stdlib.h>
#include <Arduino.h>

// WiFi 声明 ============================================================================================================================
//https://github.com/prampec/IotWebConf/tree/v2.x.x
#include <IotWebConf.h>
const char thingName[] = "Relay";                                              // 开发板当 AP 使用时,所采用的名称,类似 SSID.
const char wifiInitialApPassword[] = "66666666";                               // 开发板当 AP 使用时,连接所需之密码.
// 在运行时使用浏览器修改设置,用户名称为 admin,密码就是上行设置值
#define STRING_LEN 128
#define NUMBER_LEN 32

#define CONFIG_VERSION "Relay01"                                                // 配置特定密钥。如果更改了配置结构,就需修改该值.

// CONFIG_PIN 重新设置脚位,例如设 D0 脚位,在开发板启动时 与GND 脚位连接,将会重新进行,(用于密码遗忘)
#define CONFIG_PIN D0

// 状态指示器针脚,首先它会亮起(保持低电平),在Wifi连接上它会闪铄,当连接到Wifi时,它将关闭(保持高电平)。
#define STATUS_PIN LED_BUILTIN


// MQTT 声明 ============================================================================================================================
// pubsubclient MQTT 程序库网址https://github.com/knolleary/pubsubclient
#include <PubSubClient.h>
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg;
int value = 0;
char hexStr;                                                                // 设置 RFID 卡号
char mapic;                                                               // 设置该机 MQTT主题名称
bool wifiready = false;


// 声明回传的方法
void configSaved();
boolean formValidator();
boolean connectAp(const char* apName, const char* password);
void connectWifi(const char* ssid, const char* password);
void charToStringL(const char S[], String &D);                                 //将 char[] 转为 String 自订函数

DNSServer dnsServer;
WebServer server(80);
HTTPUpdateServer httpUpdater;


char mqttServerValue;
char mqttUserNameValue;
char mqttUserPasswordValue;
char mqttTopicValue;

char ipAddressValue;
char gatewayValue;
char netmaskValue;

IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
IotWebConfParameter ipAddressParam = IotWebConfParameter("IP位址", "ipAddress", ipAddressValue, STRING_LEN, "text", NULL, "192.168.3.124");
IotWebConfParameter gatewayParam = IotWebConfParameter("网关", "gateway", gatewayValue, STRING_LEN, "text", NULL, "192.168.3.1");
IotWebConfParameter netmaskParam = IotWebConfParameter("子网掩码", "netmask", netmaskValue, STRING_LEN, "text", NULL, "255.255.255.0");
IotWebConfParameter mqttServerParam = IotWebConfParameter("MQTT 服务器-", "mqttServer", mqttServerValue, STRING_LEN);
IotWebConfParameter mqttUserNameParam = IotWebConfParameter("MQTT 用户", "mqttUser", mqttUserNameValue, STRING_LEN);
IotWebConfParameter mqttUserPasswordParam = IotWebConfParameter("MQTT 密码", "mqttPass", mqttUserPasswordValue, STRING_LEN, "password");
IotWebConfParameter mqttTopicParam = IotWebConfParameter("MQTT 主题", "mqttTopic", mqttTopicValue, STRING_LEN);

// 开发板固定 发送的主题 mqttTopicValue/uid    这是RFID卡号
// 开发板固定 接收的主题 mqttTopicValue/inp    自行决定发送之消息 例如 单号 货号 产品名称可以是中文 (LCD无法显示中文)
// 开发板固定 接收的主题 mqttTopicValue/re01   =1 开启 1 号继电器   =0 关闭 1 号继电器
// 开发板固定 接收的主题 mqttTopicValue/re02   =1 开启 2 号继电器   =0 关闭 2 号继电器


IPAddress ipAddress;
IPAddress gateway;
IPAddress netmask;

// LCD1602 声明 =============================================================================================================================
//https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
#include <Wire.h>
#include <LiquidCrystal_I2C.h>                  //引用I2C库

LiquidCrystal_I2C lcd(0x27, 16, 2);               //设备位址,这里的位址是0x3F,一般是0x20,或者0x27,具体看模块手册

// RFID 读卡机 声明 ===========================================================================================================================
#include <SPI.h>
#include "MFRC522.h"

#define RST_PIN D3                              // RFID 读卡机的重置脚位 RC522
#define SS_PIND4                              //RFID 读卡机的芯片选择脚位
MFRC522 mfrc522(SS_PIN, RST_PIN);               // 创建MFRC522物件
//============================================================================================================================================

void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
SPI.begin();                                 // Init SPI bus
mfrc522.PCD_Init();                            // Init MFRC522
Serial.println("RFID ready");
// WiFi 设置 =============================================================================================================================
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(CONFIG_PIN);
iotWebConf.addParameter(&ipAddressParam);
iotWebConf.addParameter(&gatewayParam);
iotWebConf.addParameter(&netmaskParam);
iotWebConf.addParameter(&mqttServerParam);
iotWebConf.addParameter(&mqttUserNameParam);
iotWebConf.addParameter(&mqttUserPasswordParam);
iotWebConf.addParameter(&mqttTopicParam);
iotWebConf.setConfigSavedCallback(&configSaved);             // 回传副程序 - 保存设置
iotWebConf.setFormValidator(&formValidator);               // 回传副程序 - 检查输入参数是否有错
iotWebConf.setApConnectionHandler(&connectAp);               //启动系统缺省 192.168.4.1 之AP 造成无法引入设置之IP
iotWebConf.setWifiConnectionHandler(&connectWifi);         // 回传副程序 - 启动 WiFi副程序名称 connectWifi

// -- Initializing the configuration.

boolean validConfig = iotWebConf.init();
if (!validConfig)   {
    mqttServerValue = '\0';
    mqttUserNameValue = '\0';
    mqttUserPasswordValue = '\0';
}
else
{
    strcpy(mapic, mqttTopicValue);
}
// -- 在Web服务器上设置必需的URL处理进程.

server.on("/", handleRoot);
server.on("/config", [] { iotWebConf.handleConfig(); });
server.onNotFound([]() {
    iotWebConf.handleNotFound();
});

//设置 MQTT ===================================================================================================
// client.setServer("192.168.3.125", 1883);
client.setServer(mqttServerValue, 1883);
client.setCallback(callback);
if (client.connected()) {
    char mymapic;
    strcpy(mymapic, mapic);          // strcpy(复制目的字符串,来源字符串
    strcat(mymapic, "/#");
    client.subscribe(mymapic);
}

//设置蜂鸣器===================================================================================================
pinMode(D8, OUTPUT);                           //设置 D8 脚位用于控制蜂鸣
lcd.begin();                                 // 初始化LCD
lcd.backlight();                               //设置LCD背景等亮

//设置继电器===================================================================================================
pinMode(D9, OUTPUT);                        //设置继电器使用 D9 D10 脚位为输出状态
pinMode(D10, OUTPUT);
digitalWrite(D9,HIGH);
digitalWrite(D10,HIGH);
}

void loop() {
// WiFI 运行 ============================================================================================================================
iotWebConf.doLoop();                         // -- 尽可能频繁地调用doLoop.

// MQTT 接收主题(单号) ========================================================================================================================
client.loop();
if (client.connected()) {
    // RFID 运行 ============================================================================================================================
    if ( ! mfrc522.PICC_IsNewCardPresent()) {      // 检查是否为新卡
      delay(50);
      return;
    }
    // Select one of the cards
    if ( ! mfrc522.PICC_ReadCardSerial()) {
      delay(50);
      return;
    }
    else
    {
      // Show some details of the PICC (that is: the tag/card)
      Serial.print(F("Card UID:"));
      // 转换卡号以十六进位的字符串显示
      to_hex(mfrc522.uid.uidByte, mfrc522.uid.size);

      // 蜂鸣器响声
      beep(23);   //不可大于 24

      //发送卡号到 MQTT Broker
      char pubmapic;
      strcpy (pubmapic, mapic);
      strcat(pubmapic, "/uid");
      Serial.println(pubmapic);

      // MQTT 发送主题(卡号) ========================================================================================================================
      Serial.println("connected");
      Serial.println(pubmapic);
      client.publish(pubmapic, hexStr);
      delay(1500);                           //得暂停 要不然回圈会很快扫卡 读好几次
    }
}
else
{
    if (wifiready) {
      reconnect();
    }
}


/**    此段程序取消 因为会紧跟着显示 hello Word 信号数
         将来在发送大量字符串时可以参考使用
    long now = millis();
    if (now - lastMsg > 2000) {
    lastMsg = now;
    ++value;
    snprintf (msg, 50, "hello world #%ld", value);
    Serial.print("Publish message: ");
    Serial.println(msg);
    client.publish("outTopic", msg);
    }
**/

}

// RFID 副程序 =============================================================================================================================
void beep(int len) {
for (int i = 0; i < len; i++) {
    tone(D8, Music, 100); // 从第8Pin发声,发出100ms的声音
    //delay(200);
}
}

// -----------------------------------------------------------------------------------------------------------------------------------------------
// 转换卡号以十六进位的字符串显示
void to_hex(byte *buffer, byte buffSize) {
char* s = &hexStr;
for (byte i = 0; i < buffSize; i++) {
    snprintf(s, 3, "%02x", buffer);
    s += 2;
}
hexStr = 0;
Serial.println(hexStr);
lcd.clear(); //显示清除
lcd.setCursor(0, 0);                //设置显示行列数
lcd.print(F("Card UID:"));          //输出字符到LCD1602上
lcd.setCursor(0, 1);
lcd.print(hexStr);

}

// WiFi 副程序 =============================================================================================================================
void handleRoot()                                                      //处理“/”路径的Web请求.
{
// -- 让IotWebConf测试并处理强制门户请求.
if (iotWebConf.handleCaptivePortal())
{
    // -- 主要的需 求已经提供.
    return;
}
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" charset=\"utf-8\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
s += "<title>网络设置作业</title></head><body>您好!";
s += "<ul>";
s += "<li>固定 IP 设置: ";
s += ipAddressValue;
s += "</ul>";
s += "请至<a href='config'>设置页面</a> 请修改.";
s += "</body></html>\n";

server.send(200, "text/html", s);
}
// -----------------------------------------------------------------------------------------------------------------------------------------------
void configSaved()
{
Serial.println("设置即将更新.");
}
// -----------------------------------------------------------------------------------------------------------------------------------------------
boolean formValidator()
{
Serial.println("Validating form.");
boolean valid = true;

if (!ipAddress.fromString(server.arg(ipAddressParam.getId())))
{
    ipAddressParam.errorMessage = "请提供正确的 IP 位址!";
    valid = false;
}
if (!netmask.fromString(server.arg(netmaskParam.getId())))
{
    netmaskParam.errorMessage = "请提供正确的子网掩码!";
    valid = false;
}
if (!gateway.fromString(server.arg(gatewayParam.getId())))
{
    gatewayParam.errorMessage = "请提供正确的网关位址!";
    valid = false;
}

return valid;
}
// -----------------------------------------------------------------------------------------------------------------------------------------------
boolean connectAp(const char* apName, const char* password)
{
// -- 自定义AP设置
return WiFi.softAP(apName, password, 4);
}
// -----------------------------------------------------------------------------------------------------------------------------------------------
void connectWifi(const char* ssid, const char* password)
{
ipAddress.fromString(String(ipAddressValue));
netmask.fromString(String(netmaskValue));
gateway.fromString(String(gatewayValue));

if (!WiFi.config(ipAddress, gateway, netmask)) {
    Serial.println("WiFi 连接失败 请检查网络设置");
}
wifiready = true;
Serial.print("ip: ");
Serial.println(ipAddress);
Serial.print("gw: ");
Serial.println(gateway);
Serial.print("net: ");
Serial.println(netmask);
WiFi.begin(ssid, password);
}

// MQTT 副程序 =============================================================================================================================
// 接收主题後调用进程
void callback(char* topic, byte* payload, unsigned int length) {
String mapre01;                                       // 预定收到的主题1   /re01
String mapre02;                                       // 预定收到的主题2   /re02
String mapre03;                                       // 预定收到的主题3   /inp
String mappu01;                                       // 预定发送的主题3   /UID
String mapres;                                        // 实际从 MQTT Broker 接收到的主题
String information;                                 // 实际从 MQTT Broker 接收到的主题内容
String RelayOpen="1";
//将 char[] 转为 String charToStringL(需转换的 Char数组, 转换後的 String)
charToStringL(mapic, mapre01);                        //用户自设的主题
charToStringL(mapic, mapre02);
charToStringL(mapic, mapre03);
charToStringL(mapic, mappu01);
mapre01 = mapre01 + "/re01";                        //1号继电器 的主题
mapre02 = mapre02 + "/re02";                        //2号继电器 的主题息
mapre03 = mapre03 + "/inp";                           //其他收到的主题
mappu01 = mappu01 + "/uid";                           //发布的主题
charToStringL(topic, mapres);                         //实际从 MQTT Broker 接收到的主题
for (int i = 0; i < length; i++) {                  //读取收到的字符串
    information = information + (char)payload;
}
if (mapres != mappu01) {                              // 不显示发布的主题
   Serial.print("接收消息 " + mapres + " [");
   Serial.print(information);
   Serial.print("] ");
   lcd.clear();                                       // LCD 显示清除
   lcd.setCursor(0, 0);                               // 设置显示行列数
   lcd.print("Message:");
   lcd.setCursor(0, 1);
   beep(15);                                          // 蜂鸣器响声 24
   beep(15);
}

if (mapres == mapre01) {
    if (information == RelayOpen) {               
      Serial.println("Open Relay-1");
      lcd.print("Open Relay-1");                         //输出消息到 LCD1602 显示
      digitalWrite(D9,LOW);
    }
    else {
      Serial.println("Close Relay-1");
      lcd.print("Close Relay-1");
      digitalWrite(D9,HIGH);
    }
}
if (mapres == mapre02) {                  
    if (information == RelayOpen) {
      Serial.println("Open Relay-2");
      lcd.print("Open Relay-2");
      digitalWrite(D10,LOW);
    }
    else {
      Serial.println("Close Relay-2");
      lcd.print("Close Relay-2");
      digitalWrite(D10,HIGH);
    }
}
if (mapres == mapre03) {
    lcd.print(information);
}
/**
    digitalWrite(D9,LOW);
    delay(200);
    digitalWrite(D10,LOW);
    delay(2000);
    digitalWrite(D9,HIGH);
    delay(200);
    digitalWrite(D10,HIGH);
    delay(1000);
**/


Serial.println();

// 收到消息的第一个字符 开发板上 LED 亮灯

if ((char)payload == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
} else {
    digitalWrite(BUILTIN_LED, HIGH);// 关闭 LED 灯
}
}

void reconnect() {
// 一直循环直到连上 MQTT Broker
while (!client.connected()) {
    Serial.print("正在连接 MQTT Broker...");
    // 随机生成 client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // 开始进行连接
    lcd.clear();                                       // LCD 显示清除
    lcd.setCursor(0, 0);                                 // 设置显示行列数
    if (client.connect(clientId.c_str(), mqttUserNameValue, mqttUserPasswordValue)) {
      Serial.println("MQTT Broker 已经连接上");
      char mymapic;
      strcpy(mymapic, mapic);          // strcpy(复制目的字符串,来源字符串
      strcat(mymapic, "/#");
      client.subscribe(mymapic);
      
      lcd.print("RFID Ready:");                        // 正确开机 在LCD 显示消息
   
    } else {
      Serial.print("连接失败, rc=");
      Serial.print(client.state());
      Serial.println("五秒钟之后再连接");
      lcd.print("failed, rc=");                        // 在LCD 显示错误消息
      lcd.print(client.state());                        
      lcd.setCursor(0, 1);
      lcd.print("try again in 5 seconds... ");
      delay(5000);
    }
}
}

//将 char[] 转为 String 自订函数
void charToStringL(const char S[], String & D)
{
byte at = 0;
const char *p = S;
D = "";

while (*p++) {
    D.concat(S);
}
}
```

&emsp;&emsp;刷写完成后,重启 ESP8266 ,此时 WiFi 是以 AP 模式运行的,我们用手机或者电脑连接到SSID为 `Relay` 的无限网络,使用浏览器访问 <http://192.168.4.1>,打开网页页面,点击设置页面,进入设置的页面程序。根据页面要求设置对应的连接项或者设置项,其中的 MQTT 相关的设置项是为后续的连接作铺垫的,所以测试时,也请先设置好可用的MQTT服务器。设置保存后断开连接,并重启ESP8266。

&emsp;&emsp;在通电后,请先立即移除 ESP8266 针脚 TX RX 的连接,查看 LCD 屏幕的显示情况。等待 LCD 屏幕显示 `RFID Ready` 后,再将 TX RX 针脚重新接上。这个时候,可以将卡片放置于 MFRC522 的感应区,可以听到蜂鸣器的声音,同时屏幕上会显示刷卡的结果。

&emsp;&emsp;到这里了,你可能会问,这个继电器怎么没用上啊?MQTT 是干什么用的?接下来还会有更新的内容,希望大家能持续关注。
页: [1]
查看完整版本: RC522 RFID 模块上手,由浅入深,探索一下整合(持续更新)