ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于单片机的门禁系统设计:从硬件选型到状态机实现

基于单片机的门禁系统设计:从硬件选型到状态机实现

简介:这份资源是一篇完整的学位论文文档,主题为基于单片机的门禁系统设计,面向计算机、电子信息及自动化相关专业的本科生与研究生,可用于毕业设计选题参考、课程设计借鉴或论文写作模板学习。文档围绕写字楼安全管理场景,提出一套基于无线通信模式的联网式门禁方案,重点解决传统有线门禁布线复杂、成本高、难以扩展升级等问题。压缩包内共1个doc文件,整体约1.33MB,即论文正文全文,包含摘要、绪论、方案设计、硬件设计、软件设计、总结、参考文献与致谢等完整章节。硬件部分涉及电源、门禁控制器、RFM12射频模块无线传输平台、读卡器、RS232转换电路与电子锁等模块;软件部分涵盖主控设备、无线传输模块与管理软件设计,并采用C语言与Visual Basic实现人机界面。目前已有36人学习,适合需要参考完整论文结构、系统方案论证与软硬件设计思路的读者。

1. 从一份“学位论文—基于单片机的门禁系统设计论文.doc”说起:这套方案到底能不能落地

很多做嵌入式课程设计的人,第一次看到“基于单片机的门禁系统设计”这个题目,第一反应是去搜一份现成的 .doc 文档,把目录、原理图、流程图、代码一股脑抄下来,改改封面就交差。但真正做过一线项目的人都知道,门禁系统最核心的不是论文格式,而是“识别—判断—执行—反馈”这条闭环能不能稳定跑起来。它解决的是:如何用一颗几十块钱的单片机,配合读卡模块、电控锁、显示与报警电路,做出一套能识别合法用户、拒绝非法闯入、并在异常时给出提示的小型控制系统。适合谁?适合正在做课程设计、毕业设计、或者想入门嵌入式系统集成的开发者。这一章不聊论文怎么写,只聊这套系统从硬件选型到软件状态机,怎么一步步做成能演示、能复现、能经得起答辩追问的实物。

2. 门禁系统的硬件选型与最小系统搭建:别让电源和地线先翻车

2.1 单片机主控怎么选:51、STM32 还是 ESP32

常见做法是:如果只是完成“刷卡—开锁—显示”的基础功能,STC89C52 或 STM32F103C8T6 都够用。51 单片机便宜、资料多、IO 口操作直接,适合新手快速点灯和驱动继电器;STM32 资源多、中断和定时器更稳,适合需要同时处理读卡、显示、按键和锁控的多任务场景。我一般会建议:如果论文里要写“系统稳定性”和“低功耗”,选 STM32F103;如果只求快速出实物,51 单片机加最小系统板是最短路径。注意,选型一旦定了,后面所有代码和电路都要围绕它的供电电压、IO 驱动能力和时钟频率来设计,不要中途换芯片。

2.2 读卡模块与电控锁的接口设计

读卡模块常见有 RFID-RC522、MFRC522 这类 13.56MHz 方案,通过 SPI 接口和单片机通信。电控锁一般是 12V 供电,单片机 IO 口不能直接驱动,必须经过继电器或 MOS 管模块。接线时最容易忽略的是共地:读卡模块、单片机、继电器模块、电控锁电源,四者的地必须连在一起,否则会出现“刷卡有反应但锁不动”或者“锁一动单片机就复位”的玄学现象。下面是一个典型的接口分配表,实际布线时按这个逻辑走:

模块信号线接单片机引脚备注
RC522SDA/SSPA4片选
RC522SCKPA5SPI 时钟
RC522MOSIPA7主出从入
RC522MISOPA6主入从出
RC522RSTPA3复位
继电器INPB0高电平触发
蜂鸣器I/OPB1低电平触发
OLEDSCL/SDAPB6/PB7I2C 接口

2.3 最小系统搭建的四个必查点

第一,电源。单片机用 3.3V 或 5V,读卡模块通常 3.3V,继电器和锁用 12V,必须分开供电或加稳压模块。第二,复位电路。51 单片机高电平复位,STM32 低电平复位,接错会一直复位。第三,晶振。51 常用 11.0592MHz 或 12MHz,STM32 用 8MHz 外部晶振加内部 PLL。第四,下载接口。51 用串口下载,STM32 用 SWD 或串口,提前把下载排针引出来,不然后面调试要拆线。把这几步做完,再上电测电压,确认 3.3V 和 5V 都正常,再插模块。

// 以 STM32 HAL 库为例,初始化 RC522 的 SPI 和 GPIO void RC522_Init(void) { // 使能 SPI1 和 GPIOA 时钟 __HAL_RCC_SPI1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // 配置 PA5/PA7 为复用推挽,PA6 为浮空输入 GPIO_InitTypeDef gpio = {0}; gpio.Pin = GPIO_PIN_5 | GPIO_PIN_7; gpio.Mode = GPIO_MODE_AF_PP; gpio.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &gpio); gpio.Pin = GPIO_PIN_6; gpio.Mode = GPIO_MODE_INPUT; gpio.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &gpio); // 配置 PA4 片选和 PA3 复位为普通输出 gpio.Pin = GPIO_PIN_4 | GPIO_PIN_3; gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &gpio); // 拉高片选和复位,进入待机状态 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET); }

这段代码的逻辑是:先开时钟,再配 SPI 引脚复用功能,然后配片选和复位引脚为普通输出。参数说明:SPI 速率建议先设 1MHz 以下,等读卡稳定后再往上调;片选和复位初始电平要拉高,否则 RC522 上电就进不了正常模式。如果读不到卡号,先量 PA5、PA7 有没有波形,再查片选有没有拉低。

3. 读卡识别与权限判断的代码实现:状态机比 if-else 更靠谱

3.1 读卡流程:寻卡、防冲突、选卡、读序列号

RC522 读一张卡要经过四步:寻卡(Request)、防冲突(Anticollision)、选卡(Select)、读序列号(Read UID)。很多新手只做寻卡就以为读到了卡号,结果多张卡同时靠近时数据全乱。正确做法是每一步都判断返回值,只有四步都成功,才把 UID 存下来做权限比对。下面是一个简化的读卡函数:

uint8_t Read_Card_ID(uint8_t *uid) { uint8_t status; uint8_t buffer[5]; // 寻卡,返回 ATQA status = PCD_Request(PICC_REQIDL, buffer); if (status != MI_OK) return status; // 防冲突,获取 UID status = PCD_Anticoll(buffer); if (status != MI_OK) return status; // 选卡,为后续读写做准备 status = PCD_Select(buffer); if (status != MI_OK) return status; // 拷贝 4 字节 UID memcpy(uid, buffer, 4); return MI_OK; }

逻辑说明:PCD_Request 的参数 PICC_REQIDL 表示寻感应区内所有卡;PCD_Anticoll 返回的 buffer 前 4 字节是 UID,第 5 字节是校验;PCD_Select 用 UID 选中一张卡。参数上,如果现场有多张卡,防冲突阶段会返回第一张卡的 UID,后续要循环读才能读全。失败时看返回值:MI_NOTAGERR 表示没卡,MI_ERR 表示通信出错,先查 SPI 接线和供电。

3.2 权限表怎么存:数组、EEPROM 还是 Flash

常见做法是:如果只有几张固定卡,直接定义一个二维数组存 UID 和权限等级;如果需要发卡和删卡,用 AT24C02 这类 EEPROM 存,掉电不丢;如果卡数量大,用 STM32 内部 Flash 模拟 EEPROM。我一般会建议课程设计用数组加 EEPROM 的组合:数组做快速比对,EEPROM 做持久化。下面是一个权限表结构:

typedef struct { uint8_t uid[4]; // 卡号 uint8_t level; // 权限等级:0 非法,1 普通用户,2 管理员 } CardInfo; CardInfo cardTable[10]; // 最多存 10 张卡 uint8_t cardCount = 0; // 当前卡数量

参数说明:level 为 0 时直接拒绝,为 1 时开锁并记录,为 2 时进入管理模式。比对时用 memcmp 比较 4 字节 UID,不要用字符串比较,否则遇到 0x00 会截断。

3.3 状态机设计:待机、读卡、验证、开锁、报警

用状态机写主循环,比一堆 if-else 清晰得多。状态定义如下:

状态行为转移条件
IDLE显示待机界面,蜂鸣器不响检测到卡 → READ
READ读 UID,超时 500ms读到 UID → VERIFY;超时 → IDLE
VERIFY查权限表合法 → UNLOCK;非法 → ALARM
UNLOCK继电器吸合 3 秒,显示欢迎3 秒到 → IDLE
ALARM蜂鸣器响 2 秒,显示拒绝2 秒到 → IDLE
void Main_Loop(void) { static uint8_t state = IDLE; uint8_t uid[4]; switch (state) { case IDLE: if (Card_Present()) state = READ; break; case READ: if (Read_Card_ID(uid) == MI_OK) { state = VERIFY; } else if (Timeout(500)) { state = IDLE; } break; case VERIFY: if (Check_Permission(uid) > 0) { state = UNLOCK; } else { state = ALARM; } break; case UNLOCK: Relay_On(); if (Timeout(3000)) { Relay_Off(); state = IDLE; } break; case ALARM: Buzzer_On(); if (Timeout(2000)) { Buzzer_Off(); state = IDLE; } break; } }

逻辑说明:每个状态只做一件事,超时用毫秒计数。参数上,读卡超时设 500ms 是为了避免卡没放稳就报错;开锁 3 秒是常见门禁的默认时长,可以按需改成 1 到 5 秒;报警 2 秒足够引起注意又不扰民。如果状态卡死,先查 Timeout 函数有没有被正确调用,再查继电器和蜂鸣器有没有把电源拉低导致单片机复位。

4. 显示、报警与数据记录:让系统有“反馈”和“后悔药”

4.1 OLED 显示:待机、刷卡、拒绝三种界面

OLED 用 I2C 接口,显示内容分三行:第一行状态,第二行卡号,第三行提示。待机显示“请刷卡”,读到卡显示 UID 后四位,拒绝显示“非法卡”。常见坑是 I2C 地址写错,0x78 和 0x7A 要试一下。下面是一个显示函数:

void OLED_Show_Status(uint8_t *uid, uint8_t status) { OLED_Clear(); if (status == 0) { OLED_ShowString(0, 0, "Please Swipe"); } else if (status == 1) { OLED_ShowString(0, 0, "Welcome"); OLED_ShowHexNum(0, 2, uid[0], 2); OLED_ShowHexNum(20, 2, uid[1], 2); } else { OLED_ShowString(0, 0, "Denied"); } }

参数说明:OLED_ShowHexNum 的第三个参数是数值,第四个是显示位数。如果显示乱码,先查 I2C 速率是不是太高,降到 100kHz 试试。

4.2 报警电路:蜂鸣器驱动与静音策略

蜂鸣器分有源和无源,有源给电就响,无源要 PWM。课程设计常用有源蜂鸣器加三极管驱动,单片机 IO 口输出高电平导通。注意,蜂鸣器电流可能达到 30mA,直接接 IO 口会拉低电压导致单片机复位,必须加 S8050 或类似三极管。静音策略:管理员刷卡后进入管理模式,可以临时关闭报警,但要有超时自动恢复,避免忘记打开。

4.3 数据记录:把刷卡记录写进 EEPROM

每次刷卡,把 UID、时间戳、结果写进 EEPROM。时间戳可以用单片机内部 RTC 或者简单的开机计时。记录格式:4 字节 UID + 1 字节结果 + 2 字节计数。写之前先读出来判断是不是空,再写。注意 EEPROM 擦写次数有限,不要每次刷卡都写同一地址,用环形缓冲区。

void Log_Event(uint8_t *uid, uint8_t result) { static uint16_t addr = 0x00; uint8_t buf[7]; memcpy(buf, uid, 4); buf[4] = result; buf[5] = addr >> 8; buf[6] = addr & 0xFF; AT24C02_Write(addr, buf, 7); addr += 7; if (addr > 0x7F) addr = 0x00; // 环形覆盖 }

逻辑说明:addr 从 0 开始,每次加 7,超过 0x7F 就回到 0。参数上,AT24C02 容量 256 字节,最多存 36 条记录。如果写不进去,查 I2C 上拉电阻是不是 4.7k,地址是不是 0xA0。

5. 避坑与常见问题:那些让门禁系统“时好时坏”的细节

5.1 刷卡没反应,但电压正常

现象:读卡模块灯亮,单片机也在跑,但刷卡就是没数据。原因:SPI 片选引脚接错,或者 RC522 的 RST 一直拉低。解决:用示波器看片选有没有拉低,RST 上电后要拉高至少 10ms 再操作。没有示波器就用万用表测电压,片选待机高电平,刷卡瞬间拉低。

5.2 开锁瞬间单片机复位

现象:继电器一吸合,OLED 黑屏,单片机重启。原因:电控锁启动电流大,电源被拉低。解决:电控锁单独供电,继电器模块加续流二极管,单片机电源加 100uF 和 0.1uF 电容。如果还不行,继电器和单片机之间加光耦隔离。

5.3 多张卡同时靠近读不出卡号

现象:一张卡正常,两张卡一起放就读不到。原因:防冲突没做完整,只寻卡没选卡。解决:按 3.1 的四步走,每一步判断返回值。如果还不行,降低 SPI 速率到 500kHz 以下。

5.4 断电后权限表丢失

现象:重新上电,之前发的卡都不认了。原因:权限表只存在 RAM 里。解决:发卡时同步写 EEPROM,上电时从 EEPROM 读回 cardTable。注意 EEPROM 读写要加延时,AT24C02 写周期 5ms。

5.5 论文里的流程图和实物对不上

现象:答辩时老师问“你这个防冲突怎么实现的”,答不上来。原因:论文抄的流程图和实际代码不一致。解决:画流程图之前先把代码状态机写清楚,按状态转移画,不要凭想象画。论文里的每一个模块,都要能在实物上指出对应的芯片和引脚。

6. 从能跑到好用:门禁系统的进阶技巧与验证方法

6.1 用串口打印调试信息,把黑匣子打开

很多新手调试门禁系统,全靠看灯和猜。我一般会先在主循环里加串口打印,把状态、UID、权限结果都打出来。串口波特率设 115200,用 USB 转 TTL 接电脑,开串口助手看。这样刷卡没反应时,能立刻知道是寻卡失败还是权限比对失败。打印格式建议:[STATE] IDLE -> READ、[UID] 12 34 56 78、[RESULT] DENIED。注意,串口打印会占用时间,读卡超时时间要相应放宽,否则打印一半就超时了。

6.2 用逻辑分析仪抓 SPI 时序,确认 RC522 通信正常

如果串口打印显示寻卡失败,下一步就是抓 SPI 波形。逻辑分析仪接 SCK、MOSI、MISO、CS 四根线,采样率设 1MHz 以上。正常时序:CS 拉低,SCK 八个脉冲,MOSI 发命令,MISO 回数据。如果 SCK 没波形,查 SPI 初始化;如果 MISO 一直是高,查 MISO 接线或 RC522 供电。这个步骤能把“玄学”问题变成确定问题。

6.3 权限表加超时锁定,防止暴力试卡

进阶做法:连续 3 次非法卡,锁定 30 秒,期间不响应任何卡。实现方式:在 VERIFY 状态加一个失败计数,超过阈值进 LOCK 状态,用定时器计时。这样能防止有人拿一堆卡反复试。参数上,3 次和 30 秒是常见值,可以按需调整。注意锁定期间 OLED 要显示“已锁定”,否则用户以为坏了。

6.4 验证方法:用一张卡跑通全流程,再用多张卡测边界

验证时不要只测一张卡。准备三张卡:一张管理员卡、一张普通卡、一张未授权卡。按顺序测:管理员卡开锁并进管理模式,普通卡开锁但不进管理,未授权卡报警。然后测边界:卡放在感应区边缘、快速划过、两张卡叠放、断电重启后权限是否还在。最后测异常:拔掉读卡模块看是否报警,短接继电器看是否复位。把这些测完,系统才算能跑。

6.5 一个具体技巧:用状态机的超时计数替代 delay

很多新手在开锁时用delay(3000),结果这 3 秒内单片机什么都不干,刷卡没反应。正确做法是用定时器中断每 1ms 减计数,主循环里判断计数到 0 再关锁。这样开锁期间还能响应其他事件。代码片段:

volatile uint32_t tick = 0; void SysTick_Handler(void) { if (tick > 0) tick--; } void Relay_On_With_Timeout(uint32_t ms) { Relay_On(); tick = ms; while (tick > 0) { // 这里可以处理其他任务,比如读卡 } Relay_Off(); }

参数说明:tick 是全局变量,SysTick 每 1ms 中断一次。Relay_On_With_Timeout 传入 3000 就是 3 秒。注意 while 里不要放阻塞操作,否则超时不准。

我自己的习惯是:每次做完门禁系统,先不急着写论文,而是把实物放在桌上连续刷 100 次卡,看有没有一次失败。如果有,就查电源和接线;如果没有,再写文档。因为答辩时老师最可能问的不是原理,而是“你这个稳定吗”。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进