Arduino NFC 低成本宿舍门禁(防爆破)(详细)

发布于 2023-12-17  7123 次阅读


刚开学就有了改造宿舍的念头了,不过刚开学一切还没有完全熟悉,就先压下来了,直到我把家里的小爱音箱拿过来,然后让我们的寝室的空调自动起来,再有买了NFC贴纸,让舍友可以很方便的控制寝室里的东西,我发现,我可以对寝室进行进一步改造了。

想要改造的有两个部分一个是寝室的大灯,一个是寝室门。但是我们寝室的灯开关很小,不好改,想要拆开之后深入改,但是没有电笔,没有绝缘的螺丝刀,只能继续推推。在与创协会长进行一番交流后,我开始准备对宿舍门进行改造了。

在网上找了,并一番实操后,发现虽然类似的文章有很多,实际操作时遇见的问题坑却很多,所以打算记一下制作流程。

材料的选购

所用的工具

烙铁和焊锡(如果没买建议看看广乾的,用着很不错)(用之前先学学如何保养,要不焊一次就废了)

热熔胶枪(9.9包邮,很便宜)

USB 转 TTL(可选,用来在想不出哪出错的时候调试,一般用不到)

主要的部分

杜邦线(公对母的,母对母的)

arduino开发板,可以直接买裸板,买国产的裸板也行,价格在20以内

舵机(买经典的SG90 180度就行,注意不要买功率过高的(arduino板流经的电流尽量在500mA以内,超过500mA或者拉不动可以选择外接电源,外接时舵机的地线除了跟外接电源连接外要跟主板连接))

MFRC-522 NFC模块,可以选择其他的,但是所用库文件跟这篇教程不同

USB Type-A 转USB Type-B(方口)的线,一般买arduino的时候会送,用于下载到开发板以及给开发板供电

其他部分

你可能需要一个充电宝,以及一个充电头给arduino供电,也可以自己做电池供电。我舍友桌子离门近,我用一根两米的USB延长线以及买开发板送的线解决了供电问题。

如果仅主要部分的话成本在30软妹币以内

硬件部分

准备开发环境并测试开发板

https://www.arduino.cc/en/software下载Arduino IDE,并且安装,在进入后接受安装其提供的驱动

安装后在库管理处

下载两个库:Servo 、 MFRC522

之后测试开发板是否可用,将USB线一端插入电脑,一端插入开发板,开发板的电源灯常亮。

在IDE选择如下示例

在右边选择 选择其他开发板和接口

开发版选择Arduino Uno,端口可在设备管理器查找,也可重新插拔看看哪个消失出现,最新版的IDE在接入时会在端口处显示USB,如果显示的话一般就是它。

点击对号测试编译,之后再点击右箭头符号下载到开发板(虽然示例一般不会出错,但这是个好习惯),这个示例的作用是让板载的L灯闪亮,如果它如期运行,说明你运气不是很差

焊接NFC模块

将排插以你认为方便的方法焊到NFC版上,焊的时候注意安全,焊上之后撕下7根母对母的杜邦线,接上除IRQ外的所有接口

撕下三根杜邦线接上舵机

将模块接入开发板

MFRC522的库文件有完整接线的演示,但是经过我测试,一直不读卡,搞不清什么原因

 * Typical pin layout used:
 * -----------------------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno/101       Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15

后来在一篇文章(现在找不到了)中发现将NFC模块RST的线直接接到5V的接口即可解决问题

图片来自 arduino.cc

NFC模块的接法为:(以NFC模块由右至左顺序)

  • 3.3V接到开发板下面的3.3V接口上(一定不要接错!)
  • RST接到开发板5V接口上,可以直接接在3.3V旁边(2024.10.6 订正:应该接 3.3V,此处为芯片的使能,这个模块应该是默认没有接上拉)
  • GND接到开发板GND上,也正好在5V旁边(开发板上所有GND是相连的)

这三条线可以很整齐的都接下面

  • IRQ跳过
  • MISO 接开发板12接口
  • MOSI接开发板11接口
  • SCK接开发板13接口
  • SDA接开发板10接口

这四条线连着接开发板上面的10-13接口(顺序有变)

将舵机接入开发板

如果你买的是跟我一样的舵机,可以选择将线全部接在开发板上。如果不清楚每根线的含义可以去看一下卖家的宣传图或者问一下卖家接线顺序,正极接在5V接口上,(开发板下面还有一个5V),负极接到任一GND接口上,PWM线接到丝印数字上标有”~“的接口上,我接的是6接口,可以根据自己的需求改接(记得改代码)。

如果你的舵机功率过大或者舵机拉不动锁,可以选择外接电源,外接时舵机的正极接外接电源正极,负极接到外接电源负极,并且同时接到开发板负极,PWM线依然接到丝印数字上标有”~“的接口上。

我还在3.4接口接了一个LED灯来做一定的提示。

软件部分

代码读取卡ID的思路借鉴自这篇文章,部分代码来自所用库MFRC522、Servo的实例文件,防爆破部分为自己所写,以下为实现代码

#include <SPI.h>
#include <MFRC522.h>  //  nfc头文件
#include <Servo.h>    //  舵机头文件

/************************************
*                                   *
*        转载请注明出处             *
*        uulin.cn                   *
*                                   *
*************************************/


#define SS_PIN 10  //  定义ss接口
#define RST_PIN 9  //  定义RST接口,在实际运行时接到此接口并未有效,而将RC552的RST改接到5V引脚上了
MFRC522 rfid(SS_PIN, RST_PIN);  //  创建一个rc522读卡器对象
Servo mainservo;   //  创建一个舵机控制对象 
byte nuidPICC[4];  // 初始化数组用于存储读取到的NUID
int conter=0,time=0,nowtime=0;  //  初始化防止爆破的全局变量

void setup()
{
    SPI.begin();   // 初始化SPI总线
    rfid.PCD_Init();    // 初始化 MFRC522
    // Serial.begin(9600);  //  调试时如要启用串口监控取消前面注释
    mainservo.attach(6);   //  设定舵机的接口为6
    mainservo.write(180);  //  设定舵机旋转角度初始角度为180.(可调0~180)
    mainservo.write(70);  //  这三行让舵机呈现第一次启动时候扭动并在1.2s后归位的效果,不喜欢可以删掉
    delay(1200);
    mainservo.write(180);  //  效果结束
    pinMode(4,OUTPUT);
    pinMode(3,OUTPUT);  //  设置3、4这两个接口为输出,为了在这两个接口处接入LED灯
}

void loop()
{
  if ( ! rfid.PICC_IsNewCardPresent())
    return;  // 找卡
 
  if ( ! rfid.PICC_ReadCardSerial())
    return;  // 验证NUID是否可读
 
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  
  for (byte i = 0; i < 4; i++) {
    nuidPICC[i] = rfid.uid.uidByte[i];  // 将NUID保存到nuidPICC数组
    //Serial.println(nuidPICC[i]);  //  取消注释在串口中输出UNID
  }


  // 判断卡是否为已知卡
  if ((nuidPICC[0]==0xFF&& nuidPICC[1]==0xFF&& nuidPICC[2]==0xFF&& nuidPICC[3]==0xFF)||(nuidPICC[0]==0xFF&& nuidPICC[1]==0xFF&& nuidPICC[2]==0xFF&& nuidPICC[3]==0xFF))
  // 此处0xFF为卡的ID,每个括号为一组,数据为16进制,可选择在手机上读卡然后把读的每两个数前加0x


   {
    // Serial.println("识别成功");
    conter=0;  //  防爆破计数器清零
    digitalWrite(4,HIGH);  //  将在3,4接口上的接口的灯点亮
    digitalWrite(3,LOW);
    mainservo.write(70);  //  舵机旋转到70度
    delay(1200);  //  延时1.2s
    mainservo.write(180);  //  舵机回到180度
   }
   else
   {
    // Serial.println("错误的卡"); 
    delay(6000);  //  延时6s加大暴力破解难度,调试时可以调小
      // 当conter=0时,把系统现在的时间赋值给time,记录第一次失败的相对时间
    nowtime=millis();
    if(conter==0)
     time=nowtime;

    conter=conter+1;  //  计数器加一
    int errortime=0;  //  懒了,就把error初始化到这吧,不刷错卡不会占用空间
    errortime=nowtime-time; //  计算差值,下面IF ELSE语句当时间大于100分钟时候下面IF语句假,计数器归零,如果时间小于十分钟,计算是否超过限定错误次数,超过将会锁死
    if(errortime < 6000000)
    {
      if(conter==2)  //  数字加一为限定错误次数
      {
        // Serial.println("已经锁定"); 
        digitalWrite(4,HIGH);  //  将在3,4接口上的接口的灯点亮,想要更安全的话可以把这两行注释掉
        digitalWrite(3,LOW);
        delay(6000000);  //   失败超过三次的延时,此时停在此处不会再读卡,此时延时100,如果不想在寝室外等一百分钟就改小点
        conter=0;  // 计数器归零
      }
    }
    else
    conter=0;
  }
  digitalWrite(4,LOW); //  将在3,4接口上的接口的灯归零
  digitalWrite(3,LOW);
}

如果不出意外,你将这段代码下载到开发板后,舵机会灵巧的转动一次再回到初始位置,当你刷卡时,舵机会转动到设定的点,停1.2s后再回归原位。之后可以依照你们的门调整舵机角度(代码中mainservo.write部分均为舵机角度的调节)、录入你们寝室的信息、改一下防爆破的措施。

至于卡的ID,你可以用MFRC522库文件提供的示例读取卡ID,也可以选择在手机上(如NFC Tools PRO)读取卡ID,每两个一位,前面加上0x(16进制)来修改配置

将门禁系统投入实际

每个寝室门不一样,我将我们寝室的门解决方案发一下,剩下的要靠大家聪明的大脑喽~

成品演示

已知问题:

在遇见剧烈震动或者有人触碰杜邦线时,会出现无法刷卡需要重启开发板的问题,将杜邦线直接焊在主板上或可解决该问题。可见该方案仍为实验方案,不能直接用在生产环境。在使用时仍要有人带钥匙?

鸣谢部分:

感谢创协社长提供的基本思路

感谢Arduino宿舍门禁,实现刷卡(NFC)开门这篇文章提供的一些思路