准备工作
- 硬件准备(基于ESP8266-12F的开发板、MFRC522读卡器模块)
- ProtoThreads多线程库(ProtoThreads库,ProtoThreads使用教程)
MFRC522的使用
在程序中对于卡片的识别仅仅限于Uid的读取,并没有使用卡片的其他扇区
下面是Arduino的MFRC522的示例程序,这里我之所以把代码贴出来的原因是因为接线的问题。
博主用的是WeMos D1 的开发板,本段下述描述基于WeMos D1,在程序端口号上和板子标注不一致(其实是芯片的GPIO号)
下面是部分端口对照表(全部的会在之后更新此博客)
程序端口号 | 0 | 2 | 4 | 5 | 6 | 15 |
板子端口号 | D8 | D9 | D4 | D3 | D2 | D10 |
* -----------------------------------------------------------------------------------------
* 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
*/
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 10 // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
}
void loop() {
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
// Dump debug info about the card; PICC_HaltA() is automatically called
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
}
关于MFRC522的接线:SPI相关(MOSI,MISO,SCK),是从芯片上引出标注的所以对号入座没问题,RST_PIN,SS_PIN,按照前述表格的对应方式选取合适的使用即可。
EEPROM的使用
门禁由于可以Web管理,即使用Web添加,删除,查询允许用户。自然需要在不改写程序的情况下,可以识别不同卡号。
便需要EEPROM的断电存储。
下面例子摘自门禁程序,每次重启都会自动从EEPROM中加载卡号。
#include <EEPROM.h>
char cardNum = 0;
char cards[6][4];
void ReadEEPROM()
{
int addr = 0;
cardNum = EEPROM.read(addr++);
for(int i=0;i<cardNum;i++)
{
for(int j=0;j<4;j++)
cards[i][j] = EEPROM.read(addr++);
}
}
void setup() {
EEPROM.begin(1024);
ReadEEPROM();
}
HttpServer的搭建
与其说搭建不如说模拟(因为ESP8266并不能实现Web服务器的很多功能)
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
const char* ssid = "***";
const char* password = "***";
ESP8266WebServer server(80);
void handleNotFound();
void handleInterFace();
void handleRoot();
void setup() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
delay(500);
server.on("/", handleRoot);
server.on("/InterFace",handleInterFace);
server.onNotFound(handleNotFound);
//here the list of headers to be recorded
const char * headerkeys[] = {"User-Agent","Cookie"} ;
size_t headerkeyssize = sizeof(headerkeys)/sizeof(char*);
//ask server to track these headers
server.collectHeaders(headerkeys, headerkeyssize );
server.begin();
}
void loop() {
// put your main code here, to run repeatedly:
server.handleClient();
}
void handleInterFace()
{
Serial.println("Enter Interface");
String content;
char count = 0;
content = "<?xml version='1.0' encoding='ISO-8859-1'?><cards>";
if(server.hasArg("cmd"))
{
if(server.arg("cmd")=="getUidPer")
{
Serial.println("getUidPer");
for(int i=0;i<cardNum;i++)
{
content += "<card>";
for(int j=0;j<4;j++)
{
content +="<";
content += (char)(j+65);
content +=">";
content +=(int)(cards[i][j]);
content +="</";
content += (char)(j+65);
content +=">";
}
content += "</card>";
}
}
if(server.arg("cmd")=="readUid")
{
Serial.println("readUid");
//延时5s等待读取卡片
while(!mfrc522.PICC_IsNewCardPresent()&&count < 5)
{
delay(500);
count++;
}
if ( ! mfrc522.PICC_ReadCardSerial())
{
content += "<card>";
for(int j = 0;j<4;j++)
{
content +="<";
content += (char)(j+65);
content +=">";
content +=(int)(-1);
content +="</";
content += (char)(j+65);
content +=">";
}
content += "</card>";
}
else
{
Serial.println(mfrc522.uid.uidByte[0]);
Serial.println(mfrc522.uid.uidByte[1]);
Serial.println(mfrc522.uid.uidByte[2]);
Serial.println(mfrc522.uid.uidByte[3]);
content += "<card>";
for(int j = 0;j<4;j++)
{
content +="<";
content += (char)(j+65);
content +=">";
content +=(int)(mfrc522.uid.uidByte[j]);
content +="</";
content += (char)(j+65);
content +=">";
}
content += "</card>";
}
}
{
if(server.arg("cmd")=="deleteUid")
{
Serial.println("deleteuID");
char key[4];
char i=0,j=0;
key[0] = server.arg("A").toInt();
key[1] = server.arg("B").toInt();
key[2] = server.arg("C").toInt();
key[3] = server.arg("D").toInt();
for(i=0;i<cardNum;i++)
{
for(j=0;j<4;j++)
{
if(cards[i][j]!=key[j])
break;
}
if(j==4)
break;
}
if(j==4)
{
EEPROM.write(0,cardNum-1);
for(int k=i;k<cardNum-1;k++)
{
EEPROM.write(k*4+1,EEPROM.read(4*k+5));
EEPROM.write(k*4+2,EEPROM.read(4*k+6));
EEPROM.write(k*4+3,EEPROM.read(4*k+7));
EEPROM.write(k*4+4,EEPROM.read(4*k+8));
}
EEPROM.commit();
ReadEEPROM();
content += "<card><A>1</A></card>";
}
else
content += "<card><A>2</A></card>";
}
}
{
if(server.arg("cmd")=="addUid")
{
Serial.println("addUid");
char key[4];
char i=0,j=0;
key[0] = server.arg("A").toInt();
key[1] = server.arg("B").toInt();
key[2] = server.arg("C").toInt();
key[3] = server.arg("D").toInt();
for(i=0;i<cardNum;i++)
{
for(j=0;j<4;j++)
{
if(cards[i][j]!=key[j])
break;
}
if(j==4)
break;
}
if(j==4)
{
content += "<card><A>2</A></card>";
}
else
{
EEPROM.write(0,cardNum+1);
for(int k=0;k<4;k++)
EEPROM.write(cardNum*4+k+1,key[k]);
EEPROM.commit();
ReadEEPROM();
content += "<card><A>1</A></card>";
}
}
}
content+="</cards>";
server.send(200, "text/html", content);
}
}
//root page can be accessed only if authentification is ok
void handleRoot(){
Serial.println("Enter handleRoot");
String content;
content = "<html><head><script src='https://devoutprayer.github.io/TheDoor/load.js'></script><script>ajaxGetHTML('https://devoutprayer.github.io/TheDoor/thedoor.html');</script></head></html>";
server.send(200, "text/html", content);
}
之后博主会把arduino程序和web一并传到https://github.com/DevoutPrayer/TheDoor