期末结课作业——Arduino计时RFID门禁分享

本篇代码参考文章《Arduino宿舍门禁,实现刷卡(NFC)开门》。在此基础上增加了一点功能完成的计时刷卡门禁,仅用于期末结课,并在此分享。(有不妥请联系我!我会立马删除!!!)


实验器材如下

  1. RFID-RC522 RFID射频IC卡感应模块
  2. SG90舵机
  3. LCD1602 I2C液晶显示屏
  4. Arduino主板
  5. 无源蜂鸣器
  6. LED灯*2
  7. 220Ω电阻*2
  8. 面包板
  9. 杜邦线若干

        在购买实验器材时,如果所在环境没有焊接条件,请记得购买焊接好的器材啊啊啊啊!!!没焊接的器材是无法正常使用的。

        液晶显示屏推荐使用LCD1602 I2C,因为部分显示屏显示的字母会乱码(怀疑是跟rfid使用的库有冲突?屏幕单独使用很正常,连在一起就不可以)


电路图


以下是代码部分

记得下好库哦 

#include <SPI.h>
#include <RFID.h>
#include <Servo.h>//舵机需要用的库
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);  //配置LCD地址及行列
RFID rfid(10,9);   //D10--读卡器MOSI引脚、D5--读卡器RST引脚,指定了 SDA 引脚为 10,RST 引脚为 9。
int temp=0;//判断卡号是否录入
int r=0;//判断具体用户
Servo myservo;//定义舵机变量名
// 定义蜂鸣器引脚
const int BUZZER_PIN = 4; 
//定义红绿led灯引脚
const int Green_pin=5;
const int Red_pin=6;
unsigned long startTime = 0;  // 用于存储计时器开始的时间
unsigned long elapsedTime = 0;  // 用于存储经过的时间
bool timing = false;  // 标志位,表示计时是否正在进行
// 定义马里奥主题曲的音符和节奏
const int melody[] = {659, 659, 0, 659, 0, 523, 659, 0, 784, 0, 0, 0, 392, 0, 0, 0};//音符
const int rhythm[] = {8, 8, 8, 8, 8, 8, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8};//每个音符的节奏长度,一个拍的几分之几
//刷卡有误会报警报,警报的声音
const int melody1[] = {1000, 0, 1000, 0, 1000, 0, 1000, 0};//音符
const int rhythm1[] = {500, 500, 500, 500, 500, 500, 500, 500};//每个音符的节奏长度,一个拍的几分之几,500代表每个音符持续半拍
void setup()
{
  Serial.begin(9600);//设置波特率
  SPI.begin();//初始化arduino上的串行外设接口,SPI接口常与外部设备进行数据交换
  rfid.init();//初始化RFID模块,准备好与卡片进行通信。进行的操作有:1.启动rfid模块;2.配置rfid模块参数;3.初始化与rfid模块通信所需的引脚和其他设置。
  pinMode(BUZZER_PIN,OUTPUT);//初始化蜂鸣器
  pinMode(Green_pin,OUTPUT);
  pinMode(Red_pin,OUTPUT);
  myservo.attach(7);//将舵机与7引脚连接初始化。舵机通过PWM脉冲宽度信号进行控制。
  digitalWrite(BUZZER_PIN,LOW);//蜂鸣器初始状态设置为LOW
  lcd.init(); //初始化LCD
  lcd.backlight(); //打开背光
}
void loop()
{
 myservo.write(0);//将舵机设置到0度的位置
  //找卡
  if (rfid.isCard()) {//判断硬件是否接触到卡
    Serial.println("找到卡");
    //读取卡序列号
    if (rfid.readCardSerial()) {//是否读到了卡片序列号,读到了存储在rfid.serNum数组中
      Serial.print("卡号");
      Serial.print(rfid.serNum[0],HEX);
      Serial.print(" ");
      Serial.print(rfid.serNum[1],HEX);
      Serial.print(" ");
      Serial.print(rfid.serNum[2],HEX);
      Serial.print(" ");
      Serial.print(rfid.serNum[3],HEX);
      Serial.print(" ");
      Serial.print(rfid.serNum[4],HEX);
      Serial.print(" ");
      Serial.println(" ");
      //将读到的卡片序号通过串口监视器打印出来
 if(rfid.serNum[0]==0x61&&rfid.serNum[1]==0x93&&rfid.serNum[2]==0x2f&&rfid.serNum[3]==0x90&&rfid.serNum[4]==0x4d)//我的学生卡
      {
        temp=1;//cc
        r=1;
      }
      //按照串口监视器读取数值填入
      else if(rfid.serNum[0]==0x61&&rfid.serNum[1]==0x93&&rfid.serNum[2]==0x3E&&rfid.serNum[3]==0x7F&&rfid.serNum[4]==0xB3)//学生1的学生卡
      {
        temp=1;//学生1
        r=2;
      }
      else if(rfid.serNum[0]==0x61&&rfid.serNum[1]==0x93&&rfid.serNum[2]==0x3E&&rfid.serNum[3]==0x60&&rfid.serNum[4]==0xAC)//学生2的学生卡
      {
        temp=1;//学生2
        r=3;
      }
      else if(rfid.serNum[0]==0x01&&rfid.serNum[1]==0x31&&rfid.serNum[2]==0xAC&&rfid.serNum[3]==0x80&&rfid.serNum[4]==0x1C)//学生3的手机
      {
        temp=1;//学生3
        r=2;
      }
      else if(rfid.serNum[0]==0x61&&rfid.serNum[1]==0x93&&rfid.serNum[2]==0x04&&rfid.serNum[3]==0x8A&&rfid.serNum[4]==0x7C)//学生4的学生卡
      {
        temp=1;//学生4
        r=4;
      }
      else if(rfid.serNum[0]==0x61&&rfid.serNum[1]==0x93&&rfid.serNum[2]==0x17&&rfid.serNum[3]==0x59&&rfid.serNum[4]==0xBC)//学生5的学生卡
      {
        temp=1;//学生5
        r=5;
      }
      else{
        temp=2;
      }
    }
    //选卡,可返回卡容量(锁定卡片,防止多数读取),去掉本行将连续读卡。选择模块中特定的卡片,选择卡片后,可以执行进一步的操作,如读取卡片上的数据、写入数据到卡片等。
    rfid.selectTag(rfid.serNum);
  }
  if(temp==1)//temp==1表示改卡片信息已经录入
  {
    timing = false;//每当有人刷卡就重新计时
    lcd.clear();
    lcd.setCursor(0,0);//设置 LCD 光标的位置.第一个参数表示要设置的光标所在行数(从 0 开始计数),第二个参数表示要设置的光标所在列数(同样从 0 开始计数)。不设置光标位置的话,重复刷卡会显示错乱。
    lcd.print("Welcome home!");//显示字符数据
    digitalWrite(Green_pin, HIGH); //绿色led灯亮起
    myservo.write(85);//舵机开始转动,转动85度
    switch(r){//判断当前刷卡的是哪位用户,并显示相应的名字
          case 1:Serial.println("欢迎cc回家!");lcd.setCursor(4,1);lcd.print("Dear cc.");break;
          case 2:Serial.println("欢迎sy回家!");lcd.setCursor(4,1);lcd.print("Dear sy.");break;
          case 3:Serial.println("欢迎yw回家!");lcd.setCursor(4,1);lcd.print("Dear yw.");break;
          case 4:Serial.println("欢迎jj回家!");lcd.setCursor(4,1);lcd.print("Dear jj.");break;
          case 5:Serial.println("欢迎dd回家!");lcd.setCursor(4,1);lcd.print("Dear dd.");break;
          default:Serial.println("欢迎回家!");break;
    }
//刷卡成功,绿色led灯亮起,并播放马里奥主题曲作为提示
    for (int i = 0; i < sizeof(melody) / sizeof(int); i++) {//遍历音符和节奏数组。在 C/C++ 中,sizeof 运算符可以返回给定类型或变量所占用的字节数。通过将数组的总字节数除以单个元素的字节数,可以得到数组中元素的个数。
      if (melody[i] == 0) {//如果当前音符为0,则停顿,只持续节奏时间
        // 休息时间
        delay(rhythm[i] * 20);//延迟一段时间,使当前停顿时间得以保持
      } else {
       // 发出声音并持续一段时间
        tone(BUZZER_PIN, melody[i]);//在蜂鸣器上播放当前音符声音,该函数指定引脚产生特定频率值的方波,以产生声音。tone()和noTone()是内置函数,不属于特定的库。
        delay(rhythm[i] * 20);//延迟当前音符节奏长度,说白了就是播放这个音符多久
        noTone(BUZZER_PIN);//关闭蜂鸣器
      }
      // 稍微延迟一下,使音符之间有一定的间隔
      delay(50);
  }
      delay(2000);//让舵机持续85度一段时间
      myservo.write(0);//舵机归位
      temp=0;//录入变量归0
      r=0;//用户判断变量归0
      digitalWrite(Green_pin, LOW);//led灯灭
      lcd.clear();//lcd显示屏清屏
  }
  else if(temp==2){//当前卡片未录入
    timing = false;//每当有人刷卡就重新计时
    lcd.clear();
    lcd.print("ERROR:");//显示字符数据
    lcd.print(rfid.serNum[2],HEX);//以16进制的方式打印卡号第3-5个。(因为校园卡前两位相同)
    lcd.print(" ");
    lcd.print(rfid.serNum[3],HEX);
    lcd.print(" ");
    lcd.print(rfid.serNum[4],HEX);
    digitalWrite(Red_pin, HIGH); 
     Serial.println("卡号错误,请换卡!");
    temp=0;
    //刷卡失败,红色led灯伴随音乐闪烁作为提示 
    for (int i = 0; i < sizeof(melody1) / sizeof(int); i++) {
    if (melody1[i] == 0) {
      // 休息时间,蜂鸣器不响,灯也灭
      digitalWrite(Red_pin, LOW);
      delay(rhythm1[i]);
    } else {
      // 发出声音并持续一段时间,同时红色led灯亮起
      digitalWrite(Red_pin, HIGH); 
      tone(BUZZER_PIN, melody1[i]); 
      delay(rhythm1[i]);
      noTone(BUZZER_PIN);
    }
    // 稍微延迟一下,使音符之间有一定的间隔
    delay(50);
  }
 //lcd.clear();//lcd清屏,否则会一直显示
  }else{//lcd显示计时功能
    if (!timing) {
      startTime = millis();  // 开始计时
      timing = true;
    }
  elapsedTime = millis() - startTime;  // 计算经过的时间
  int seconds = elapsedTime / 1000;
  int minutes = seconds / 60;
  int hours = minutes / 60;
  int ac_seco=seconds-minutes*60-hours*60*60;//实际打印的秒
  int ac_mins=minutes-hours*60*60;//实际打印的分
  // 显示计时结果
  lcd.setCursor(0,1);
  lcd.print("Last: ");
  lcd.print(hours);
  lcd.print(":");
  if (ac_mins< 10) {
    lcd.print("0");
  }
  lcd.print(ac_mins);
  lcd.print(":");
  if (ac_seco < 10) {
    lcd.print("0");
  }
  lcd.print(ac_seco);
  //Serial.println(seconds-minutes*60-hours*60*60);
  }
  rfid.halt();//RFID模块休眠。当RFID模块不需要再读取卡片时,可以使用rfid.halt()函数将其置于休眠状态,以节省功耗并延长模块的使用寿命。同时,这个函数也可以释放RFID模块与卡片之间的通信,使得其他设备可以使用SPI总线。
}

使用这个代码需要下载两个库, rfid的可以直接看参考链接,里面写的很详细。

LCD的库请搜索LCDIIC有关教程。


功能展示

 RFID门禁计时系统。

每重新启动主板或有人刷卡时,开始重新计时(如图1所示)。

图 1

     RFID读卡器模块识别校园卡,通过RFID库自带的函数检测当前RFID模块是否接触了校园卡并读取当前卡片的序列号,用rfid.serNum[],即RFID模块中用于存储卡片序列号的数组来存储该卡片的前五位序列号。

如果代码判断部分中包含该卡的序列号,则舵机转动,带动门把手实现开门。同时绿色led灯亮起,蜂鸣器播放马里奥主题曲,lcd屏幕显示“Welcome  home!”(如图3所示)持续一段时间。串口监视器显示该卡片序列号,以及学生姓名(如图2所示)。Lcd显示一段时间后重新回到计时界面,开始新一轮计时(如图1所示)。

                             

图 2

图 3

如果代码判断部分中不包含该卡的序列号,则舵机不转动。红色led灯伴随蜂鸣器播放的警报进行闪烁,lcd屏幕显示“ERROR:卡号后三位”因为学生卡的前两位相同,所以只显示后三位以作区分(如图5所示),串口监视器显示该卡片序列号,并提示卡号错误(如图4所示)。蜂鸣器关闭后,LCD在显示未录入的卡号的同时,实时显示距上次刷卡所经过时间的计时,直到重启主板或下一次刷卡才做更新(如图6所示)。       

图 4

图 5   

图 6


增加了显示名字和计时的功能,剩下的请参考文章顶部链接!

想起来再回来补充 ;-) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值