目錄
前言:程序包下載
下載方式一: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; //遍歷清零
}
}
四、矩陣鍵盤的詳解
五、串口屏的詳解