在日常的生活和工作中,住宅与部门的安全防范、单位的文件档案、财务报表以及一些个人资料的保存多以加锁的办法来解决。若使用传统的机械式钥匙开锁,人们常需携带多把钥匙, 使用极不方便, 且钥匙丢失后安全性即大打折扣。在安全技术防范领域,具有防盗报警功能的电子密码锁逐渐代替了传统的机械式密码锁,电子密码锁具有安全性高、成本低、功耗低、易操作等优点。本文主要介绍运用51单片机设计数字密码锁的方法。本设计采用自上而下的数字系统设计方法,将数字密码锁系统分解为若干子系统,并且进一步细划为若干模块,然后用C语言来设计这些模块,通过KEIL软件编译,并且进行实机调试。调试结果表明:该数字密码锁能够效验4位十进制数密码,且有显示实时时间,修改时间,显示输入密码,设置密码,修改密码,输入错误回删,重置密码,密码输入超时报警,输入次数过多报警等功能。该密码锁体积小,功耗低,操作简单,不怕掉电,维护和升级都十分方便,应用日益广泛。
利用FD51F_DB开发板设计数字密码锁。FD51F_DB开发板采用的是新一代增强型8051单片机IAP15F2K61S2芯片。该芯片具有STC15F2K60S2单片机的所有性能:不需要外部晶振和复位电路、可在线编程、大容量2K字节的SRAM、两个独立串口、8通道高速A/D转换器、1个时钟/机器周期8051等。同时IAP15具有自己的特色:可支持Keil中设置断点,在线单步调试等。
项目的主要内容为利用单片机设计实现一个多位电子密码锁,该密码锁具有开锁和修改密码、输错密码超过三次会蜂鸣器报警等功能。除此之外它还具有简单电子表功能,可显示年、月、日、星期、时、分、秒。
此次课程设计使用keil5软件进行程序的编写与编译,编译无误后将程序烧录到开发板1上进行调试,进行数字密码锁各项功能的检验并观察结果。
项目完成的目标是设计实现一个多位电子密码锁,同时具有确定键和取消键,在未确定之前可以取消,重新输入;连续输入三次错误密码,会产生报警电路动作,启动蜂鸣器,并返回初始界面,无法继续进行密码输入;具有密码重置、修改功能,密码输入等待操作时间限制功能,超过限定的时间也将出发报警功能,此时蜂鸣器鸣叫;除此之外还具有简单电子表功能,可显示年、月、日、星期、时、分、秒。
程序流程框图如下图所示:
主函数程序说明:
Step0_welcome:显示欢迎(待机画面),屏幕上方显示当前时间(年-月-日-时-分-秒 星期x)。显示过后跳转步骤1。
Step1_ask_changePassword:询问是否修改密码(原始密码为6666),显示选择菜单,有按键按下时跳转步骤2。
Step2_judge_changePassword:判断是否修改密码,若按键4按下,则跳转步骤3直接开锁,若按键6按下,则跳转步骤6修改密码。
Step3_tips:提示输入密码,跳转步骤4。
Step4_inputPassword:输入密码以*显示,若按键delete按下,则可以删除输入的密码值。
Step5_PasswordComparison:密码比对,正确就开锁,错误次数小于3时返回步骤3,错误次数超过3时返回步骤0,蜂鸣器报警标志置位。
Step6_changePassword():修改密码,调用修改密码分函数,实现修改密码完整功能。
Step6_0:提示输入原密码,跳转至步骤6_1
Step6_1:输入密码以*显示,同Step4_inputPassword。
Step6_2():密码比对,Step5_PasswordComparison。
Step6_3():判断输入密码错误次数是否小于3
Step6_4():输入新密码。
void Step6_5:保存新密码。
按键模块:扫描行列按键及独立按键,得出按下的按键位置及其代表值。为主函数提供按键扫描等函数。
存储模块:首先存储原始密码。在修改密码的步骤中,存储输入的新密码。在密码比对步骤中,提供正确密码值与输入的值比对。
12864显示模块:提供主函数中清屏、显示字符、显示汉字等函数。
时钟模块:计时,为主函数提供时钟信息。
蜂鸣器模块:当密码输入错误次数超过3或者输入密码时长超过25s时蜂鸣器报警。
管脚说明:
P0 LCD12864_DATAPINS
P3^7 LCD12864_EN
P4^1 LCD12864_RW
P4^2 LCD12864_D/I
p2^1 DS1302模块 SCLK
p2^2 DS1302模块 I/O
p4^4 DS1302模块 CE
P1^6 蜂鸣器
P3 矩阵键盘
P5^5 存储模块 24C02 SCL
P5^4 存储模块 24C02 SDA
模块 |
个数 |
IAP15F2K61S2芯片 |
1 |
AT24C02 |
1 |
LCD12864 |
1 |
3x3按键模块 |
1 |
DS1302 |
1 |
蜂鸣器 |
1 |
单片机上电后lcd12864屏显示初始界面,第一排显示当时的年、月、日、星期,第二排显示当时的时、分、秒,第三排显示“welcome”。此时可以按下任意键继续,此时lcd12864屏显示菜单栏中开锁和修改密码两个选项。在这里我们可以“4”或“6”选择开锁(unlock)或者是修改密码(New password)。如果这里选择的开锁,按下确定键,此时会提示输入密码(初始密码默认为6666)。输入密码后按下确定键,如果密码正确则会显示“欢迎小仙女”,如果输入密码错误则会提示“Error 密码错误”。如果输入密码时间超过规定时间(25s)则会显示“Error 已超时”,且启动蜂鸣器;如果输入密码错误超过三次,则会提示启动蜂鸣器,并且返回到初始界面。如果需要修改密码,则在菜单页面选择“New password”。这里会提示输入原始密码。输入原始密码后按下确认键,如果密码正确会提示输入新密码。输入密码后按下确认键,会提示“OK”并返回到待机画面;如果输入密码错误超过三次,则会提示启动蜂鸣器,并且返回到初始界面。
main
/**************************************************************************************
* 电子密码锁 *
实现现象:下载程序输入正确密码,会开启数字密码锁
硬件连接:
矩阵键盘:
4 5 6
1 2 3
删除 0 确认
注意事项:无
***************************************************************************************/
#include "stc15f2k60s2.h" //此文件中定义了单片机的一些特殊功能寄存器
#include "key.h"
#include "lcd12864.h"
#include "hc595.h"
#include "eeprom.h"
#include "ds1302.h"
#define u16 unsigned int //对数据类型进行声明定义
#define u8 unsigned char
///*****************************************************************************/
u8 pw_num, Error_Num,Error_Num1;
u8 PassWord_Length = 4;
u8 PASSWORD[] = {6, 6, 6, 6};
u8 INPUT_PW_Tab[] = {6, 6, 6, 6};
u8 KeyValue, Step, Step6, Load_first_flag = 0, menu_flag = 0, fengming_flag = 0;
// 秒 分 时 日 月 星期 年
unsigned char code Init[7] = {0x00, 0x00, 0x12, 0x25, 0x05, 0x01, 0x22};
uchar *pBuf = 0;
//存放当前时间
unsigned char Now[7];
//保存RAM数据
unsigned char RAMData[7];
unsigned char T1_Cnt = 0;
//时间更新标记
bit UpdateTimeFlag;
///*****************************************************************************/
bit result_flag, Input_suc_flag, unlock_flag,chaoshi_flag;
bit List1 = 0;
///*****************************************************************************/
///*定义数字密码锁输入密码判断密码过程中的一些函数模块
///*******************************************************************************/
void Step0_welcome();//欢迎(待机画面)
void Step1_ask_changePassword();//询问是否修改密码(原始密码为6666)
void Step2_judge_changePassword();//判断是否修改密码
void Step3_tips();//提示输入密码
void Step4_inputPassword();//输入密码以*显示
void Step5_PasswordComparison();//密码比对,正确就开锁
void Step6_changePassword();//修改密码
void Step6_0();//提示输入原密码
void Step6_1();//输入密码以*显示
void Step6_2();//密码比对
void Step6_3();//判断输入的密码是否正确
void Step6_4();//输入新密码
void Step6_5();//保存新密码
///********************************************************************************/
///*定义一些上述函数中用到的函数模块
///*******************************************************************************/
void CipherComparison();
void input_password(bit m);
void Read_Password();
void delaya_ms(unsigned int ms)
{ unsigned int i;
while ((ms--) != 0)
{ for (i = 0; i < 600; i++);
}
}
void Timer_Init(void);
uchar HEX2ASCII(uchar dat);
// void LCD1602_Display_Str(uchar* str);
void LCD12864_Display_Date(uchar *pointer);
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{ LCD12864_Init() ;
AT24C02_Init();
Timer_Init();
IO2_Init();
DS1302_Init();
//HC595_Init();
delaya_ms(1000);
Step = 0;
Step6 = 0;
Error_Num = 0x00;
Error_Num1 =0x00;
unlock_flag = 0;
Read_Password();
while (1)
{ KeyValue = Key_Scan();
switch (Step)
{ case 0:
{ if (UpdateTimeFlag == 1) //定时1s更新时间
{ UpdateTimeFlag = 0;
DS1302_GetTime(Now); //读取DS1302时间
LCD12864_Display_Date(Now);
}
Step0_welcome();//欢迎(待机画面)
break;
}
case 1:
{ Step1_ask_changePassword();//询问是否修改密码(原始密码为6666)
break;
}
case 2:
{ Step2_judge_changePassword();//判断是否修改密码
break;
}
case 3:
{ Step3_tips();//提示输入密码
break;
}
case 4:
{ Step4_inputPassword();//输入密码以*显示
break;
}
case 5:
{ Step5_PasswordComparison();//密码比对,正确就开锁
break;
}
case 6:
{ Step6_changePassword();//修改密码
break;
}
}
if (chaoshi_flag == 1)
{ LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x98, "Error 已超时");
delaya_ms(5000);
LCD12864_WriteCMD(0x01);//清屏
chaoshi_flag=0;
fengming_flag = 1;
}
if (fengming_flag == 1)
{
u8 i=0;
ALARM_ON(); //蜂鸣器响
Delay_ms(50); //延时500ms
ALARM_OFF(); //蜂鸣器灭
Delay_ms(50); //延时500ms
i++;
fengming_flag=0;
}
}
}
void Step0_welcome()//欢迎(待机画面)
{ LCD12864_Display(0x8A, "welcome");
if (KeyValue != 0) Step = 1; // 有按键按下进入下一步
}
void Step1_ask_changePassword()//询问是否修改密码(原始密码为6666)
{ delaya_ms(1000);
LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x87, "<");
LCD12864_Display(0x80, "menu");
LCD12864_Display(0x90, "Unlock");
LCD12864_Display(0x98, "New Password");
Step = 2;
}
void Step2_judge_changePassword() //判断是否修改密码
{ if (KeyValue != 0) //检测是否有键按下
{if (KeyValue == 5 || KeyValue == 7) //4键或6键按下 4键是开锁,6键是修改密码
{ if (KeyValue == 5) //确认开锁
{ List1 = 0;
LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x90, "Unlock");
LCD12864_Display(0x97, "<");
LCD12864_Display(0x98, "New Password");
}
Else //确认修改密码·
{ List1 = 1;
LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x90, "Unlock");
LCD12864_Display(0x98, "New Password");
LCD12864_Display(0x9F, "<");
}
}
else
{ if (List1 == 0) Step = 3;
else
{
Step = 6;
}
}
}
}
void Step3_tips() //提示输入密码
{ LCD12864_WriteCMD(0x01);//清屏
LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x90, "Password: ");
Step = 4;
}
void input_password(bit m)
{ unsigned char t = 0;
TR1 = 1; //运行T1
if (KeyValue != 0) //ok键没有按下
{ if (KeyValue < 8 && pw_num < PassWord_Length) //1-7按下
{ INPUT_PW_Tab[pw_num] = KeyValue - 1; //保存至输入密码数组
pw_num = pw_num + 1; //密码长度+1
for (t = 0; t < pw_num; t++) //未到字符串末尾
if (m == 0)
{ LCD12864_WriteCMD(0x98 + t); //设定DDRAM地址
LCD12864_WriteDAT('*'); //密码隐藏
}
else
{ LCD12864_WriteCMD(0x98 + t);
LCD12864_WriteDAT(INPUT_PW_Tab[t] + 0x30); //显示密码
}
}
else if (KeyValue == 8) //删除键按下
{ LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x90, "Password: ");
if (pw_num != 0)
{ pw_num = pw_num - 1;
for (t = 0; t < pw_num; t++) //未到字符串末尾
if (m == 0)
{ LCD12864_WriteCMD(0x98 + t); //设定DDRAM地址
LCD12864_WriteDAT('*'); //密码隐藏
}
else
{ LCD12864_WriteCMD(0x98 + t);
LCD12864_WriteDAT(INPUT_PW_Tab[t] + 0x30); //显示密码
}
}
else
{
Step = 0;
}
}
else //ok键按下
{
if (pw_num == 0)
{
Step = 0;
TR1 = 0; //关闭T1
T1_Cnt = 0;
unlock_flag = 1;
LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x98, "Error 未输入密码");
delaya_ms(5000);
LCD12864_WriteCMD(0x01);//清屏
}
else
{
Input_suc_flag = 1;
}
}
}
TR1 = 0; //关闭T1
T1_Cnt = 0;
}
void Step4_inputPassword()//输入密码以*显示
{
input_password(0); //输入密码并以*显示
if (Input_suc_flag == 1)
{
Step = 5; //密码输入完成进入下一步
Input_suc_flag = 0;
}
Input_suc_flag = 0; //清除密码输入完成标志
}
void CipherComparison()
{
u8 i, j = 0;
LCD12864_WriteCMD(0x01);//清屏
);
if (pw_num == PassWord_Length) //密码长度比对
{
for (i = 0; i < PassWord_Length; i++) //密码比对
{
if (PASSWORD[i] != INPUT_PW_Tab[i])
{ result_flag = 0;
break; //密码错误
}
else
{result_flag = 1; //密码正确
pw_num = 0;
}
INPUT_PW_Tab[i] = 0XFF; //清除密码缓存数组
}
}
else
{ result_flag = 0;
}
}
void Step5_PasswordComparison()//密码比对
{
CipherComparison(); //密码比对
if (result_flag == 1) //密码正确
{
LCD12864_WriteCMD(0x01) ; //清屏
LCD12864_Display(0x91, "欢迎小仙女");
delaya_ms(5000);
LCD12864_WriteCMD(0x01);//清屏
result_flag = 0;
Step = 0;
}
else //密码错误
{ LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x98, "Error 密码错误");
delaya_ms(2000);
LCD12864_WriteCMD(0x01);//清屏
Error_Num1++;
if(Error_Num1<3)
{
pw_num = 0;
Step=3;
}
else
{
Error_Num1=0;
fengming_flag = 1;
pw_num = 0;
Step=0;
}
}
}
void Step6_0()
{
Error_Num1=0;
LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x90, "Input PassWord:"); //12864显示:输入密码
Step6 = 1;
pw_num = 0;
}
void Step6_1()
{
input_password(0); // 输入密码并以*显示
if (Input_suc_flag == 1) //密码输入完成
{
Step6 = 2; //
Input_suc_flag = 0; //清除密码输入完成标志
}
}
void Step6_2() //
{
CipherComparison(); //密码比对
Step6 = 3;
}
void Step6_3() //
{
if (result_flag == 0) // 密码错误
{
if (Error_Num < 2) //输出错误次数小于3
{ pw_num = 0;
Error_Num++;
LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x90, "请重新输入");
delaya_ms(2000);
Step6 = 0;
}
else //密码错误次数大于3
{
Error_Num = 0;
LCD12864_Display(0x90, "解锁失败");
delaya_ms(2000);
Step = 0;
fengming_flag = 1;
}
}
else //密码正确
{
LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x90, "New PassWord:");
pw_num = 0;
Error_Num=0;
Step6 = 4;
}
}
void Step6_4()
{
input_password(1); //输入密码并显示
if (Input_suc_flag == 1) //输入完成
{
Input_suc_flag = 0;
LCD12864_WriteCMD(0x01);//清屏
LCD12864_Display(0x90, "OK!");
pw_num = 0;
Step6 = 5;
}
}
void Step6_5()//保存新密码
{
unsigned char j;
delaya_ms(100);
for (j = 0; j < PassWord_Length; j++)
{
PASSWORD[j] = INPUT_PW_Tab[j]; //读取密码
AT24C02_WriteByte(j, INPUT_PW_Tab[j]); //保存密码至EEPROM
delaya_ms(100);
}
Step6 = 0;
Step = 0;
}
void Step6_changePassword()//修改密码
{
switch (Step6)
{
case 0:
{
Step6_0();
break;
}
case 1:
{
Step6_1();
break;
}
case 2:
{
Step6_2();
break;
}
case 3:
{
Step6_3();
break;
}
case 4:
{
Step6_4();
break;
}
case 5:
{
Step6_5();
break;
}
}
}
void Read_Password()
{ unsigned char j;
if (Load_first_flag == 0) //初次运行
{
Load_first_flag = 1;
for (j = 0; j < PassWord_Length; j++)
{
AT24C02_WriteByte(j, 6); //写默认密码6666至EEPROM
delaya_ms(100);
}
}
else
{
for (j = 0; j < PassWord_Length; j++) //读取密码
{
PASSWORD[j] = AT24C02_ReadByte(j);
}
}
}
/***********************************************
函数名称:LCD1602_Display_Date
功 能:lcd1602显示时钟
入口参数:pointer指针地址
返 回 值:无
备 注:1602LCD显示的为字符,必须将整数转换成
相应的字符,否则显示乱码。
************************************************/
void LCD12864_Display_Date(uchar *pBuf)
{
LCD12864_CheckBusy(); //检测忙信号
LCD12864_WriteCMD(0x80); //写入地址
LCD12864_Display_Str("20");
LCD12864_WriteDAT(HEX2ASCII((*(pBuf + 6) & 0xf0) >> 4)); //年高位
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII(*(pBuf + 6) & 0x0f)); //年低位
LCD12864_CheckBusy();
LCD12864_WriteDAT('-'); //“-”
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII((*(pBuf + 4) & 0xf0) >> 4)); //月高位
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII(*(pBuf + 4) & 0x0f)); //月低位
LCD12864_CheckBusy();
LCD12864_WriteDAT('-'); //“-”
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII((*(pBuf + 3) & 0xf0) >> 4)); //日高位
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII(*(pBuf + 3) & 0x0f)); //日低位
LCD12864_CheckBusy();
LCD12864_WriteCMD(0x85);
LCD12864_CheckBusy();
LCD12864_Display_Str("星期"); //“-”
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII(*(pBuf + 5) & 0x0f)); //星期
LCD12864_CheckBusy();
LCD12864_WriteCMD(0x90);
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII((*(pBuf + 2) & 0xf0) >> 4)); //时高位
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII(*(pBuf + 2) & 0x0f)); //时低位
LCD12864_CheckBusy();
LCD12864_WriteDAT(':'); //“:”
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII((*(pBuf + 1) & 0xf0) >> 4)); //分高位
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII(*(pBuf + 1) & 0x0f)); //分低位
LCD12864_CheckBusy();
LCD12864_WriteDAT(':'); //“:”
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII(((*pBuf) & 0xf0) >> 4)); //秒高位
LCD12864_CheckBusy();
LCD12864_WriteDAT(HEX2ASCII((*pBuf) & 0x0f)); //秒低位
}
/***********************************************
函数名称:HEX2ASCII
功 能:十六进制转ASCII函数
入口参数:dat:十六进制数
返 回 值:转换成的ASCII值。
备 注:无
************************************************/
uchar HEX2ASCII(uchar dat)
{
dat &= 0x0f;
if (dat <= 9) return (dat + '0'); //数字0~9
return (dat - 10 + 'A'); //字母A~F
}
/***********************************************
函数名称:Timer0_Init
功 能:定时器0初始化函数
入口参数:无
返 回 值:无
备 注:定时初值可以使用stc下载软件中的
定时初值自动生成功能。
************************************************/
void Timer_Init(void)
{
AUXR &= 0x3f; //T0时钟12T模式
TMOD &= 0x11; //T0,1工作于十六位定时方式
//使用位操作,避免对其他定时器产生影响
TL0 = 0x00; //定时初值50ms 11.0592MHz
TH0 = 0x4c;
TL1 = 0x00; //定时初值50ms 11.0592MHz
TH1 = 0x4c;
TF0 = 0; //清除TF0标记
ET0 = 1; //使能T0中断
TF1 = 0; //清除TF1标记
ET1 = 1; //使能T1中断
EA = 1; //使能总中断
TR0 = 1; //运行T0
TR1 = 0; //关闭T1
}
/***********************************************
函数名称:Timer0_ISR
功 能:定时器0中断服务函数
入口参数:无
返 回 值:无
备 注:无
************************************************/
void Timer0_ISR(void) interrupt 1
{
//static unsigned char T0_Cnt = 0;
//使用静态计数器,每次调用该中断函数时,
//静态计数器都能保持上一次的计数值。
//如果不使用静态计数器,每次调用该中断函数时
//该计数器初值都是0,计数值就无法累加。
TL0 = 0x00; //定时初值50ms 11.0592MHz
TH0 = 0x4c;
T0_Cnt++;
if (T0_Cnt == 20) //定时1000ms
{
T0_Cnt = 0;
UpdateTimeFlag = 1; //更新时间标记有效
}
}
/***********************************************
函数名称:Timer1_ISR
功 能:定时器0中断服务函数
入口参数:无
返 回 值:无
备 注:无
************************************************/
void Timer1_ISR(void) interrupt 3
{
static unsigned char T1_Cnt = 0;
//使用静态计数器,每次调用该中断函数时,
//静态计数器都能保持上一次的计数值。
//如果不使用静态计数器,每次调用该中断函数时
//该计数器初值都是0,计数值就无法累加。
TL1 = 0x00; //定时初值50ms 11.0592MHz
TH1 = 0x4c;
T1_Cnt++;
if (T1_Cnt == 50) //定时
{
T1_Cnt = 0;
chaoshi_flag=1;
Step=0;
TR1=0;
}
}
2.此时可以按下任意键继续,lcd12864屏显示菜单栏中开锁和修改密码两个选项
3.在这里我们可以“4”或“6”选择开锁或者是修改密码。如果这里选择的开锁,按下确定键,此时会提示输入密码,初始密码默认为6666。
4.然后按下确定键,如果密码正确则会显示欢迎小仙女
5.如果输入密码错误则会提示Error 密码错误
6.如果输入密码时间超过规定时间(25s)则会显示Error 已超时,并且会启动蜂鸣器
7.如果输入密码错误超过三次,则会启动蜂鸣器,并且返回到待机画面
8..如果需要修改密码,则在菜单页面选择New password
9.这里会提示输入原始密码
10.输入原始密码后按下确认键,如果密码正确会提示输入新密码
11.输入密码后按下确认键,会提示OK并返回到待机画面
//—— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— //
一些心得:
写程序之前我花了一个多小时的时间理清密码锁所需功能、即将用到的模块、各个步骤之间的关系,画出来可执行性强的程序框图,定义了即将用到的步骤函数。在做设计的过程中,我每一步要做什么,每一步要完成什么任务都有着清晰的思路及逻辑块,在程序测试的过程中分模块debug,使得整体程序的编写及查错简单清晰了许多。
程序的编写并不是特别容易,虽然上学期学了微机课程,但是实际操作起来比理论学习复杂了很多。由于模块庞大,密码锁的程序我是先写出了主要流程:开屏欢迎-菜单选择开锁或者修改密码-输入密码-密码比对-开锁,然后添加了修改密码(输入旧密码-密码对比-正确则输入新密码-存储密码-返回)、密码输入错误超过三次报警提示、密码输入时间超过指定限制报警提示、开屏显示日期(年、月、日、时、分、秒)等功能。分模块、分层次编写使得我的整体编写思路清晰、代码简单、逻辑性强、出错较少。
因为我之前对KEIL5的编程环境有过一些学习,所以对分模块编程、.H文件函数编写及调用、芯片引脚规划有一定的了解及运用能力,这给我的课程设计减小了一点压力。但是我较少使用KEIL5,对程序的实际编写还不够熟悉,编程过程中遇到了很多ERROR及WARNING,例如重复调用、重复编写、中断函数和主函数调用函数冲突、逻辑错误、缺少清屏步骤等,好在通过一次次的逻辑检查及查询CSDN上优秀博主的例程和错误分析,我学会了很多debug技巧,也解决了一些常见错误如逻辑值定义、flag设置及清零等问题。
答辩之后:
答辩的时候,老师说数字密码锁比较简单,只是一些按键逻辑,确实如此,多花些功夫,是能够将密码锁做的更加完善、功能更加复杂的。
我用的这个板子只有3个独立按键和6个行列按键,所以数字我只设置到了0-6,答辩的时候,老师提示我们不能被按键数量限制,比如可以利用加减运算将6个按键扩展成更多的按键。
我暂时没能够想出如何判断按下一个键是要输入还是要做加减运算,我想的是通过长按和短按代表不同的数值,可以将数字范围扩展为两倍,程序里面只需要加一个延时再读案件返回数值的判断函数就行了。(或许加减运算那里也可以通过长按和短按来区分?)
密码锁其实还存在一些问题:
1.密码输入时间超过25s则警告,按照设想,是每次输入时间都控制在25s内,但是运行时是每次输入密码时间累加至25s时都会跳出,导致有时候刚要输密码就跳出了。应该是定时器中断里面那个静态计数值没有清零,我之前设置了清零标志但是程序跑不动,我还没有进一步找到问题。
2.有时候用着用着乱码,应该是有些按键我没有考虑到,按键太多了如果不按照上面规定的每个步骤按规定的键就会乱码。
文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别
文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具
文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量
文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置
文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖
文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...
文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序
文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码
文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型
文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件
文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令
文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线