带联网功能的RFID宿舍门禁(六)-两年后的再次总结

带联网功能的RFID宿舍门禁

两年后更新,为什么更新?因为有门课能拿它来扯

项目介绍

涉及技术

  1. 射频识别技术(Radio-frequency identification, RFID)。
  2. WiFi 联网。

项目出发点

  • 以更低的成本实现项目所需功能。
    1. 物料成本低。
    2. 学习成本低。
    3. 结合 RFID 与联网功能。

设计方向

  • 实现一个门禁装置,该门禁装置需要允许学生卡刷卡开门,以及联网控制开门。
    • RFID的一个简单应用就是门禁装置,通过刷卡控制舵机转动,舵机拉动门锁。
    • 加上联网功能后,手机连上控制设备的WiFi,打开控制网页控制舵机转动,舵机拉动门锁。

实现效果

  1. RFID: 在感应装置刷录入系统的学生卡后,可控制舵机转动。
  2. WiFi: 连上 WiFi,登录控制页面后,点击控制按钮,可控制舵机转动。
  3. 舵机: 舵机转动带动门锁,并打开门锁(实际实现中因舵机动力不足无法完全拉开门锁)。

实现过程

  1. 选择 RFID 与 WIFI 模块、实现平台、实现语言
  2. 测试 WIFI 模块与 RFID 模块
  3. 实现 WIFI 功能
  4. 实现 RFID 功能
  5. 融合 WIFI 与 RFID 功能

路径选择

资料收集

  1. 网上是否有现成或类似的方案?
  2. 该方案实现效果是否满足需求?
  3. 该方案所需成本是否可以接受?

确定目标

  • 硬件:
    • RFID 模块:MFRC522
    • WiFi 模块:ESP8266
    • 开发板:Arduino Nano V3 CH340G
    • 舵机:SG90
  • 开发平台:
    • Arduino
  • 编程语言:
    • C

首次实验

实验目的

  • 测试烧录与串口通信

实验结果

  • Arduino 环境配置。
  • 实验了 ESP8266 的烧录。
  • 学习了 Lua 与 CH340 开发板通信。

测试 WiFi 模块

实验目的

  • 使用 ESP8266,开放热点,建立简单网站。

实验材料

ESP8266
WiFi 模块
NodeMCU.jpg

实验过程

  1. ESP8266 环境配置
    • 环境下载速度慢:
      1. 用连谷歌的网络下载。
      2. 更换第三方下载源。
      3. 使用默认下载,然后用其它地方发布的该文件替换它(文件数量少)。
  2. ESP8266 建站及开放热点
    • 参考网上的代码,搞清楚各函数意义,修改为适用于本实现的代码。
  3. 测试连接
    • 根据代码写好的 WiFi 名与密码,使用手机连接 ESP8266 的热点,并在电脑上通过串口通信查看是否连接正常。

实验代码

#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库

ESP8266WebServer esp8266_server(80);// 建立ESP8266WebServer对象,对象名称为esp8266_server
                                    // 括号中的数字是网路服务器响应http请求的端口号
                                    // 网络服务器标准http端口号为80,因此这里使用80为端口号
#define WIFISSID "ESP8266Web"     //设定ESP8266 wifi名称
#define WIFIPSSD "123456789"      //设定wifi密码

void setup(void){
  Serial.begin(115200);          // 启动串口通讯
  setAP();                       // 设定AP模式,并建立热点。

//--------"启动网络服务功能"程序部分开始-------- //  此部分为程序为本示例程序重点1
  esp8266_server.begin();                   //  详细讲解请参见太极创客网站《零基础入门学用物联网》
  esp8266_server.on("/", handleRoot);       //  第3章-第2节 ESP8266-NodeMCU网络服务器-1
  esp8266_server.onNotFound(handleNotFound);        
//--------"启动网络服务功能"程序部分结束--------
  Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}

void loop(void){
  esp8266_server.handleClient();     // 处理http服务器访问
}

void setAP(){
  WiFi.mode(WIFI_AP);               // AP模式设定
  WiFi.softAP(WIFISSID,WIFIPSSD);   // WIFI热点建立
  Serial.printf("Success!\nWIFISSID:  %s \nWIFIPSSD:  %s \nControlWeb:  ", WIFISSID, WIFIPSSD);     // 输出相关信息
  Serial.println(WiFi.softAPIP());  // 输出网站地址
}

void handleRoot() {   //处理网站根目录“/”的访问请求 
  esp8266_server.send(200, "text/plain", "ESP8266 WEB CONTROL PAGE.\n       -mwhls.top");   // NodeMCU将调用此函数。
}

// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){                                        // 当浏览器请求的网络资源无法在服务器找到时,
  esp8266_server.send(404, "text/plain", "404: Not found");   // NodeMCU将调用此函数。
}

实验结果

  • ESP8266 开放热点并建站后,串口输出相关信息。
  • 手机可通过 WiFi 连上 ESP8266,并连接至控制网站。

测试RFID模块

实验目的

  • 使用 RC522,当校园卡刷卡时,使舵机转动。

实验材料及连线

SG90 9克舵机MFRC522Arduino Nano V3 CH340G
拉动门锁RFID 模块开发板
SG90.jpgRC522.jpgNANO.jpg
Arduino Nano V3 CH340GSG90(颜色)RC522(顺序)
GNDGND (棕)
5V5V (红)
D8PWM信号 (黄)
D9RST (2)
D10SDA (8)
D11MOSI (6)
D12MISO (5)
D13SCK (7)
3V33.3V (1)
GNDGND (3)

实验过程

  1. 刷卡控制舵机转动。
  2. 添加学生卡为通行卡。
    • 实现刷学生卡开门。
    • 读取学生卡的 ID,并创建通行卡数组,将 ID 写入数组。
  3. 舵机正转反转实现。
    • 实现拉动及恢复门锁。
    • 正转:拉动门锁。
    • 反转:恢复门锁。

实验代码

#include <SPI.h>
#include <MFRC522.h>

#define SS_PIN 10
#define RST_PIN 9
#define SERVO_PIN 8
#define USER_NUM 3

byte servoRun = 0;              // 舵机是否运行。
MFRC522 rfid(SS_PIN, RST_PIN);  // 实例化类
byte userCard[USER_NUM][4] = {  // 通行卡存储数组。
  {28,   184,  119,  33},
  {249,  231,  71,   179},
  {109,  242,  234,  235}
};

void setup() { 
  Serial.begin(9600);           // 波特率设置
  SPI.begin();                  // 初始化SPI总线
  rfid.PCD_Init();              // 初始化 MFRC522 
  pinMode(SERVO_PIN, OUTPUT);   // 舵机控制端口
}

void loop() {
  if(servoRun == 1){            // 舵机运行变量若为1,则运行。
    servoControl();             // 舵机控制函数。
  }

  if ( ! rfid.PICC_IsNewCardPresent()) return;       // 找卡
  if ( ! rfid.PICC_ReadCardSerial())   return;       // 验证NUID是否可读
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&  // 检查是否MIFARE卡类型
    piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
    piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println("Can identify this card!");
    return;
  }

  byte i;
  for (i=0; i<USER_NUM;  i++){    // 判断卡是否为通行卡。
    byte i2;
    for(i2=0;  i2<4; i2++){       // 遍历userCard中所有卡。
      if(rfid.uid.uidByte[i2] != userCard[i][i2]) break;  // break时,表示此卡不是通行卡。
    }
    if(i2 == 4){                  // i2为4,表示此卡的四位值都验证通过。
      Serial.println("Find an accessful card.");  // 输出成功信息。
      servoRun = 1;               // 将开门变量置1。
      break;                      // 已找到通行卡,跳出循环。
    }
  }
  if(i==USER_NUM){                // 若i等于通行用户数量,则上层循环未找到通行卡。
    Serial.print("Find a unknown card, its uid:");
    for(i=0;  i<4;  i++){         // 输出此卡UID。
      Serial.print(rfid.uid.uidByte[i], DEC);
      Serial.print(" ");
    }
    Serial.println();
  }

  rfid.PICC_HaltA();              // 使放置在读卡区的IC卡进入休眠状态,不再重复读卡
  rfid.PCD_StopCrypto1();         // 停止读卡模块编码

}

void servoControl(){              // 舵机控制函数。
  Serial.println("Servo run!");   // 函数运行输出标识。
  servoPulse(0);                  // 舵机转至0度。
  delay(1000);                    // 等待舵机运转。
  servoPulse(180);                // 舵机转至180度。
  servoRun = 0;                   // 舵机运行变量置零。
}

void servoPulse(int myangle)      // 定义一个脉冲函数,作者:https://blog.csdn.net/sss_369/article/details/52894347
{
  int pulseWidth=(myangle*11)+500;// 将角度转化为500-2480 的脉宽值
  digitalWrite(SERVO_PIN,HIGH);   // 将舵机接口电平至高
  delayMicroseconds(pulseWidth);  // 延时脉宽值的微秒数weimiao
  digitalWrite(SERVO_PIN,LOW);    // 将舵机接口电平至低
  delay(20-pulseWidth/1000);
}

实验结果

  • RC522 读取到未录入通行数组的卡时,串口会输出对应卡 ID 信息。
  • RC522 读取到学生卡时,会触发舵机转动。
  • 舵机触发转动后,将正转 180 度,在 1 秒后回转180度。

连接 WiFi 模块与 RFID 模块

实验目的

  • 可通过 WiFi 连接至控制网站以转动舵机;也可通过刷学生卡来转动舵机。

实验材料及连线

引脚图画线.jpg

名称用途数量
Arduino Nano V3 CH340G 及配套数据线开发板1
MFRC522RFID 模块1
NodeMCU(ESP8266 CH340串口) 及配套数据线WiFi 模块1
SG90舵机1
母对母杜邦线导线13
公对公杜邦线导线3
支持微电流的两万毫安小米充电宝电源1
Arduino Nano V3 CH340G(引脚)NodeMCU(引脚)RC522(顺序)SG90(颜色)
GNDGND
A4D1
A5D2
D9RST (2)
D10SDA (8)
D11MOSI (6)
D12MISO (5)
D13SCK (7)
3V33.3V (1)
GNDGND (3)
5V5V(红)
D8PWM信号(黄)
GNDGND (棕)

实验过程

  1. 开发板开启通信端口,接收外部信号。
  2. WiFi 模块开放热点,并建立可交互网站。
  3. 与网站交互后,WiFi 模块发送舵机转动信号至开发板,开发板触发舵机转动。
  4. RC522 读取到学生卡后,开发板触发舵机转动。

实验环境

  • 烧录平台:Arduino 1.8.13
  • 开发板:NodeMCU 1.0

实验代码 - 开发板

/* 作者:MWHLS,主页MWHLS.TOP
 * 链接:http://mwhls.top/?p=659
 * 因为使用的不是SERVO.H库,舵机的PWM控制端口并不局限于9/10两个端口,且也不局限于仅控制两个舵机。
 * 通行卡的存储使用二维数组,将卡的UID转为十进制保存。
 * 卡的对比使用for函数遍历二维数组,对比UID是否相同。
 * 舵机启动由舵机控制变量servoRun控制,若值为1,则启动,其余不运行。
 * 接受到NodeMCU传来的信号时,舵机控制变量置1。
 * 发现通行卡时,舵机控制变量置1。
 * 参考文章:
 * 网页控制:https://blog.csdn.net/qq_46292418/article/details/106605366
 * I2C通信:https://blog.csdn.net/qq_44506730/article/details/90578507
 * RC522读卡:https://blog.csdn.net/leytton/article/details/73480974
 * 舵机控制:https://blog.csdn.net/sss_369/article/details/52894347
 */ 

#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>              //使用Wire.h进行I2C通信

#define SS_PIN 10
#define RST_PIN 9
#define SERVO_PIN 8
#define USER_NUM 3

byte servoRun = 0;              // 舵机控制变量。
MFRC522 rfid(SS_PIN, RST_PIN);  // 实例化类
byte userCard[USER_NUM][4] = {  // 通行卡存储数组。
  {28,   184,  119,  33},
  {249,  231,  71,   179},
  {109,  242,  234,  235}
};

void setup() { 
  Serial.begin(9600);           // 波特率设置
  SPI.begin();                  // 初始化SPI总线
  rfid.PCD_Init();              // 初始化 MFRC522 
  pinMode(SERVO_PIN, OUTPUT);   // 舵机控制端口。
  Wire.begin(8);                // 设置与NodeMCU的通信I2C端口。
  Wire.onReceive(receiveEvent); // 信号接受处理。
}

void loop() {
  if(servoRun == 1){            // 舵机运行变量若为1,则运行。
    servoControl();             // 舵机控制函数。
  }

  if ( ! rfid.PICC_IsNewCardPresent()) return;       // 找卡
  if ( ! rfid.PICC_ReadCardSerial())   return;       // 验证NUID是否可读
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&  // 检查是否MIFARE卡类型
    piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
    piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println("Can identify this card!");
    return;
  }

  byte i;
  for (i=0; i<USER_NUM;  i++){    // 判断卡是否为通行卡。
    byte i2;
    for(i2=0;  i2<4; i2++){       // 遍历userCard中所有卡。
      if(rfid.uid.uidByte[i2] != userCard[i][i2]) break;  
    }                             // break时,表示此卡不是通行卡。
    if(i2 == 4){                  // i2为4,表示此卡的四位值都验证通过。
      Serial.println("Find an accessful card.");  // 输出成功信息。
      servoRun = 1;               // 将开门变量置1。
      break;                      // 已找到通行卡,跳出循环。
    }
  }
  if(i==USER_NUM){                // 若i等于通行用户数量,则上层循环未找到通行卡。
    Serial.print("Find a unknown card, its uid:");
    for(i=0;  i<4;  i++){         // 输出此卡UID,便于后期新增通行卡。
      Serial.print(rfid.uid.uidByte[i], DEC);
      Serial.print(" ");
    }
    Serial.println();
  }

  rfid.PICC_HaltA();              // 使放置在读卡区的IC卡进入休眠状态,不再重复读卡
  rfid.PCD_StopCrypto1();         // 停止读卡模块编码

}

void servoControl(){              // 舵机控制函数。
  Serial.println("Servo run!");   // 函数运行输出标识。
  servoPulse(0);                  // 舵机转至0度。
  delay(1000);                    // 等待舵机运转。
  servoPulse(180);                // 舵机转至180度。
  servoRun = 0;                   // 舵机运行变量置零。
}

void servoPulse(int myangle)      // 定义一个脉冲函数,作者:https://blog.csdn.net/sss_369/article/details/52894347
{
  int pulseWidth=(myangle*11)+500;// 将角度转化为500-2480 的脉宽值
  digitalWrite(SERVO_PIN,HIGH);   // 将舵机接口电平至高
  delayMicroseconds(pulseWidth);  // 延时脉宽值的微秒数weimiao
  digitalWrite(SERVO_PIN,LOW);    // 将舵机接口电平至低
  delay(20-pulseWidth/1000);
}

void receiveEvent(int howMany){   // 定义接受联网信息函数,参考:https://blog.csdn.net/qq_44506730/article/details/90578507
  while(0<Wire.available()){      
    char c = Wire.read();
    if (c == '1')  servoRun = 1;  // 如果传入数据为1,则舵机运行变量置1。
    Serial.println("Receive an access sign from ESP8266.");  
  }
}

实验代码 - WiFi 模块

/* 作者:MWHLS,主页MWHLS.TOP
 * 链接:http://mwhls.top/?p=659
 * 通过主机连接上ESP8266热点,进入通信网址,点击CLICK按钮后,
 * 一个消息会使用I2C通信传输给Arduino,这个消息会触发舵机转动。
 * 参考文章:
 * I2C通信:https://blog.csdn.net/qq_44506730/article/details/90578507
 * 网页控制:https://blog.csdn.net/qq_46292418/article/details/106605366
 */
#include <ESP8266WiFi.h>            // 本程序使用 ESP8266WiFi库
#include <ESP8266WebServer.h>       // ESP8266WebServer库
#include <Wire.h>                   // 使用Wire.h进行I2C通信

ESP8266WebServer esp8266_server(80);// 建立ESP8266WebServer对象,对象名称为esp8266_server
                                    // 括号中的数字是网路服务器响应http请求的端口号
                                    // 网络服务器标准http端口号为80,因此这里使用80为端口号
#define WIFISSID "ESP8266Web"       // 设定ESP8266 wifi名称
#define WIFIPSSD "123456789"        // 设定wifi密码

void setup(void){
  Serial.begin(9600);               // 启动串口通讯
  Wire.begin(D1,D2);                // I2C通信端口
  setAP();                          // 设定AP模式,并建立热点。

//--------"启动网络服务功能"程序部分开始--------           // 此部分为程序为本示例程序重点1
  esp8266_server.begin();                             // 详细讲解请参见太极创客网站《零基础入门学用物联网》
  esp8266_server.on("/", HTTP_GET, handleRoot);       // 第3章-第2节 ESP8266-NodeMCU网络服务器-1
  esp8266_server.on("/CLICK", HTTP_POST, handleClick);// 处理用户点击消息。
  esp8266_server.onNotFound(handleNotFound);          // 404处理。
//--------"启动网络服务功能"程序部分结束--------
  Serial.println("HTTP esp8266_server started");      // 告知用户ESP8266网络服务功能已经启动
}

void loop(void){
  esp8266_server.handleClient();                      // 处理http服务器访问
}

void setAP(){
  WiFi.mode(WIFI_AP);                                 // 设定ESP8266的AP模式
  WiFi.softAP(WIFISSID,WIFIPSSD);                     // 设定ESP8266热点
  Serial.printf("Success!\nWIFISSID:  %s \nWIFIPSSD:  %s \nControlWeb:  ", WIFISSID, WIFIPSSD);
  Serial.println(WiFi.softAPIP());                    // 接上行,输出WIFI信息与通信网址。
}

void handleRoot() {                                   // 处理网站根目录“/”的访问请求 
  esp8266_server.send(200, "text/html", "<form action=\"/CLICK\" method=\"POST\"><input type=\"submit\" value=\"CLICK\"></form>");
}

void handleClick(){                                   // 点击消息处理函数
  Serial.println("Click.");                           
  clickTransmission();                                // 传输点击消息到Arduino板。
  esp8266_server.sendHeader("Location","/");          // 跳转回页面根目录
  esp8266_server.send(303);                           // 发送Http相应代码303 跳转  
}

void clickTransmission(){                             // 点击消息传输函数
  Wire.beginTransmission(8);                          // 开始传输
  Wire.write('1');                                    // 传 1 至Arduino版
  Wire.endTransmission();                             // 结束传输
  Serial.println("Click transmiss success.");         // 输出成功信息
}

// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){                                        // 当浏览器请求的网络资源无法在服务器找到时,
  esp8266_server.send(404, "text/plain", "404: Not found");   // NodeMCU将调用此函数。
}

实验结果

  • RC522 读取到学生卡时,触发舵机转动。
  • RC522 读取到未录入的卡时,串口输出卡 ID。
  • 手机连接至 ESP8266 热点后,登录 192.168.4.1 ,点击 Click 以触发舵机转动。
  • 舵机收到触发信号,先正转 180 度,再回转 180 度。

成果展示

视频及图片

  • 没有视频图床,以后想起来再补视频。
  • 实物连线图.jpg

材料成本

  • 合计 49.75 元,其中 RC522 因为坏了一块重买了,去掉之后只有 44.95 元。
材料用途数量价格
RC522RFID 模块24.8 * 2
公对公杜邦线 (10cm)导线11.9
母对母杜邦线 (30cm)导线11.65
NodeMCU(ESP8266 CH340串口) 及配套数据线WiFi 模块114.8
SG90 9克舵机舵机15.1
Arduino Nano V3 CH340G 及配套数据线开发板116.7

优点

  1. 完成了所需功能。
  2. 成本控制令我满意。
  3. 学习成本低,生态好,且可直接使用 C 语言实现。

缺点

  1. 舵机拉力太小,无法拉动门锁,中看不中用。
  2. RC522 质量太差,第一天正常,第二天就坏了,得刷三次卡才能触发一次,不过还好当时录了视频。

版权声明:
作者:MWHLS
链接:http://panwj.top/4066.html
来源:无镣之涯
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
< <上一篇
下一篇>>