【STM32单片机】多功能电子密码锁设计


一、功能简介

本项目使用STM32F103C8T6单片机控制器,使用按键、IIC OLED模块、DS18B20温度传感器、SG90舵机、红外遥控、矩阵按键、EEPROM等。
主要功能:
系统运行后,OLED显示RTC日期时间和温度;

键盘解锁:可使用矩阵键盘S1-S10键输入数字
0-9,初始密码为012345,当密码输入有误可按下S11键撤回,输入完成后可按下S12键解锁,若密码正确则开锁,舵机启动。若密码错误,OLED显示错误信息,当错误次数超过3次则锁死一段时间后重新输入。当按下S13键可修改密码,进入密码修改界面首先需校验旧密码,当输入旧密码正确,才可进入新密码设置。可按下S16键返回主界面。密码支持掉电不丢失。

红外遥控解锁:使用红外遥控器,按下第一个键(该键对应HEX为A2),则一键解锁。


二、软件设计

/*
作者:嗨小易(QQ:3443792007)

*/



//系统参数初始化
void sys_parm_init(void)
{
	u8 i=0;
	sys_ctrl.mode=0;
	sys_ctrl.err_cnt=0;
	sys_ctrl.psw_flag=0;
	sys_ctrl.psw_resive=0;
	sys_ctrl.psw_bit=0;
	//初始密码0-5
	if(AT24CXX_ReadOneByte(255)!=0x28)
	{
		AT24CXX_WriteOneByte(255,0x28);
		//写入初始密码到EEPROM
		for(i=0;i<PSW_BITNUM;i++)
		{
			sys_ctrl.save_psw[i]=i;
			AT24CXX_WriteOneByte(i,sys_ctrl.save_psw[i]);
		}	
	}
	else
	{
		//读取EEPROM内密码数据
		for(i=0;i<PSW_BITNUM;i++)
		{
			sys_ctrl.save_psw[i]=AT24CXX_ReadOneByte(i);	
		}	
	}	
}

//系统时钟温度显示模块
void sys_rtc_temp_show(void)
{
	u8 buf[5];
	static u8 i=0;

	OLED_Clear();
	OLED_ShowString(0,0,  "2023-08-22 Week5",16);
	OLED_ShowString(0,20, "   12:16:56",16);
	OLED_ShowString(0,40,"  Temp:    C",16);
	
	while(sys_ctrl.mode==0)
	{
		//温度获取
		i++;
		if(i%1==0)
			sys_ctrl.temp=DS18B20_GetTemperture()*10;
		//日期显示
		buf[0]=calendar.w_year/1000+0x30;
		buf[1]=calendar.w_year%1000/100+0x30;
		buf[2]=calendar.w_year%1000%100/10+0x30;
		buf[3]=calendar.w_year%1000%100%10+0x30;
		buf[4]='\0';
		OLED_ShowString(0,0,buf,16);
		
		buf[0]=calendar.w_month/10+0x30;
		buf[1]=calendar.w_month%10+0x30;
		buf[2]='\0';
		OLED_ShowString(5*8,0,buf,16);
		buf[0]=calendar.w_date/10+0x30;
		buf[1]=calendar.w_date%10+0x30;
		buf[2]='\0';
		OLED_ShowString(8*8,0,buf,16);
		buf[0]=calendar.week%7+0x30;
		buf[1]='\0';
		OLED_ShowString(15*8,0,buf,16);
		
		//时间显示
		buf[0]=calendar.hour/10+0x30;
		buf[1]=calendar.hour%10+0x30;
		buf[2]='\0';
		OLED_ShowString(3*8,20,buf,16);//时
		buf[0]=calendar.min/10+0x30;
		buf[1]=calendar.min%10+0x30;
		buf[2]='\0';
		OLED_ShowString(6*8,20,buf,16);//分
		buf[0]=calendar.sec/10+0x30;
		buf[1]=calendar.sec%10+0x30;
		buf[2]='\0';
		OLED_ShowString(9*8,20,buf,16);//秒
		
		//温度显示
		buf[0]=sys_ctrl.temp/100+0x30;
		buf[1]=sys_ctrl.temp%100/10+0x30;
		buf[2]='.';
		buf[3]=sys_ctrl.temp%100%10+0x30;
		buf[4]='\0';
		OLED_ShowString(7*8,40,buf,16);
		
		//检测是否按下键,进入密码输入界面
		if(KEY_Matrix_Scan()!=0)
		{
			sys_ctrl.mode=1;
			break;
		}
		OLED_Refresh_Gram();//刷新显存
	}
}

//密码输入界面显示
void psw_input_show(void)
{
	OLED_Clear();
	OLED_ShowString(0,0,"Password:",16);
}
//修改密码时输入校验密码界面显示
void adjust_input_show(void)
{
	OLED_Clear();
	OLED_ShowString(0,0,"Calib Psw:",16);
}
//设置新密码界面显示
void set_new_psw_show(void)
{
	OLED_Clear();
	OLED_ShowString(0,0,"New Psw:",16);	
}
//一键解锁界面显示
void one_click_unlock_show(void)
{
	OLED_Clear();
	OLED_ShowString(0,0,"One click unlock",16);
	OLED_ShowString(0,20,"OK...",16);	
}

//修改密码时,密码校验
void sys_psw_resive(void)
{
	u8 key=0;
	//在密码设置有效
	if(sys_ctrl.psw_resive)
	{
		//初始化参数值
		sys_ctrl.psw_bit=0;
		sys_ctrl.err_cnt=0;
		sys_ctrl.psw_flag=0;
		memset(sys_ctrl.psw,0,PSW_BITNUM);//清除输入数据
	
		adjust_input_show();//修改密码时输入校验密码界面显示
	
		while(sys_ctrl.psw_resive)
		{
			//键盘扫描
			key=KEY_Matrix_Scan();
			if(key>0)//按键输入
			{
				BEEP_Alarm(100,100);//提示音
				if(key<=10)//数字键0-9
				{
					if(sys_ctrl.psw_bit<PSW_BITNUM)//最多输入密码位数
					{
						sys_ctrl.psw[sys_ctrl.psw_bit]=key-1;//记录输入密码
						sys_ctrl.psw_bit++;//输入位数累加
						//密码可见
						if(PASSWORD_SHOW_HIDE)
							//显示输入密码
							OLED_ShowNum((9+sys_ctrl.psw_bit)*8,0,sys_ctrl.psw[sys_ctrl.psw_bit-1],1,16);
						//密码不可见
						else
							OLED_ShowString((9+sys_ctrl.psw_bit)*8,0,"*",16);
					}	
				}
				else if(key==11)//撤回键
				{
					sys_ctrl.psw[sys_ctrl.psw_bit-1]=10;//将所需撤回的数据设置为无效数
					OLED_ShowString((9+sys_ctrl.psw_bit)*8,0," ",16);//将撤销位置显示空位
					sys_ctrl.psw_bit--;
					if(sys_ctrl.psw_bit<0)sys_ctrl.psw_bit=0;
				}
				else if(key==12)//确定键
				{
					sys_ctrl.psw_flag=0;
					sys_ctrl.psw_bit=0;
					//输入密码与存储密码比较
					if(memcmp(sys_ctrl.psw,sys_ctrl.save_psw,PSW_BITNUM)==0)
						sys_ctrl.psw_flag=1;//密码正确
					memset(sys_ctrl.psw,0,PSW_BITNUM);//清除输入数据	
		
					//密码正确,开锁
					if(sys_ctrl.psw_flag==1)
					{
						sys_ctrl.err_cnt=0;
						OLED_ShowString(0,20,"Password OK!   ",16);
						OLED_Refresh_Gram();//刷新显存
						delay_ms(1000);
						break;//进入新密码设置程序	
					}
					//如果密码错误
					else
					{
						sys_ctrl.err_cnt++;//错误次数累计
						OLED_ShowString(0,20,"Password Error!",16);
						OLED_Refresh_Gram();//刷新显存
						//密码输入错误次数超限
						if(sys_ctrl.err_cnt>=ERROR_PASSWORD_CNT)
						{
							sys_ctrl.err_cnt=0;
							OLED_ShowString(0,0,"Too many errors!",16);
							OLED_ShowString(0,20,"Please wait...",16);
							OLED_Refresh_Gram();//刷新显存
							delay_ms(1000);	
							delay_ms(1000);
							delay_ms(1000);
						}
						else delay_ms(1000);
						adjust_input_show();//修改密码时输入校验密码界面显示
					}
				}
				else if(key==16)//退出键
				{
					sys_ctrl.psw_resive=0;
					sys_ctrl.mode=0;//回到时钟温度显示模式	
					break;	
				}
			}
			
			OLED_Refresh_Gram();//刷新显存
		}		
	}	
}


//应用控制系统
void app_sys_ctrl_demo(void)
{
	u8 i=10;
	
	LED_Init();
	USART1_Init(115200);
	AT24CXX_Init();
	OLED_Init();
	KEY_Matrix_Init();
	BEEP_Init();
	DS18B20_Init();
	RTC_Init();
	Hwjs_Init();
	//获取稳定数据
	while(i--)
	{
		sys_ctrl.temp=DS18B20_GetTemperture()*10;
		delay_ms(100);
	}
	TIM4_Init(200,36000-1);  //定时100ms
	TIM3_CH2_PWM_Init(20000-1,71); //周期20ms
	steer_control(0);
	sys_parm_init();//系统参数初始化
	
	while(1)
	{
		sys_rtc_temp_show();//系统时钟温度显示模块
		sys_psw_unlock_show();//系统解锁显示模块
		sys_psw_resive();//修改密码时,密码校验
		sys_new_psw_set();//新密码设置
	}
}





三、实验现象

B站演示视频:https://space.bilibili.com/444388619

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


联系作者

专注于51单片机、STM32、国产32、DSP、Proteus、ardunio、ESP32、物联网软件开发,PCB设计,视频分享,技术交流。

### 设计基于STM32的矩阵键盘密码锁 #### 硬件组件需求 对于构建此项目,所需的主要硬件组件包括: - STM32微控制器开发板(推荐型号:STM32F103C8T6) - 4x4矩阵键盘用于接收用户输入 - 继电器模块用来控制实际物理锁的动作 - LCD或OLED屏幕以便向用户提供反馈信息 - 连接上述部件所需的面包板和杜邦线[^2] #### 软件环境搭建 确保已安装合适的集成开发环境(IDE),比如Keil MDK或是更现代的选择——STM32CubeIDE。这些工具可以帮助完成代码编辑、编译以及最终将固件上传至目标设备。 #### 密码锁工作原理概述 当用户按下按键时,系统会读取对应的键值并与预设密码比较。如果匹配成功,则发送信号给继电器打开门;反之则提示错误并给予再次尝试的机会。连续多次失败后触发报警机制[^4]。 #### 关键技术点解析 - **I/O端口配置**:初始化GPIO引脚以适应外部接口的需求。 - **中断服务例程(ISR)**:捕获来自键盘的事件而不影响其他任务执行效率。 - **状态机编程模型**:管理不同阶段间的转换逻辑,如等待输入、验证过程等。 #### 实现方案中的重要函数说明 以下是部分核心算法片段展示如何处理键盘扫描及密码校验流程: ```c #include "stm32f1xx_hal.h" #define PASSWORD_LENGTH 6 // 定义密码长度为六位数 char password[PASSWORD_LENGTH]; // 存储正确密码数组 char inputBuffer[PASSWORD_LENGTH]; // 用户输入缓冲区 // 初始化设置... void SystemClock_Config(void); static void MX_GPIO_Init(void); int main(void){ HAL_Init(); SystemClock_Config(); // 设置系统时钟频率 MX_GPIO_Init(); // GPIO初始化 while (true){ CheckKeyInput(); // 不断检测是否有新按下的键 if(IsPasswordComplete()){ VerifyPassword(); // 当收到完整的密码串时调用验证方法 ClearInputBuffer(); // 清除当前缓存准备下一轮交互 } Delay_ms(10); // 循环延时减少CPU占用率 } } bool IsPasswordComplete(){ return strlen(inputBuffer)==PASSWORD_LENGTH; } ``` 这段代码展示了基本框架结构,在`main()`循环里持续监听按键活动并通过辅助函数来管理和评估收集到的数据流。每当获取足够的字符数量之后就会启动一次身份认证检查动作[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值