目录
前言:程序包下载
下载方式一:CSDN下载:https://download.csdn.net/download/qq_38351824/12128803
下载方式二:微信公众号:① 关注Tech云 ② 回复 数字密码锁 文章最后有下载链接
一、简要的过程
--->输入开机密码(输入三次错误后,需要输入管理员密码)
--->输入正确后进入主程序
--->通过独立按键进入修改密码的模式
--->输入管理员密码(输入三次错误后,冻结60s才能接着输入)
--->输入正确后进入开始修改密码
--->填写修改的密码
--->检测密码是否修正成功
--->断电重启后,再次输入密码
--->密码修改成功
二、涉及的知识点
1、C语言
结构体、数组、指针、条件语句、循环语句
2、STM32F429
IO读写、SPI、IIC、USART
三、main.c函数
/**
******************************************************************************
* @file main.c
* @author Sumjess
* @version V1.0
* @date 2019-05-xx
* @brief MDK5.27
******************************************************************************
* @attention
*
* 实验平台 :STM32 F429
* CSDN Blog :https://blog.csdn.net/qq_38351824
* 微信公众号 :Tech云
*
******************************************************************************
*/
#include "sum_common.h"
#include "bsp_4X4key.h"
#include "OLED_Show.h"
#include "bsp_HIM.h"
#include "bsp_i2c_ee.h"
#include "OLED.h"
#define pass_num 6
#define EEP_Firstpage 0x00
void input_passw(void);
void input_change(void);
struct{
int standard_pass[pass_num] ; //用户密码
int manage_pass[pass_num]; //管理员密码
int input_pass[pass_num]; //用户键入密码
}password={{0,1,2,3,4,5},{1,2,3,4,5,6},{0}};
int Key_val=0;
struct{
int count; //输入密码位数
int show; //用*显示密码位数
int pairing; //输入密码和正确密码的匹配数量
int pairing2;//输入密码和正确密码的匹配数量
} input_test = { 0, 0 , 0 , 0}; //密码位数把控及显示、密码比对结构体
struct{
int verification; //密码验证完毕
int succeed; //密码正确
int Admin; //管理员密码
int ERROR_count; //错误次数
} Flag = { 0, 1 , 0, 0}; //标志位结构体
struct{
int verification; //密码验证完毕
int succeed; //密码正确
int change; //密码修改准备开始
int ERROR_count; //错误次数
int test; //测试是否密码修改成功
} Flag_change = { 0, 1 , 0, 0, 0}; //修改密码标志位结构体
struct{
int one; //密码验证完毕
int two; //密码正确
int three; //管理员密码
int four; //错误次数
} Flag_Del = { 0, 0 , 0, 0}; //标志位结构体
int main(void)
{
SysTick_Init(); //时钟初始化
LED_GPIO_Config(); //板载LED初始化
LED_PURPLE; //紫灯亮---开始初始化,请不要进行操作
I2C_EE_Init();
Debug_USART_Config(); //串口初始化USART1
Key_GPIO_Config();
OLED_Init();
Key4X4_GPIO_Config(); //矩阵键盘4X4初始化
LED_YELLOW; //黄灯亮---初始化结束,初始化成功,可以开始操作
input_passw(); //输入开机密码
while(1)
{
input_change(); //修改开机密码
}
}
///////////////////////////////////////////////////////修改开机密码//////////////////////////////////////////////////////
void input_change(void)
{
if(Key_Scan(GPIOA,GPIO_Pin_0)) //修改密码的按键是否按下
{
while(Flag_change.succeed) //密码是否修改成功
{
SHOW_Password_change(); //显示修改密码
Key_val=KEY_Scan(); //键值获取
if(Key_val!=NO_press) //确保有按键按下
{
if(Key_val<=9) //确保是0-9的数字
{
if(input_test.count<pass_num) //确保输入数字不超过pass_num(6)位
{
*(password.input_pass+input_test.count) = Key_val; //移位存储数据,指针指向数组的首地址(password.input_pass[0])然后通过自加变量input_test.count进行移位。
++input_test.count; //input_test.count自加
input_test.show=input_test.count; //用*显示密码位数
for(;input_test.show>0;input_test.show--) //用*显示密码位数
OLED_ShowChar(32+input_test.show*8,5,'*'); //用*显示密码位数
}
}
//////////////////////////////////////////////////////
if(Key_val==10) //确保是A,相当于确认键,开始比对密码
{
for(int b=0;b<pass_num;b++) //遍历比对
{
if(*(password.input_pass+b) == *(password.manage_pass+b)) //是否比对成功
input_test.pairing++; //如果成功,匹配数量加一
}
Flag_change.verification = 1; //比对完毕,开始测试密码是否符合要求
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(Flag_change.verification) //开始测试密码是否符合要求
{
Flag_change.verification=0; //清空标志位
if(input_test.pairing==pass_num) //如果六位密码都对
{
LED_GREEN; //绿灯通过
Flag_change.change=1; //密码成功开始修改密码标志位
SHOW_Password_OK(); //显示密码通过
Delay_ms(500); //延时500ms
OLED_Clear(); //清屏
}
else
{
LED_RED; //红灯警报
input_test.count=0; //清空输入密码位数
input_test.pairing=0; //清空配对数量
for(int c=0;c<pass_num;c++) //遍历输入数据数组清零
{
*(password.input_pass+c)=0; //清空用户输入的错误密码
SHOW_Password_error(); //显示输入密码错误
Delay_ms(500); //延时500ms
}
OLED_Clear(); //清屏
}
}
if(Flag_change.change) //密码修改完毕,开始检测
{
Flag_change.change=0; //清空标志位
input_test.count=0; //清空输入密码位数
LED_WHITE; //白灯亮
while(1)
{
SHOW_Password_new(); //显示请输入新密码
Key_val=KEY_Scan(); //键值获取
if(Key_val!=NO_press) //确保有按键按下
if(Key_val<=9) //确保是0-9的数字
{
if(input_test.count<pass_num) //确保输入数字不超过pass_num(6)位
{
*(password.standard_pass+input_test.count) = Key_val; //移位存储数据,指针指向数组的首地址(password.standard_pass[0])然后通过自加变量input_test.count进行移位。
++input_test.count; //input_test.count自加
input_test.show=input_test.count; //显示密码
OLED_ShowNum(32+input_test.show*8,6,Key_val,1,16); //显示密码
}
}
//////////////////////////////////////////////////////
if(Key_val==10) //确保是A,相当于确认键,开始比对密码
{
//将I2c_Buf_Write中顺序递增的数据写入EERPOM中
I2C_EE_BufferWrite( password.standard_pass, EEP_Firstpage, 6);
OLED_Clear(); //清屏
Flag_change.test=1; //打开测试程序的标志位
SHOW_pass_succ(); //显示密码修改成功
Delay_ms(500); //延时500ms
OLED_Clear(); //清屏
Flag_change.succeed=0;//清空密码修改成功标志位
break;
}
}
}
}
if(Flag_change.test) //密码修改测试
{
input_test.count=0; //清空输入位数
Flag.ERROR_count=0; //清空输错次数
for(int b=0;b<pass_num;b++) //遍历清空数组
*(password.input_pass+b) = 0;
while(1)
{
SHOW_Password_user(); //请输入用户密码
Key_val=KEY_Scan(); //键值获取
if(Key_val!=NO_press) //确保有按键按下
{
if(Key_val<=9) //确保是0-9的数字
{
if(input_test.count<pass_num) //确保输入数字不超过pass_num(6)位
{
*(password.input_pass+input_test.count) = Key_val; //移位存储数据,指针指向数组的首地址(password.input_pass[0])然后通过自加变量input_test.count进行移位。
++input_test.count; //input_test.count自加
input_test.show=input_test.count; //用*显示密码位数
for(;input_test.show>0;input_test.show--) //用*显示密码位数
OLED_ShowChar(32+input_test.show*8,5,'*'); //用*显示密码位数
}
}
//////////////////////////////////////////////////////
if(Key_val==10) //确保是A,相当于确认键,开始比对密码
{
//将EEPROM读出数据顺序保持到I2c_Buf_Read中
I2C_EE_BufferRead(password.standard_pass, EEP_Firstpage, 6); ;
for(int b=0;b<pass_num;b++) //遍历比对
{
if(*(password.input_pass+b) == *(password.standard_pass+b)) //是否比对成功
input_test.pairing++; //如果成功,匹配数量加一
}
Flag.verification = 1; //比对完毕,开始测试密码是否符合要求
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(Flag.verification) //开始测试密码是否符合要求
{
Flag.verification=0;//清空标志位
if(input_test.pairing==pass_num) //如果六位密码都对
{
Flag.succeed=0; //打开密码成功标志位
SHOW_Password_OK(); //显示密码通过
Delay_ms(500); //延时500ms
LED_GREEN; //绿灯通过
}
else
{
LED_RED; //红灯警报
++Flag.ERROR_count; //错误次数累加
input_test.count=0; //清空输入密码位数
input_test.pairing=0; //清空配对数量
for(int c=0;c<pass_num;c++) //遍历
{
*(password.input_pass+c)=0; //清空用户输入的错误密码
SHOW_Password_error(); //显示输入密码错误
Delay_ms(500); //延时500ms
}
OLED_Clear(); //清屏
if(Flag.ERROR_count>=3) //检测密码输错次数
{
Flag.ERROR_count=0; //清空密码输错次数
SHOW_clock_one(); //显示锁住一分钟
Delay_ms(500); //延时500ms
OLED_Clear(); //清屏
for(int time=0;time<60;time++) //倒计时一分钟
{
SHOW_clock_one(); //显示锁住一分钟
Delay_ms(1000);
OLED_ShowNum(32,6,60-time,2,16);//实时显示倒计时
}
}
}
}
}
}
}
}
///////////////////////////////////////////////////////输入开机密码//////////////////////////////////////////////////////
void input_passw(void)
{
while(Flag.succeed) //密码是否正确
{
SHOW_Password_prompt();//显示请输入密码
Key_val=KEY_Scan(); //键值获取
if(Flag.Admin) //是否进入管理员模式
{
if(Key_val!=NO_press)//确保有按键按下
{
//////////////////////////////////////////////////////
if(Key_val<=9) //确保是0-9的数字
{
if(input_test.count<pass_num) //确保输入数字不超过pass_num(6)位
{
*(password.input_pass+input_test.count) = Key_val; //移位存储数据,指针指向数组的首地址(password.input_pass[0])然后通过自加变量input_test.count进行移位。
++input_test.count; //input_test.count自加
input_test.show=input_test.count; //用*显示密码位数
for(;input_test.show>0;input_test.show--) //用*显示密码位数
OLED_ShowChar(32+input_test.show*8,5,'*'); //用*显示密码位数
}
}
//////////////////////////////////////////////////////
if(Key_val==10) //确保是A,相当于确认键,开始比对密码
{
//将EEPROM读出数据顺序保持到I2c_Buf_Read中
I2C_EE_BufferRead(password.standard_pass, EEP_Firstpage, 6);
for(int b=0;b<pass_num;b++) //遍历比对
{
if(*(password.input_pass+b) == *(password.manage_pass+b)) //是否比对成功
input_test.pairing++; //如果成功,匹配数量加一
}
Flag.verification = 1; //比对完毕,开始测试密码是否符合要求
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(Flag.verification) //开始测试密码是否符合要求
{
Flag.verification=0; //清空标志位
if(input_test.pairing==pass_num) //如果六位密码都对
{
LED_GREEN; //绿灯通过
Flag.succeed=0; //打开密码成功标志位
Flag.Admin=0; //清空管理员模式标志位
SHOW_Password_OK(); //显示密码通过
Delay_ms(500); //延时500ms
Flag_Del.one=1;
}
else
{
LED_RED; //红灯警报
input_test.count=0; //清空输入密码位数
input_test.pairing=0; //清空配对数量
for(int c=0;c<pass_num;c++) //遍历
{
*(password.input_pass+c)=0; //清空用户输入的错误密码
SHOW_Password_error(); //显示输入密码错误
Delay_ms(500); //延时500ms
}
OLED_Clear(); //清屏
}
}
}
else //是否进入用户模式
{
if(Key_val!=NO_press)//确保有按键按下
{
//////////////////////////////////////////////////////
if(Key_val<=9) //确保是0-9的数字
{
if(input_test.count<pass_num) //确保输入数字不超过pass_num(6)位
{
*(password.input_pass+input_test.count) = Key_val; //移位存储数据,指针指向数组的首地址(password.input_pass[0])然后通过自加变量input_test.count进行移位。
++input_test.count; //input_test.count自加
input_test.show=input_test.count; //用*显示密码位数
for(;input_test.show>0;input_test.show--) //用*显示密码位数
OLED_ShowChar(32+input_test.show*8,5,'*'); //用*显示密码位数
}
}
//////////////////////////////////////////////////////
if(Key_val==10) //确保是A,相当于确认键,开始比对密码
{
//将EEPROM读出数据顺序保持到I2c_Buf_Read中
I2C_EE_BufferRead(password.standard_pass, EEP_Firstpage, 6);
for(int b=0;b<pass_num;b++) //遍历比对
{
if(*(password.input_pass+b) == *(password.standard_pass+b)) //是否比对成功
input_test.pairing++; //如果成功,匹配数量加一
if(*(password.input_pass+b) == *(password.manage_pass+b)) //是否比对成功
input_test.pairing2++; //如果成功,匹配数量加一
}
Flag.verification = 1; //比对完毕,开始测试密码是否符合要求
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(Flag.verification) //开始测试密码是否符合要求
{
Flag.verification=0; //清空标志位
if((input_test.pairing==pass_num)||(input_test.pairing2==pass_num))
{ //如果六位密码都对
Flag.succeed=0; //打开密码成功标志位
SHOW_Password_OK(); //显示密码通过
Delay_ms(500); //延时500ms
LED_GREEN; //绿灯通过
Flag_Del.one=1; //清空标志位和缓存数组数据
}
else
{
LED_RED; //红灯警报
++Flag.ERROR_count; //错误次数累加
input_test.count=0; //清空输入密码位数
input_test.pairing=0; //清空配对数量
for(int c=0;c<pass_num;c++) //遍历
{
*(password.input_pass+c)=0; //清空用户输入的错误密码
SHOW_Password_error(); //显示输入密码错误
Delay_ms(500); //延时500ms
}
OLED_Clear(); //清屏
if(Flag.ERROR_count>=3) //检测密码输错次数
{
Flag.ERROR_count=0; //清空密码输错次数
SHOW_Password_state(); //显示进入管理员模式
Delay_ms(500); //延时500ms
OLED_Clear(); //清屏
Flag.Admin=1; //进入管理员模式
}
}
}
}
}
if(Flag_Del.one==1) //清空标志位和缓存数组数据
{
OLED_Clear(); //清屏
Flag_Del.one=0; //只清除一次
input_test.count=0; //清空输入密码位数
for(int b=0;b<pass_num;b++) //遍历清零
*(password.input_pass+b) = 0; //遍历清零
}
}