带联网功能的RFID宿舍门禁(五)-项目总结(2020/12/4更新)

带联网功能的RFID宿舍门禁项目目录Github项目地址

2020/12/4:加了项目优点,美化了排版,现在更花里胡哨了。

效果展示视频

http://pan-yz.chaoxing.com/preview/showpreview_536535694800277504.html?v=1605849878000

完成效果

  • 舵机转动:收到转动信号后,舵机正转180°,后逆转180°复原。
  • 读卡转动舵机:RC522读卡器读到已知卡时,会向舵机发送转动信号。
  • 联网控制舵机:ESP8266启动wifi后,使用任意带无线网卡的主机连接到ESP8266Web网络后,打开192.168.4.1后,可进入舵机控制页面,点击控制键后,可向舵机发送转动信号。
  • 未知卡ID读取:将nano板连接至电脑,可显示串口信息后,将未知的卡放在读卡器上,可输出卡ID。
  • 新卡添加:将卡ID加入nano代码的userCard数组中,再将USER_NUM加一,即可添加新卡,可添加校园卡并正常刷卡转动。

优点

  • 扩展性好:控制信号触发,控制信号控制装置,装置运行,三个部分均是分开运行,易于扩展。
    如需加入蓝牙控制,只需在蓝牙信号处理中将控制信号置为1即可。
    如需控制多个装置,只需将控制信号处理中增加新控制函数即可。
    如需改变开门装置,直接将舵机转动函数更换成相应控制函数即可。
  • 解决未带卡的痛点:在用户未带卡的时候可以通过wifi控制开门。
  • 组装方便:无需焊接,不用担心虚焊。
  • 成本低:在组装方便且实现基本功能的基础上,使用价格较低的器件,不购买附带多余功能的器件。

不足与改进方向

  • 舵机环形转动,拉动宿舍门栓时会转到一个地方卡主,即因为不能平行拉动,无法正常拉动门栓,于是换了一栋楼尝试。
    舵机力量太小,在另一栋楼又无法拉动门栓。
    改进方向:改用平移的舵机,或使用拉力更大的舵机。
  • RC522质量差,在使用时,第一片RC522可正常转动,但一天后损坏,
    而后又买了一片RC522,在示例程序中也无法正常使用,只能读三次卡后,转动一次舵机,然后只能重启后才能继续读卡。
    但wifi模块始终正常运行。
    改进方向:更换读卡芯片,或换一家质量好的店铺。
  • 电源使用小米20000毫安微电流充电宝,价格将近整套材料三倍。
    改进方向:使用电池供电。

材料及费用

除自带的充电宝作为电源外,零件理论共44.6元,但实际使用中,RC522坏了一块,于是重新购买,再扣去红包折扣,实际花费44.82元。
当然,如果直接用电脑,也是不用电源的。

名称用途数量价格/元
Arduino Nano V3 及配套数据线开发板116.7
MFRC522RFID读卡器14.8
NodeMCU(CH340串口) 及配套数据线ESP8266模块114.8
SG90舵机15.1
母对母杜邦线导线131.6
公对公杜邦线导线31.6
支持微电流的两万毫安小米充电宝电源1-

连线

Arduino(引脚)NodeMCU(引脚)RC522(顺序)SG90(颜色)
GNDGND
A4D1
A5D2
D9RST (2)
D10SDA (8)
D11MOSI (6)
D12MISO (5)
D13SCK (7)
3V33.3V (1)
GNDGND (3)
5V5V(红)
D8PWM信号(黄)
GNDGND (棕)

Arduino Nano代码及功能介绍

Arduino 1.8.13
开发板:Arduino Nano
处理器:ATmega328P (Old Bootloader)

代码功能介绍:

  • 基于MFRC522.h提供的实例库,实例库提供了寻卡、卡类型识别、卡验证、防碰撞等基本功能,
  • 加入了卡的存储管理数组userCard,用于存储卡ID的十进制数据。
  • 加入了舵机控制函数,收到信号后,控制舵机转动180°后,回转180°回到原位,舵机使用脉冲控制替换了舵机库控制,因此不限于特定引脚发送信号。
  • 加入了读特定卡后舵机转动功能,读到卡后,与userCard中数据对比,若相同,则向舵机发送转动信号。
  • 加入了读未知卡后串口输出卡ID功能,将卡ID添加至userCard数组后,将USER_NUM加一,即可添加新卡。
  • 加入了I2C通信函数,NodeMCU板通过I2C通信,将信号传输到Nano版,验证信号后,向舵机发送转动信号。
/* 作者:MWHLS,主页MWHLS.TOP
 * 链接:http://mwhls.top/?p=1075
 * 因为使用的不是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.");  
  }
}

NodeMCU代码及功能介绍

Arduino 1.8.13
开发板:NodeMCU 1.0
其余设置默认。

代码功能介绍:

  • NodeMCU通电后自动运行代码,
  • 将使用AP模式开启一个ESP8266Web的wifi,
  • 并建立一个简单网页,
  • 网页中有一个基于I2C通信的按钮,在按下后,NodeMCU会向Nano板发送信号。
  • 将NodeMCU与主机连接,监听串口信息,在wifi开启后,串口会输出wifi相关信息,包括wifi名称,wifi密码以及控制页面地址。
<pre id="block-c0073fc6-054a-4469-98b1-29aa9dca8bb9" class="wp-block-code"><code>/* 作者:MWHLS,主页MWHLS.TOP
 * 链接:http://mwhls.top/?p=1075
 * 通过主机连接上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将调用此函数。
}

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

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