自制网络化 RFID 读卡器:Arduino + ENC28J60 以太网 + MFRC522
组件与物料
| Mifare MFRC522 RFID 模块 | ×1 |
| Arduino UNO(或任意 Arduino) | ×1 |
| ENC28J60 以太网模块 | ×1 |
| 跳线(公对公/公对母) | 若干 |
| 面包板 | ×1 |
| 电脑(联网) | ×1 |
必需工具
- 剪刀或剥线钳
应用与在线服务
- PyCharm(运行 Python 服务端)
- Arduino IDE
项目简介
想给家里或办公室加 RFID 门禁/考勤系统?商业方案动辄 $200-$2000,太贵!我和朋友决定用不到 $100 做一个功能更强的系统——联网 Arduino RFID 读卡器,加 $20 还能控制门锁。原本为高中学生考勤设计,希望学校采纳。
开始前的准备(必做)
需安装两个库:
放入 Program Files(x86)/Arduino/Libraries/ 并重启 Arduino IDE。
硬件连接
- Arduino Nano 插面包板
- 查阅开发板引脚图找到 SPI 引脚(下文可修改)
- Arduino 10 (SS) → 以太网模块 CS
- Arduino 12 (MISO) → RFID MISO 和 以太网 SO
- Arduino 11 (MOSI) → RFID MOSI 和 以太网 SI
- Arduino 13 (SCK) → RFID SCK 和 以太网 SCK
- Arduino 9 → RFID RST
- Arduino 8 → RFID SSN(因以太网占用 10)
- Arduino 5/4/3 → RGB LED 的绿/蓝/红(配 330Ω 电阻)
- AC-DC 电源模块(3.3V/5V >700mA)接面包板正负极
- Arduino GND 与电源 GND 共地
- RFID 和以太网的 VCC/GND 接电源输出(注意:两模块仅支持 3.3V!严禁 5V,必要时分压)
- LED VCC 接 Arduino 3.3V 或电源 3.3V
- 以太网模块接网线,确保与电脑同一局域网
- USB 连接 Arduino 与电脑
代码配置
代码注释详细,主要修改网络参数:
- MAC 地址可保持默认(多设备需修改)
- 192.168.x 网段可保持 IP
- DNS 可保持 8.8.8.8 或改 8.8.4.4
- 网关:运行
ipconfig查看(默认 192.168.1.1,代码中为 192.168.1.5) - 电脑 IP:
ipconfig获取 - 找到 “SEND TO SERVER” 部分,填入电脑 IP(或公网 IP 端口映射)
- 确保 Python 服务端运行(示例代码用于演示,可用任何 TCP/Telnet 服务端)
运行步骤
- 接通 AC-DC 电源
- Arduino 连电脑 USB
- 确保同一网络
- 烧录修改后的代码
- 启动 Python/C++ 等 TCP 服务端
- 复位 Arduino
- 蓝灯亮起后刷卡,服务端收到 ID 即成功
LED 状态含义:
- 紫/渐变红:启动中
- 红:错误(卡角度问题或服务端超时)
- 绿:通过(服务端回复允许)
- 蓝:等待/读卡中
若 Arduino 卡顿 >30 秒亮红灯,可能原因:供电不足、服务端未运行、网络不通、IP 填错。排查建议:关闭防火墙、放行端口 23、路由器端口映射、有线直连路由器、更换大功率电源。
注意:代码不含门锁控制,如需门禁功能需自行添加。
代码
Arduino 代码
/* 引脚定义见代码注释 */
#include <UIPEthernet.h>
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9
#define SS_PIN 8
byte sector = 0, blockAddr = 0, trailerBlock = 1;
int red = 3, blue = 4, green = 5;
EthernetClient client;
MFRC522 mfrc522(SS_PIN, RST_PIN);
MFRC522::MIFARE_Key key;
signed long timeout;
void setup() {
pinMode(red, OUTPUT); pinMode(blue, OUTPUT); pinMode(green, OUTPUT);
Reset(); Serial.begin(9600);
SPI.begin();
uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};
IPAddress mip(192,168,1,160), mdns(8,8,8,8), mgate(192,168,1,5), msubnet(255,255,255,0);
Ethernet.begin(mac, mip, mdns, mgate, msubnet);
Serial.println("Succesful connection");
for(int t=255;t>0;t--){ analogWrite(red,t); delay(10); }
mfrc522.PCD_Init();
for(byte i=0;i<6;i++) key.keyByte[i]=0xFF;
Serial.println(F("Scan a Card")); dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE);
timeout=0; delay(2000); Reset();
}
void loop() {
if(!mfrc522.PICC_IsNewCardPresent()){ digitalWrite(blue,LOW); return; }
if(!mfrc522.PICC_ReadCardSerial()) return;
digitalWrite(blue,HIGH);
byte piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
if(piccType!=MFRC522::PICC_TYPE_MIFARE_MINI && piccType!=MFRC522::PICC_TYPE_MIFARE_1K && piccType!=MFRC522::PICC_TYPE_MIFARE_4K){ Error(); return; }
byte status, buffer[18], size=sizeof(buffer);
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if(status!=MFRC522::STATUS_OK){ Error(); return; }
status = mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if(status!=MFRC522::STATUS_OK){ Error(); }
mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1();
if(client.connect(IPAddress(192,168,1,100),23)){
timeout=millis()+1000; Serial.println("Client connected");
String ID = dump_byte_array(buffer,size); client.println(ID); Serial.println("sent:"+ID); delay(10);
while(client.available()==0){ if(timeout-millis()<0) goto close; }
int sz; while((sz=client.available())>0){
uint8_t* msg=(uint8_t*)malloc(sz); sz=client.read(msg,sz); Serial.write(msg,sz);
if(sz==sizeof("g")-1) Pass(); else Error(); free(msg);
}
close: client.stop();
}else{ Serial.println("Couldn't connect to Server"); Error(); }
Reset();
}
String dump_byte_array(byte *buffer, byte bufferSize){
String out=""; for(byte i=0;i
Python 服务端示例
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
print self.data
# SQL 逻辑:若匹配发送 "g" 并记录,否则发送 "bb"
self.request.sendall("g")
if __name__ == "__main__":
HOST, PORT = "", 23
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
最新代码见 GitHub。
原理图
接线照片见附件。
制造工艺
- 贺卡产业:历史、生产与未来趋势
- 信用卡:历史、设计、制造与未来趋势
- Arduino RFID 门锁系统 – RC522 模块实现安全门禁
- 打造安全的 Arduino RFID 门锁——分步指南
- 基于 Arduino 与 Python 的可靠 RFID 考勤系统
- DIY 蓝牙控制 Arduino 间谍小车
- FlickMote:基于手势的智能家居红外遥控器
- DIY Arduino TV-B-Gone:万能关机遥控器
- 自制大尺寸LED主时钟带闹钟功能 — 12米外清晰可见
- Find Me:基于 Arduino 与蓝牙的智能寻物器制作指南
- Arduino 项目优化供电方案:从按键开关到电池监测与数据记录
- 基于 Arduino 的 Amiga 软盘读取器:低成本开源数据恢复方案