已阅: 20
带联网功能的RFID宿舍门禁
两年后更新,为什么更新?因为有门课能拿它来扯
项目介绍
涉及技术
- 射频识别技术(Radio-frequency identification, RFID)。
- WiFi 联网。
项目出发点
- 以更低的成本实现项目所需功能。
- 物料成本低。
- 学习成本低。
- 结合 RFID 与联网功能。
设计方向
- 实现一个门禁装置,该门禁装置需要允许学生卡刷卡开门,以及联网控制开门。
- RFID的一个简单应用就是门禁装置,通过刷卡控制舵机转动,舵机拉动门锁。
- 加上联网功能后,手机连上控制设备的WiFi,打开控制网页控制舵机转动,舵机拉动门锁。
实现效果
- RFID: 在感应装置刷录入系统的学生卡后,可控制舵机转动。
- WiFi: 连上 WiFi,登录控制页面后,点击控制按钮,可控制舵机转动。
- 舵机: 舵机转动带动门锁,并打开门锁(实际实现中因舵机动力不足无法完全拉开门锁)。
实现过程
- 选择 RFID 与 WIFI 模块、实现平台、实现语言
- 测试 WIFI 模块与 RFID 模块
- 实现 WIFI 功能
- 实现 RFID 功能
- 融合 WIFI 与 RFID 功能
路径选择
资料收集
- 网上是否有现成或类似的方案?
- 该方案实现效果是否满足需求?
- 该方案所需成本是否可以接受?
确定目标
- 硬件:
- RFID 模块:MFRC522
- WiFi 模块:ESP8266
- 开发板:Arduino Nano V3 CH340G
- 舵机:SG90
- 开发平台:
- 编程语言:
首次实验
实验目的
实验结果
- Arduino 环境配置。
- 实验了 ESP8266 的烧录。
- 学习了 Lua 与 CH340 开发板通信。
测试 WiFi 模块
实验目的
实验材料
ESP8266 |
---|
WiFi 模块 |
|
实验过程
- ESP8266 环境配置
- 环境下载速度慢:
- 用连谷歌的网络下载。
- 更换第三方下载源。
- 使用默认下载,然后用其它地方发布的该文件替换它(文件数量少)。
- ESP8266 建站及开放热点
- 参考网上的代码,搞清楚各函数意义,修改为适用于本实现的代码。
- 测试连接
- 根据代码写好的 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模块
实验目的
实验材料及连线
SG90 9克舵机 | MFRC522 | Arduino Nano V3 CH340G |
---|
拉动门锁 | RFID 模块 | 开发板 |
| | |
Arduino Nano V3 CH340G | SG90(颜色) | RC522(顺序) |
---|
GND | GND (棕) | |
5V | 5V (红) | |
D8 | PWM信号 (黄) | |
D9 | | RST (2) |
D10 | | SDA (8) |
D11 | | MOSI (6) |
D12 | | MISO (5) |
D13 | | SCK (7) |
3V3 | | 3.3V (1) |
GND | | GND (3) |
实验过程
- 刷卡控制舵机转动。
- 添加学生卡为通行卡。
- 实现刷学生卡开门。
- 读取学生卡的 ID,并创建通行卡数组,将 ID 写入数组。
- 舵机正转反转实现。
- 实现拉动及恢复门锁。
- 正转:拉动门锁。
- 反转:恢复门锁。
实验代码
#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 连接至控制网站以转动舵机;也可通过刷学生卡来转动舵机。
实验材料及连线
名称 | 用途 | 数量 |
---|
Arduino Nano V3 CH340G 及配套数据线 | 开发板 | 1 |
MFRC522 | RFID 模块 | 1 |
NodeMCU(ESP8266 CH340串口) 及配套数据线 | WiFi 模块 | 1 |
SG90 | 舵机 | 1 |
母对母杜邦线 | 导线 | 13 |
公对公杜邦线 | 导线 | 3 |
支持微电流的两万毫安小米充电宝 | 电源 | 1 |
Arduino Nano V3 CH340G(引脚) | NodeMCU(引脚) | RC522(顺序) | SG90(颜色) |
---|
GND | GND | | |
A4 | D1 | | |
A5 | D2 | | |
D9 | | RST (2) | |
D10 | | SDA (8) | |
D11 | | MOSI (6) | |
D12 | | MISO (5) | |
D13 | | SCK (7) | |
3V3 | | 3.3V (1) | |
GND | | GND (3) | |
5V | | | 5V(红) |
D8 | | | PWM信号(黄) |
| GND | | GND (棕) |
实验过程
- 开发板开启通信端口,接收外部信号。
- WiFi 模块开放热点,并建立可交互网站。
- 与网站交互后,WiFi 模块发送舵机转动信号至开发板,开发板触发舵机转动。
- 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 度。
成果展示
视频及图片
- 没有视频图床,以后想起来再补视频。
材料成本
- 合计 49.75 元,其中 RC522 因为坏了一块重买了,去掉之后只有 44.95 元。
材料 | 用途 | 数量 | 价格 |
---|
RC522 | RFID 模块 | 2 | 4.8 * 2 |
公对公杜邦线 (10cm) | 导线 | 1 | 1.9 |
母对母杜邦线 (30cm) | 导线 | 1 | 1.65 |
NodeMCU(ESP8266 CH340串口) 及配套数据线 | WiFi 模块 | 1 | 14.8 |
SG90 9克舵机 | 舵机 | 1 | 5.1 |
Arduino Nano V3 CH340G 及配套数据线 | 开发板 | 1 | 16.7 |
优点
- 完成了所需功能。
- 成本控制令我满意。
- 学习成本低,生态好,且可直接使用 C 语言实现。
缺点
- 舵机拉力太小,无法拉动门锁,中看不中用。
- RC522 质量太差,第一天正常,第二天就坏了,得刷三次卡才能触发一次,不过还好当时录了视频。
共有 0 条评论