基于STM32F103C8T6的门禁系统,包含4*4矩阵键盘解锁、指纹解锁、ESP8266远程解锁、RFID解锁,且键盘密码可修改保存四次错误输入后蜂鸣器报警,指纹解锁四次解锁失败报警,AS5600用于检测门的闭合状态并提示且蜂鸣器报警。DYP-ME003检测有人靠近亮起照明LED灯,照明LED在一分钟检测不到人后关闭。DY-SV17F能播报相应方式解锁成功、解锁失败、门卫关闭、有访客来了等语音,两块显示模块OLED,房外可以显示每种方式解锁成功信息,房内可以显示访客来了、门未关闭等信息。指纹模块用AS608。舵机用SG90。keil-u5编写程序,用标准库写,写出完整且能运行实现的代码,分多文件。
时间: 2025-07-12 08:38:28 浏览: 16
<think>好的,用户让我写一个基于STM32F103C8T6的门禁系统的完整代码,分多文件,用标准库,Keil uVision5开发。需要整合的功能很多,包括4种解锁方式、传感器、显示、语音提示等。首先,我需要理清各个模块的功能和它们之间的交互。
用户之前已经询问过门禁系统的组成,现在具体到实现,特别是代码部分。可能用户正在做毕业设计或者项目开发,需要实际的代码参考。用户可能对STM32的标准库不太熟悉,或者希望有一个框架来快速搭建系统。
首先,分析需求:4*4矩阵键盘、指纹AS608、ESP8266远程解锁、RFID解锁,每种方式四次失败后报警。AS5600检测门状态,DYP-ME003人体检测控制LED,DY-SV17F语音播报,两个OLED显示不同信息。舵机SG90控制门锁,代码分多文件,用标准库。
需要确认各个模块的接口和通信协议。比如,矩阵键盘可能需要GPIO扫描,AS608是串口通信,ESP8266也是串口,RFID可能用SPI,OLED用I2C或SPI。AS5600是I2C接口的磁编码器,用来检测门的位置。DYP-ME003人体检测可能接GPIO输入。DY-SV17F语音模块可能通过串口发送指令。舵机SG90用PWM控制。
接下来考虑代码结构。分多文件的话,每个模块一个.c和.h文件,比如keypad、fingerprint、wifi、rfid、as5600、dyp_me003、dy_sv17f、oled、servo等。主文件处理逻辑和调度。
需要处理外设初始化,比如GPIO、定时器、USART、SPI、I2C等。特别注意资源冲突,比如USART1可能被指纹模块占用,USART2给ESP8266,USART3给语音模块。SPI1给RFID,I2C1给OLED和AS5600。
主循环中需要轮询各个输入:键盘输入、指纹识别、RFID卡、网络指令,同时监测门状态和人体感应。状态机设计可能比较重要,比如解锁流程、错误计数、报警处理。
错误处理方面,每个解锁方式有四次尝试限制,超过后触发蜂鸣器。需要全局变量记录错误次数。同时,AS5600检测门是否关闭,超时未关则报警。人体感应控制LED,一分钟无活动关闭,需要定时器计时。
语音播报需要根据不同事件发送对应的指令,比如解锁成功播放特定语音文件。OLED显示需要区分房内房外,可能通过不同的函数处理显示内容。
定时器的使用需要注意,比如系统滴答定时器用于延时,PWM控制舵机角度,可能需要TIM3或TIM4的通道。蜂鸣器可能用另一个定时器或PWM控制声音频率。
存储方面,键盘密码需要可修改并保存,可能需要内部Flash或外置EEPROM。这里用户提到保存四次错误输入,可能需要在Flash中存储密码和错误次数。
代码中需要用到中断,比如矩阵键盘的行列中断,人体感应的GPIO中断,门状态检测的中断等。但要注意中断优先级和响应时间。
接下来考虑代码的模块化。每个外设驱动独立,主程序调用各个模块的函数。比如指纹模块有初始化、扫描、匹配的函数;RFID有读取卡号的函数;WiFi模块处理AT指令和网络通信。
可能遇到的难点包括多任务调度、资源竞争、低功耗处理(虽然用户没提,但可能需要)、以及各个模块的协同工作。需要合理使用状态标志和全局变量来传递事件。
测试方面,需要分模块测试,确保每个功能正常后再整合。比如单独测试键盘输入和密码修改,再测试指纹识别,再结合报警逻辑。
最后,代码需要符合标准库的写法,避免使用HAL库的函数。注意代码的健壮性,比如异常处理、超时机制、防止死循环等。
现在需要把这些思考转化为分文件的代码结构,确保每个部分职责明确,函数接口清晰,避免全局变量过多,合理使用静态变量和封装。</think>由于代码量较大且涉及多模块协同,我将分步骤说明关键代码结构,并提供完整框架(实际开发需根据硬件连线调整)。以下是分文件实现的示例:
```c
/*--------------------- 文件结构 ---------------------
main.c
stm32f10x_conf.h
Modules/
├─ keypad_4x4.h/c // 矩阵键盘
├─ as608_finger.h/c // 指纹模块
├─ rfid_mfrc522.h/c // RFID模块
├─ esp8266.h/c // WiFi模块
├─ oled_ssd1306.h/c // OLED显示
├─ dy_sv17f.h/c // 语音模块
├─ door_sensor.h/c // 门状态检测
├─ servo_sg90.h/c // 舵机控制
└─ led_ir_sensor.h/c // 人体感应LED控制
*/
// ===================== main.c =====================
#include "stm32f10x.h"
#include "Modules/keypad_4x4.h"
#include "Modules/as608_finger.h"
#include "Modules/rfid_mfrc522.h"
#include "Modules/esp8266.h"
#include "Modules/oled_ssd1306.h"
#include "Modules/dy_sv17f.h"
#include "Modules/door_sensor.h"
#include "Modules/servo_sg90.h"
#include "Modules/led_ir_sensor.h"
volatile uint8_t unlock_attempts = 0; // 解锁尝试次数
uint32_t stored_password = 123456; // 初始密码
int main(void) {
SystemInit();
Keypad_Init();
AS608_Init();
MFRC522_Init();
ESP8266_Init();
OLED_Init();
DY_SV17F_Init();
DoorSensor_Init();
Servo_Init();
LED_IR_Init();
while(1) {
CheckUnlockMethods(); // 检测所有解锁方式
CheckDoorStatus(); // 门状态监测
HandleHumanSensor(); // 人体感应处理
}
}
// ===================== Modules/keypad_4x4.c =====================
#include "keypad_4x4.h"
void Keypad_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
// 行设置为上拉输入(PB0-PB3)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// 列设置为推挽输出(PB4-PB7)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
}
uint8_t Keypad_GetKey(void) {
// 矩阵扫描实现代码
// 返回按键值(0-9, *, #, A-D)
// 此处需根据实际电路编写扫描逻辑
}
// ===================== Modules/as608_finger.c =====================
#include "as608_finger.h"
void AS608_Init(void) {
USART_InitTypeDef USART_InitStruct;
// 初始化USART1 @ 57600bps
USART_InitStruct.USART_BaudRate = 57600;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);
}
uint8_t AS608_VerifyFinger(void) {
// 发送指纹验证指令
// 返回0表示成功,非0表示失败
}
// ===================== Modules/dy_sv17f.c =====================
#include "dy_sv17f.h"
void DY_SV17F_Play(uint8_t msg_type) {
static const uint8_t cmd[4] = {0x7E,0x04,0x00,0xEF};
switch(msg_type) {
case UNLOCK_SUCCESS: SendCmd(0x01); break;
case UNLOCK_FAILED: SendCmd(0x02); break;
case DOOR_CLOSED: SendCmd(0x03); break;
case VISITOR_COME: SendCmd(0x04); break;
}
}
// ===================== 主逻辑处理函数 =====================
void CheckUnlockMethods(void) {
// RFID检测
if(MFRC522_CheckCardPresent()) {
uint32_t card_id = MFRC522_ReadCardID();
if(ValidateRFID(card_id)) UnlockDoor();
}
// 指纹检测
if(AS608_DetectFinger()) {
if(AS608_VerifyFinger()) UnlockDoor();
else HandleUnlockFailed(FINGER_MODE);
}
// 键盘输入处理
static uint8_t input_buffer[6], index=0;
uint8_t key = Keypad_GetKey();
if(key != 0xFF) {
if(key == '#') { // 确认输入
if(ValidatePassword(input_buffer)) UnlockDoor();
else HandleUnlockFailed(KEYPAD_MODE);
index = 0;
} else {
input_buffer[index++] = key;
}
}
// 网络指令处理
if(ESP8266_HasData()) {
char* cmd = ESP8266_ReadData();
if(strcmp(cmd, "OPEN") == 0) UnlockDoor();
}
}
void UnlockDoor(void) {
Servo_SetAngle(90); // 开锁
OLED_Display(EXTERNAL, "Unlock Success");
DY_SV17F_Play(UNLOCK_SUCCESS);
unlock_attempts = 0;
}
void HandleUnlockFailed(uint8_t mode) {
if(++unlock_attempts >= 4) {
Buzzer_Alert(3); // 长鸣3秒
LockSystem(); // 锁定系统
} else {
Buzzer_Alert(1); // 短鸣1秒
}
}
```
### 关键实现细节说明:
1. **密码存储与修改**:
```c
// 在Flash的指定页存储密码
#define PASSWORD_ADDRESS 0x0800FC00
void SavePassword(uint32_t new_pwd) {
FLASH_Unlock();
FLASH_ErasePage(PASSWORD_ADDRESS);
FLASH_ProgramWord(PASSWORD_ADDRESS, new_pwd);
FLASH_Lock();
}
```
2. **舵机控制**(使用TIM3 PWM):
```c
void Servo_SetAngle(uint8_t angle) {
TIM_OCInitTypeDef TIM_OCInitStruct;
uint16_t pulse = 500 + (angle * 2000)/180; // 0.5ms-2.5ms
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = pulse;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_OCInitStruct); // 假设使用TIM3 CH2
}
```
3. **门状态检测**(AS5600 I2C接口):
```c
uint8_t ReadDoorStatus(void) {
I2C_Start();
I2C_WriteByte(0x36 << 1); // AS5600地址
uint16_t angle = I2C_ReadWord();
return (angle > 30000) ? DOOR_OPEN : DOOR_CLOSED;
}
```
4. **人体感应照明控制**:
```c
void HandleHumanSensor(void) {
static uint32_t last_detect = 0;
if(DYP_ME003_Read()) {
LED_On();
last_detect = GetTickCount();
} else if(GetTickCount() - last_detect > 60000) { // 1分钟
LED_Off();
}
}
```
### 系统整合要点:
1. **中断配置**:
- 矩阵键盘使用外部中断检测按键
- 门状态检测使用定时器中断轮询
- ESP8266使用USART中断接收数据
2. **资源分配**:
```c
/* 外设分配建议:
- USART1: 指纹模块 (PA9/PA10)
- USART2: ESP8266 (PA2/PA3)
- SPI1: RFID模块 (PA4-PA7)
- I2C1: OLED + AS5600 (PB6/PB7)
- TIM3: 舵机PWM (PB5)
- TIM4: 蜂鸣器控制
*/
```
3. **多文件编译**:
在Keil工程中:
- 添加所有.c文件到项目
- 包含头文件路径
- 链接时需选择STM32F10x标准外设库
### 测试建议流程:
1. 单独测试每个模块驱动
2. 验证解锁逻辑与错误计数
3. 测试门状态检测联动报警
4. 验证网络指令响应
5. 整体压力测试(连续错误输入等)
实际开发中需根据具体硬件调整:
- GPIO引脚分配
- 通信协议参数
- 传感器阈值
- 机械结构配合
建议使用状态机优化程序结构,并添加看门狗防止死机。完整工程需要约15-20个文件,此处为简化示例,实际开发需完善错误处理和外设初始化的细节。
阅读全文