一、使用proteus绘制简单的电路图,用于后续仿真

二、编写程序

/********************************************************************************************************************
----    @Project:   LED-74HC595
----    @File:  main.c
----    @Edit:  ZHQ
----    @Version:   V1.0
----    @CreationTime:  20200627
----    @ModifiedTime:  20200627
----    @Description:   数字1键对应S1键,数字2键对应S2键,数字3键对应S3键…. 数字9键对应S9键, 数字0键对应S10键。其他的按键不用。
----    本程序有3个窗口。
----    开机显示第1个密码登录框窗口“----”,在这个窗口下输入密码,如果密码等于”9922”表示密码正确,将会切换到第2个显示按键值的窗口。在窗口2下,按不同的按键会显示不同的按键值,如果10秒内没有按键操作,将会自动切换到第1个密码登录窗口,类似手机上的自动锁屏操作。在密码登录窗口1下,如果密码不正确,会自动清除密码的数字,继续在窗口1下显示”----”。
----    窗口3是用来停留0.5秒显示全部密码的信息,然后根据密码的正确与否自动切换到对应的窗口。
----    单片机:AT89C52
********************************************************************************************************************/
#include "reg52.h"
/*——————宏定义——————*/
#define FOSC 11059200L
#define T1MS (65536-FOSC/12/500)   /*0.5ms timer calculation method in 12Tmode*/#define const_voice_short   18  /*蜂鸣器短叫的持续时间*/
#define const_key_time 9    /*按键去抖动延时的时间*/#define const_no_key_push 960 /*大概10秒内无按键按下的时间*/
#define const_0_1s  48  /*大概0.5秒的时间*//*——————变量函数定义及声明——————*/
/*定义数码管的74HC595*/
sbit Dig_Hc595_Sh = P2^0;
sbit Dig_Hc595_St = P2^1;
sbit Dig_Hc595_Ds = P2^2;/*定义蜂鸣器*/
sbit Beep = P2^7;/*作为中途暂停指示灯 亮的时候表示中途暂停*/
sbit LED = P3^5;/*定义按键*/
sbit Key_S1 = P0^0; /*第一行输入*/
sbit Key_S2 = P0^1; /*第二行输入*/
sbit Key_S3 = P0^2; /*第三行输入*/
sbit Key_S4 = P0^3; /*第四行输入*/sbit Key_D1 = P0^4;    /*第一列输入*/
sbit Key_D2 = P0^5; /*第二列输入*/
sbit Key_D3 = P0^6; /*第三列输入*/
sbit Key_D4 = P0^7; /*第四列输入*/unsigned char ucKeyStep = 1;   /*按键扫描步骤变量*/
unsigned int uiKeyTimeCnt = 0;  /*按键去抖动延时计数器*/
unsigned char ucKeyLock = 0;    /*按键触发后自锁的变量标志*/unsigned char ucRowRecord = 1;  /*记录当前扫描到第几列了*/
unsigned char ucKeySec = 0; /*被触发的按键编号*/unsigned char ucDigShow8;   /*第8位数码管要显示的内容*/
unsigned char ucDigShow7;   /*第7位数码管要显示的内容*/
unsigned char ucDigShow6;   /*第6位数码管要显示的内容*/
unsigned char ucDigShow5;   /*第5位数码管要显示的内容*/
unsigned char ucDigShow4;   /*第4位数码管要显示的内容*/
unsigned char ucDigShow3;   /*第3位数码管要显示的内容*/
unsigned char ucDigShow2;   /*第2位数码管要显示的内容*/
unsigned char ucDigShow1;   /*第1位数码管要显示的内容*/unsigned char ucDigDot8;   /*数码管8的小数点是否显示的标志*/
unsigned char ucDigDot7;   /*数码管7的小数点是否显示的标志*/
unsigned char ucDigDot6;   /*数码管6的小数点是否显示的标志*/
unsigned char ucDigDot5;   /*数码管5的小数点是否显示的标志*/
unsigned char ucDigDot4;   /*数码管4的小数点是否显示的标志*/
unsigned char ucDigDot3;   /*数码管3的小数点是否显示的标志*/
unsigned char ucDigDot2;   /*数码管2的小数点是否显示的标志*/
unsigned char ucDigDot1;   /*数码管1的小数点是否显示的标志*/unsigned char ucDigShowTemp = 0;  /*临时中间变量*/
unsigned char ucDisplayDriveStep = 1; /*动态扫描数码管的步骤变量*/unsigned char ucWd1Update = 1;    /*窗口1更新显示标志*/
unsigned char ucWd2Update = 0;  /*窗口2更新显示标志*/
unsigned char ucWd3Update = 0;  /*窗口2更新显示标志*/
unsigned char ucWd = 1; /*本程序的核心变量,窗口显示变量。类似于一级菜单的变量。代表显示不同的窗口。*/unsigned char ucInputPassword[4];   /*在第1个窗口下,显示输入的4个密码*/
unsigned char ucPasswordCnt = 0;    /*记录当前已经输入到哪一位密码了*/
unsigned char ucKeyNumber = 1;  /*在第2个窗口下,显示当前被按下的按键*/unsigned int uiNoKeyPushTimer = const_no_key_push; /*10秒内无按键按下的计时器*/
unsigned int uiPasswordTimer = const_0_1s;  /*显示0.5秒钟全部密码的计时器,让窗口3停留显示0.5秒钟之后自动消失*/unsigned char ucTemp1 = 0;    /*中间过渡变量*/
unsigned char ucTemp2 = 0;  /*中间过渡变量*/
unsigned char ucTemp3 = 0;  /*中间过渡变量*/
unsigned char ucTemp4 = 0;  /*中间过渡变量*/unsigned int uiVoiceCnt = 0;  /*蜂鸣器鸣叫的持续时间计数器*/void Dig_Hc595_Drive(unsigned char, unsigned char);/*根据原理图得出的共阴数码管字模表*/
code unsigned char Dig_Table[] =
{
0x3f,  /*0       序号0*/
0x06,  /*1       序号1*/
0x5b,  /*2       序号2*/
0x4f,  /*3       序号3*/
0x66,  /*4       序号4*/
0x6d,  /*5       序号5*/
0x7d,  /*6       序号6*/
0x07,  /*7       序号7*/
0x7f,  /*8       序号8*/
0x6f,  /*9       序号9*/
0x00,  /*不显示  序号10*/
0x40,  /*-         序号11*/
0x73,  /*P       序号12*/
};/**
* @brief  定时器0初始化函数
* @param  无
* @retval 初始化T0
**/
void Init_T0(void)
{TMOD = 0x01;                    /*set timer0 as mode1 (16-bit)*/TL0 = T1MS;                     /*initial timer0 low byte*/TH0 = T1MS >> 8;                /*initial timer0 high byte*/
}
/**
* @brief  外围初始化函数
* @param  无
* @retval 初始化外围
* 让数码管显示的内容转移到以下几个变量接口上,方便以后编写更上一层的窗口程序。
* 只要更改以下对应变量的内容,就可以显示你想显示的数字。
**/
void Init_Peripheral(void)
{unsigned int i;ucDigDot8 = 0;  ucDigDot7 = 0; ucDigDot6 = 0; ucDigDot5 = 0;   ucDigDot4 = 0;ucDigDot3 = 0;   ucDigDot2 = 0;  ucDigDot1 = 0; for(i = 0; i < 4; i ++){ucInputPassword[i] = 11;    /*开机默认密码全部显示"----"*/}ET0 = 1;/*允许定时中断*/TR0 = 1;/*启动定时中断*/EA = 1;/*开总中断*/
}/**
* @brief  初始化函数
* @param  无
* @retval 初始化单片机
**/
void Init(void)
{LED = 0;Beep = 1;  Dig_Hc595_Drive(0x00, 0x00);    /*关闭所有经过另外两个74HC595驱动的LED灯*/Init_T0();
}
/**
* @brief  延时函数
* @param  无
* @retval 无
**/
void Delay_Long(unsigned int uiDelayLong)
{unsigned int i;unsigned int j;for(i=0;i<uiDelayLong;i++){for(j=0;j<500;j++)  /*内嵌循环的空指令数量*/{; /*一个分号相当于执行一条空语句*/}}
}
/**
* @brief  延时函数
* @param  无
* @retval 无
**/
void Delay_Short(unsigned int uiDelayShort)
{unsigned int i;for(i=0;i<uiDelayShort;i++){; /*一个分号相当于执行一条空语句*/}
}/**
* @brief  显示数码管字模的驱动函数
* @param  无
* @retval   动态驱动数码管的原理
* 在八位数码管中,在任何一个瞬间,每次只显示其中一位数码管,另外的七个数码管
* 通过设置其公共位com为高电平来关闭显示,只要切换画面的速度足够快,人的视觉就分辨不出来,感觉八个数码管
* 是同时亮的。以下dig_hc595_drive(xx,yy)函数,其中第一个形参xx是驱动数码管段seg的引脚,第二个形参yy是驱动
* 数码管公共位com的引脚。
**/
void Display_Drive(void)
{switch(ucDisplayDriveStep){case 1: /*显示第1位*/ucDigShowTemp = Dig_Table[ucDigShow1];if(ucDigDot1 == 1){ucDigShowTemp = ucDigShowTemp | 0x80; /*显示小数点*/}Dig_Hc595_Drive(ucDigShowTemp, 0xfe);break;case 2:    /*显示第2位*/ucDigShowTemp = Dig_Table[ucDigShow2];if(ucDigDot2 == 1){ucDigShowTemp = ucDigShowTemp | 0x80; /*显示小数点*/}Dig_Hc595_Drive(ucDigShowTemp, 0xfd);break;case 3:    /*显示第3位*/ucDigShowTemp = Dig_Table[ucDigShow3];if(ucDigDot3 == 1){ucDigShowTemp = ucDigShowTemp | 0x80; /*显示小数点*/}Dig_Hc595_Drive(ucDigShowTemp, 0xfb);break;case 4:    /*显示第4位*/ucDigShowTemp = Dig_Table[ucDigShow4];if(ucDigDot4 == 1){ucDigShowTemp = ucDigShowTemp | 0x80; /*显示小数点*/}Dig_Hc595_Drive(ucDigShowTemp, 0xf7);break;case 5:    /*显示第5位*/ucDigShowTemp = Dig_Table[ucDigShow5];if(ucDigDot5 == 1){ucDigShowTemp = ucDigShowTemp | 0x80; /*显示小数点*/}Dig_Hc595_Drive(ucDigShowTemp, 0xef);break;case 6:    /*显示第6位*/ucDigShowTemp = Dig_Table[ucDigShow6];if(ucDigDot6 == 1){ucDigShowTemp = ucDigShowTemp | 0x80; /*显示小数点*/}Dig_Hc595_Drive(ucDigShowTemp, 0xdf);break;case 7:    /*显示第7位*/ucDigShowTemp = Dig_Table[ucDigShow7];if(ucDigDot7 == 1){ucDigShowTemp = ucDigShowTemp | 0x80; /*显示小数点*/}Dig_Hc595_Drive(ucDigShowTemp, 0xbf);break;case 8:    /*显示第8位*/ucDigShowTemp = Dig_Table[ucDigShow8];if(ucDigDot8 == 1){ucDigShowTemp = ucDigShowTemp | 0x80; /*显示小数点*/}Dig_Hc595_Drive(ucDigShowTemp, 0x7f);break;}ucDisplayDriveStep ++;    /*逐位显示*/if(ucDisplayDriveStep > 8)   /*扫描完8个数码管后,重新从第一个开始扫描*/{ucDisplayDriveStep = 1;}
}
/**
* @brief  数码管的595驱动函数
* @param  无
* @retval
* 如果直接是单片机的IO口引脚驱动的数码管,由于驱动的速度太快,此处应该适当增加一点delay延时或者
* 用计数延时的方式来延时,目的是在八位数码管中切换到每位数码管显示的时候,都能停留一会再切换到其它
* 位的数码管界面,这样可以增加显示的效果。但是,由于是间接经过74HC595驱动数码管的,
* 在单片机驱动74HC595的时候,dig_hc595_drive函数本身内部需要执行很多指令,已经相当于delay延时了,
* 因此这里不再需要加delay延时函数或者计数延时。
**/
void Dig_HC595_Drive(unsigned char ucDigStatusTemp16_09, unsigned char ucDigStatusTemp08_01)
{unsigned char i;unsigned char ucTempData;Dig_Hc595_Sh = 0;Dig_Hc595_St = 0;    ucTempData = ucDigStatusTemp16_09;  /*先送高8位*/for(i = 0; i < 8; i ++){if(ucTempData >= 0x80){Dig_Hc595_Ds = 1;}else{Dig_Hc595_Ds = 0;}/*注意,此处的延时delay_short必须尽可能小,否则动态扫描数码管的速度就不够。*/Dig_Hc595_Sh = 0;    /*SH引脚的上升沿把数据送入寄存器*/Delay_Short(1); Dig_Hc595_Sh = 1;Delay_Short(1);    ucTempData = ucTempData <<1;}ucTempData = ucDigStatusTemp08_01;   /*再先送低8位*/for(i = 0; i < 8; i ++){if(ucTempData >= 0x80){Dig_Hc595_Ds = 1;}else{Dig_Hc595_Ds = 0;}Dig_Hc595_Sh = 0;   /*SH引脚的上升沿把数据送入寄存器*/Delay_Short(1); Dig_Hc595_Sh = 1;Delay_Short(1);    ucTempData = ucTempData <<1;}Dig_Hc595_St = 0;    /*ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来*/Delay_Short(1);Dig_Hc595_St = 1;Delay_Short(1);Dig_Hc595_Sh = 0;   /*拉低,抗干扰就增强*/Dig_Hc595_St = 0;Dig_Hc595_Ds = 0;
}
/**
* @brief  扫描按键
* @param  无
* @retval 放在定时中断里
**/
void Key_Scan(void)
{switch(ucKeyStep){case 1:  /*按键扫描输出第ucRowRecord列低电平*/if (ucRowRecord == 1) /*第一列输出低电平*/{Key_D1 = 0;Key_D2 = 1;Key_D3 = 1;Key_D4 = 1;}else if(ucRowRecord == 2) /*第二列输出低电平*/{Key_D1 = 1;Key_D2 = 0;Key_D3 = 1;Key_D4 = 1;               }else if(ucRowRecord == 3)  /*第三列输出低电平*/{Key_D1 = 1;Key_D2 = 1;Key_D3 = 0;Key_D4 = 1;               }else if(ucRowRecord == 4)  /*第四列输出低电平*/{Key_D1 = 1;Key_D2 = 1;Key_D3 = 1;Key_D4 = 0;               }   uiKeyTimeCnt = 0;   /*延时计数器清零*/ucKeyStep ++;    /*切换到下一个运行步骤*/      break;case 2:   /*此处的小延时用来等待刚才列输出信号稳定,再判断输入信号。不是去抖动延时。*/uiKeyTimeCnt ++;if(uiKeyTimeCnt > 1){uiKeyTimeCnt = 0;ucKeyStep ++;   /*切换到下一个运行步骤*/  }break;case 3:if(Key_S1 == 1 && Key_S2 == 1 && Key_S3 == 1 && Key_S4 == 1){ucKeyStep = 1;   /*如果没有按键按下,返回到第一个运行步骤重新开始扫描*/ucKeyLock = 0;  /*按键自锁标志清零*/uiKeyTimeCnt = 0;   /*按键去抖动延时计数器清零*/ucRowRecord ++; /*输出下一列*/if(ucRowRecord > 4){ucRowRecord = 1;    /*依次输出完四列之后,继续从第一列开始输出低电平*/}}else if(ucKeyLock == 0) /*有按键按下,且是第一次触发*/{if(Key_S1 == 0 && Key_S2 == 1 && Key_S3 == 1 && Key_S4 == 1){uiKeyTimeCnt ++;if(uiKeyTimeCnt > const_key_time){uiKeyTimeCnt = 0;ucKeyLock = 1;if(ucRowRecord == 1)  /*第一列输出低电平*/{ucKeySec = 1;  /*触发1号键*/}else if(ucRowRecord == 2) /*第二列输出低电平*/{ucKeySec = 2;  /*触发2号键*/}else if(ucRowRecord == 3) /*第三列输出低电平*/{ucKeySec = 3;  /*触发3号键*/}else  /*第四列输出低电平*/{ucKeySec = 4;  /*触发4号键*/}}}else if(Key_S1 == 1 && Key_S2 == 0 && Key_S3 == 1 && Key_S4 == 1){uiKeyTimeCnt ++;if(uiKeyTimeCnt > const_key_time){uiKeyTimeCnt = 0;ucKeyLock = 1;if(ucRowRecord == 1)  /*第一列输出低电平*/{ucKeySec = 5;  /*触发5号键*/}else if(ucRowRecord == 2) /*第二列输出低电平*/{ucKeySec = 6;  /*触发6号键*/}else if(ucRowRecord == 3) /*第三列输出低电平*/{ucKeySec = 7;  /*触发7号键*/}else  /*第四列输出低电平*/{ucKeySec = 8;  /*触发8号键*/}}}else if(Key_S1 == 1 && Key_S2 == 1 && Key_S3 == 0 && Key_S4 == 1){uiKeyTimeCnt ++;if(uiKeyTimeCnt > const_key_time){uiKeyTimeCnt = 0;ucKeyLock = 1;if(ucRowRecord == 1)  /*第一列输出低电平*/{ucKeySec = 9;  /*触发9号键*/}else if(ucRowRecord == 2) /*第二列输出低电平*/{ucKeySec = 10; /*触发10号键*/}else if(ucRowRecord == 3)    /*第三列输出低电平*/{ucKeySec = 11; /*触发11号键*/}else     /*第四列输出低电平*/{ucKeySec = 12; /*触发12号键*/}}}else if(Key_S1 == 1 && Key_S2 == 1 && Key_S3 == 1 && Key_S4 == 0){uiKeyTimeCnt ++;if(uiKeyTimeCnt > const_key_time){uiKeyTimeCnt = 0;ucKeyLock = 1;if(ucRowRecord == 1) /*第一列输出低电平*/{ucKeySec = 13; /*触发13号键*/}else if(ucRowRecord == 2)    /*第二列输出低电平*/{ucKeySec = 14; /*触发14号键*/}else if(ucRowRecord == 3)    /*第三列输出低电平*/{ucKeySec = 15; /*触发15号键*/}else     /*第四列输出低电平*/{ucKeySec = 16; /*触发16号键*/}}}}break;}
}
/**
* @brief  按键输入函数
* @param  无
* @retval 由于数字按键的代码相似度高,因此封装在这个函数里
**/
void number_key_input(unsigned char ucWhichKey)
{switch(ucWd){case 1:   /*在显示密码登录框的窗口下*/ucInputPassword[ucPasswordCnt] = ucWhichKey;    /*输入的密码值显示*/ucPasswordCnt ++;if(ucPasswordCnt >= 4){ucPasswordCnt = 0;ucWd = 3;  /*切换到第3个的窗口,停留显示1秒钟全部密码*/ucWd3Update = 1;   /*更新显示窗口3*/uiPasswordTimer = const_0_1s;    /*显示0.5秒钟全部密码的计时器,让窗口3停留显示0.5秒钟之后自动消失*/}ucWd1Update = 1; /*更新显示窗口1*/uiNoKeyPushTimer = const_no_key_push;    /*10秒内无按键按下的计时器赋新值*/break;case 2:   /*在显示按键值的窗口下*/ucKeyNumber = ucWhichKey; /*输入的按键数值显示*/ucWd2Update = 1;uiNoKeyPushTimer = const_no_key_push;  /*10秒内无按键按下的计时器赋新值*/break;}
}/**
* @brief  按键服务的应用程序
* @param  无
* @retval 无
**/
void Key_Service(void)
{switch(ucKeySec)   /*按键服务状态切换*/{case 1:number_key_input(1);    /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 2:number_key_input(2);    /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 3:number_key_input(3);    /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 4:number_key_input(4);    /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 5:number_key_input(5);    /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 6:number_key_input(6);    /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 7:number_key_input(7);    /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 8:number_key_input(8);    /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 9:number_key_input(9);    /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 10:number_key_input(0);   /*由于数字按键的代码相似度高,因此把具体代码封装在这个函数里*/uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 11:uiVoiceCnt = const_voice_short;    /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 12:uiVoiceCnt = const_voice_short;    /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 13:uiVoiceCnt = const_voice_short;    /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 14:uiVoiceCnt = const_voice_short;    /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 15:uiVoiceCnt = const_voice_short;    /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;case 16:uiVoiceCnt = const_voice_short;    /*按键声音触发,滴一声就停。*/ucKeySec = 0;   /*响应按键服务处理程序后,按键编号清零,避免一致触发*/break;}
}
/**
* @brief  显示的窗口菜单服务程序
* @param  无
* @retval
*凡是人机界面显示,不管是数码管还是液晶屏,都可以把显示的内容分成不同的窗口来显示,
*每个显示的窗口中又可以分成不同的局部显示。其中窗口就是一级菜单,用ucWd变量表示。
*局部就是二级菜单,用ucPart来表示。不同的窗口,会有不同的更新显示变量ucWdXUpdate来对应,
*表示整屏全部更新显示。不同的局部,也会有不同的更新显示变量ucWdXPartYUpdate来对应,表示局部更新显示。
**/
void Display_Service(void)  /*显示的窗口菜单服务程序*/
{switch(ucWd){case 1:   /*显示窗口1的数据*/            /*窗口1要全部更新显示*/if(ucWd1Update == 1)  {ucWd1Update = 0;   /*及时清零标志,避免一直进来扫描*/ucDigShow8 = 10;  /*显示空*/ucDigShow7 = 10; /*显示空*/ucDigShow6 = 10; /*显示空*/ucDigShow5 = 10; /*显示空*/ucDigShow4 = ucInputPassword[0]; /*第4位数码管显示输入的密码*/ucDigShow3 = ucInputPassword[1];   /*第3位数码管显示输入的密码*/ucDigShow2 = ucInputPassword[2];   /*第2位数码管显示输入的密码*/ucDigShow1 = ucInputPassword[3];   /*第1位数码管显示输入的密码*/}break;case 2: /*显示被按下的键值*/            /*窗口2要全部更新显示*/if(ucWd2Update == 1)  {ucWd2Update = 0;   /*及时清零标志,避免一直进来扫描*/ucDigShow8 = 10;  /*显示空*/ucDigShow7 = 10; /*显示空*/ucDigShow6 = 10; /*显示空*/ucDigShow5 = 10; /*显示空*/ucDigShow4 = 10; /*显示空*/ucDigShow3 = 10; /*显示空*/ucDigShow2 = 10; /*显示空*/ucDigShow1 = ucKeyNumber;    /*第1位数码管显示被按下的键值*/                  }break;case 3:  /*当输入完4个密码后,显示1秒钟的密码登录框*/            /*窗口3要全部更新显示*/if(ucWd3Update == 1)  {ucWd3Update = 0;   /*及时清零标志,避免一直进来扫描*/ucDigShow8 = 10;  /*显示空*/ucDigShow7 = 10; /*显示空*/ucDigShow6 = 10; /*显示空*/ucDigShow5 = 10; /*显示空*/ucDigShow4 = ucInputPassword[0]; /*第4位数码管显示输入的密码*/ucDigShow3 = ucInputPassword[1];   /*第3位数码管显示输入的密码*/ucDigShow2 = ucInputPassword[2];   /*第2位数码管显示输入的密码*/ucDigShow1 = ucInputPassword[3];   /*第1位数码管显示输入的密码*/               }break;         }
}/**
* @brief  定时器0中断函数
* @param  无
* @retval 无
**/
void ISR_T0(void)   interrupt 1
{unsigned int i;TF0 = 0;  /*清除中断标志*/TR0 = 0; /*关中断*/if(ucWd == 3)   /*在窗口3下*/{if(uiPasswordTimer > 0){uiPasswordTimer --;}if(uiPasswordTimer == 0){/*如果密码等于9922,则正确*/if(ucInputPassword[0] == 9 && ucInputPassword[1] == 9 && ucInputPassword[2] == 2 && ucInputPassword[3] == 2){ucWd = 2;   /*切换到第2个显示按键的窗口*/ucWd2Update = 1;   /*更新显示窗口2*/}else    /*如果密码不正确,则继续显示----*/{for(i = 0; i < 4; i ++){ucInputPassword[i] = 11;    /*开机默认密码全部显示"----"*/}ucWd = 1;ucWd1Update = 1;  /*更新显示窗口1*/}}}if(ucWd == 2) /*在窗口2下*/{if(uiNoKeyPushTimer > 0){uiNoKeyPushTimer --;}if(uiNoKeyPushTimer == 0)    /*如果10秒内无按键按下,则自动切换到显示密码登录框的界面*/{for(i = 0; i < 4; i ++){ucInputPassword[i] = 11; /*开机默认密码全部显示"----"*/}ucWd = 1;ucWd1Update = 1;  /*更新显示窗口1*/}}if(uiVoiceCnt != 0){uiVoiceCnt--; /*每次进入定时中断都自减1,直到等于零为止。才停止鸣叫*/Beep=0;  /*蜂鸣器是PNP三极管控制,低电平就开始鸣叫。*/}else{; /*此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。*/Beep=1;  /*蜂鸣器是PNP三极管控制,高电平就停止鸣叫。*/}  Key_Scan(); /*按键扫描函数*/Display_Drive();  /*数码管字模的驱动函数*/TL0 = T1MS;                     /*initial timer0 low byte*/TH0 = T1MS >> 8;                /*initial timer0 high byte*/TR0 = 1; /*开中断*/
}
/*————————————主函数————————————*/
/**
* @brief  主函数
* @param  无
* @retval 实现LED灯闪烁
**/
void main()
{/*单片机初始化*/Init();/*延时,延时时间一般是0.3秒到2秒之间,等待外围芯片和模块上电稳定*/Delay_Long(100);/*单片机外围初始化*/   Init_Peripheral();while(1){/*按键服务的应用程序*/Key_Service();/*显示的窗口菜单服务程序*/Display_Service();}
}

三、仿真实现

51单片机实现在数码管中实现iphone4S开机密码锁的程序

单片机学习笔记————51单片机实现在数码管中实现iphone4S开机密码锁的程序相关推荐

  1. 单片机学习笔记————51单片机实现带数码管显示的象棋比赛专用计时器

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  2. 单片机学习笔记————51单片机实现数码管中的倒计时程序

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  3. 单片机学习笔记————51单片机实现带数码管显示的加法简易计算器

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  4. 单片机学习笔记————51单片机实现主机的串口收发

    proteus虚拟串口的实现:https://mp.csdn.net/console/editor/html/107251649 一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 / ...

  5. 单片机学习笔记————51单片机实现用LED灯和按键来模拟工业自动化设备的运动控制

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  6. 单片机学习笔记————51单片机实现矩阵键盘的组合按键触发

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  7. 单片机学习笔记————51单片机实现按住一个独立按键不松手的加速匀速触发

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  8. C51汇编语言寻址方式,单片机学习:51单片机寻址方式详解

    原标题:单片机学习:51单片机寻址方式详解 51单片机是对所有兼容Intel 8031指令系统的单片机的统称.该系列单片机的始祖是Intel 8031单片机,后来随着Flash rom 技术的发展,8 ...

  9. 单片机位寻址举例_单片机学习:51单片机寻址方式详解

    51单片机是对所有兼容Intel 8031指令系统的单片机的统称.该系列单片机的始祖是Intel 8031单片机,后来随着Flash rom 技术的发展,8031单片机取得了长足的发展,成为了应用最广 ...

最新文章

  1. 2019-06-12 学习日记 day33 JDBC
  2. String类型的认识以及编译器优化
  3. vba 压缩图片_1分钟批量处理100张图片,Word图片批量压缩/提取/居中统统搞定
  4. 牛客18987 粉嘤花之恋(矩阵快速幂、斐波那契数列)
  5. php unserialize 实例,PHP ArrayIterator unserialize()用法及代码示例
  6. 《OpenGL编程指南(原书第9版)》——1.4 OpenGL渲染管线
  7. 在Linux下面的某一个文件的查找命令
  8. 如何避免_如何避免钢板弹簧受损
  9. 电力载波通信模块JST-HPLC-S-C在物联网通信领域的应用
  10. Postgresql 客户端连接问题
  11. word添加脚注后正文跑到下一页
  12. 图神经网络在知识图谱中的应用
  13. 过往记忆大数据 USDP 实测搭建,可替代CDH的免费大数据套件平台
  14. 网络重置后网络适配器丢失和网络适配器前面是黄色叹号怎么办?
  15. SAP 采购订单入库——收货业务分析
  16. html制作钟表盘,CSS3简易表盘时钟
  17. Centos7 源码安装mysql5.6
  18. 15必须掌握的win7快捷键
  19. 【ABAP】SE38的一些使用技巧
  20. 【算法】【递归与动态规划模块】两个字符串的公共最长子序列

热门文章

  1. 关于EAD: Elastic-Net Attacks to Deep Neural Networks via Adversarial Examples的理解
  2. 密码算法分类 (学习笔记)
  3. 一文弄懂Python中的 if __name__ == __main__
  4. 各种校验(手机号,银行卡,身份证,邮箱等)
  5. java Comparator 多个字段比较
  6. 如何使用设计模式——qq交流群讨论纪实
  7. 5.4 一家人才测评机构低随机抽取的10名小企业的经理人用两种方法进行自信心测试,得到的自信心测试分数如下
  8. 再谈 Linux下的nanosleep函数【转】
  9. 开发的vscode插件,如何在用户卸载该插件时,删除该插件对应的文件
  10. 利用oc门或od门实现线与_oc门_od门_ttl三态门电路特点总汇