【C51】课设:电子密码锁

学校单片机结课课设,课题为电子密码锁,平台为AT89C52
琢磨明白github后会把代码全部上传到GitHub,有问题可以留言或私信,看到就回。(2023.4)

系统结构

在这里插入图片描述
主要外设有4X4矩阵键盘EEPROM存储数码管

硬件原理图

在这里插入图片描述
用了嘉立创EDA

代码

主程序

#include "main.h"
#include "string.h"
#include "seg.h"
#include "key.h"
#include "at24c02.h"
sbit AUXR = 0x8e;

//变量
u8 key_scan_flag;
u8 key_val = 0; //读取按键标志
u8 mode = 0; //当前模式,0 - 输入/管理/登陆 1 - 提示信息界面 2 - 自锁
u8 menu_index = 0; //当前模式下的菜单模式,0 - 输入 1 - 登陆 2 - 管理
u8 error_times = 0; //错误次数
u8 fin_counter = 0;  //当前已输入密码位数
u8 infor_type = 0; //0无提示消息 1-open 2-error 3-change
u8 self_down = 60;
u16 counter = 0;
code u8 char_Code[] = {
	//   0     1     2    3      4     5    6     7     8     9    
    ~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,~0x07,~0x7F,~0x6F,
};
code u8 menu_item[] = {~0x3F,~0x31,~0x37};
code u8 information[3][8] = {
	{~0x3F,~0x73,~0x79,~0x37,0xff,0xff,0xff,0xff}, //开锁
	{~0x79,~0x31,~0x31,~0x3F,~0x31,0xff,0xff,0xff}, //密码错误
	{~0x39,~0x76,~0x77,~0x37,~0x3d,~0x79,0xff,0xff} //更改成功
	
};
u8 disp_num[] = {0xff,0xff,0xff,0xff,
								0xff,0xff,0xff,0xff
};
u8 disp_com[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 //高到低,数码管位选
};

u8 input_code[4] = {0xff,0xff,0xff,0xff}; //用于记录已输入密码
u8 save_psw[4] = {~0x3f,~0x3f,~0x3f,~0x3f}; //用于保存正确密码,低位到高位

//函数
void Timer0Init(void); //定时器初始化
void key_switch(void); //按键选择
u8 judge_password(void); //判断密码是否正确,0 - 错误,1 - 正确
void seg_show(void); //数码管显示

void work_function(void);


void main(){
	
	u8 i;
	
	Timer0Init();
	
	for(i = 0;i < 4;i++){ //第一次上电时存入初始密码,下载完后可以注释掉重新编译
		AT24C02_WriteData(i,char_Code[i]);
	}
	
	for(i = 0;i < 4;i++){
		save_psw[i] = AT24C02_ReadData(i);
	}
	
	while(1){
		if(key_scan_flag){ //读取按键值
			key_scan_flag = 0;
			key_val = key_read();
		}
		key_switch();
		work_function();

	}
}

//按键模块
void key_switch(void){
	
	if(key_val == 0) return;
	if(mode == 2) return;
	
	if(key_val == 0x77){ //S1 输入数字1
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[1];
		}
	}
	else if(key_val == 0xb7){ //S2 输入数字2
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[2];
		}
	}
	else if(key_val == 0xd7){ //S3 输入数字3
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[3];
		}
	}
	else if(key_val == 0xe7){ //S4 进入管理员界面
		menu_index = 1; //登陆
		fin_counter = 0; //已输入的密码位数清零
		error_times = 0;
	}
	else if(key_val == 0x7b){ //S5 输入数字4
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[4];
		}
	}
	else if(key_val == 0xbb){ //S6 输入数字5
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[5];
		}
	}
	else if(key_val == 0xdb){ //S7 输入数字6
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[6];
		}
	}
	else if(key_val == 0xeb){ //S8 退出登陆
		if(menu_index == 2){
			menu_index = 1;
			fin_counter = 0;
			error_times = 0;
		}
	}
	else if(key_val == 0x7d){ //S9 输入数字7
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[7];
		}
	}
	else if(key_val == 0xbd){ //S10 输入数字8
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[8];
		}
	}
	else if(key_val == 0xdd){ //S11 输入数字9
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[9];
		}
	}
	else if(key_val == 0xed){ //S12 返回输入界面
		menu_index = 0;
		fin_counter = 0;
	}
	else if(key_val == 0x7e){ //S13 确定
		if(menu_index == 0 || menu_index == 1){
			if(fin_counter < 4){
				fin_counter = 0;
				if(++error_times == 3){
					error_times = 0;
					mode = 2;
					counter = 0;
					self_down = 60;
				}else{
					mode = 1;
					infor_type = 2;
					counter = 0;
				}
			}else{
				fin_counter = 0;
				if(judge_password()){ //密码正确
					if(menu_index == 0){
						mode = 1;
						infor_type = 1;//开锁
						counter = 0;
					}else{
						mode = 0;
						menu_index = 2;//进入管理员界面
					}
				}else{
					if(++error_times == 3){ //错误次数达到3次,进入自锁模式
						error_times = 0;
						mode = 2;
						self_down = 60;
						counter = 0;
					}else{
						mode = 1;
						infor_type = 2; //错误
						counter = 0;
					}
				}				
			}
		}
		else if(menu_index == 2){
			u8 i;
			if(fin_counter < 4){
				mode = 1;
				infor_type = 2;
				counter = 0;
				return;
			}
			//管理员界面,存储密码
			
			for(i = 0;i < 4;i++){
				save_psw[i] = input_code[i];
				AT24C02_WriteData(i,save_psw[i]);
			}
			mode = 1; //进入提示信息
			infor_type = 3;
			fin_counter = 0;
			counter = 0;
		}
	}
	else if(key_val == 0xbe){ //S14 输入数字0
		if(fin_counter < 4){
			input_code[fin_counter++] = char_Code[0];
		}
	}
	else if(key_val == 0xde){ //S15 回退
		input_code[--fin_counter] = 0xff;
	}
	else if(key_val == 0xee){ //S16 清空
		u8 i;
		for(i = 0;i < fin_counter;i++){
			input_code[i] = 0xff;
		}
		fin_counter = 0;
	}
	
	key_val = 0;
}


//数码管显示模块
void seg_show(void){
	u8 i;
	
	for(i = 0;i < 8;i++){
		disp_seg(disp_com[i],disp_num[i]);
	}
}

//判断密码
u8 judge_password(void){
	u8 rtval = 0;
	u8 i;
	
	for(i = 0;i < 4;i++){
		if(save_psw[i] != input_code[i]){
			rtval = 0;
			break;
		}
		rtval = 1;
	}
	return rtval;
}


//工作模块
void work_function(void){
	//1.先判断处于哪个模式
	if(mode == 0){ //正常模式
		u8 i,j;
		memset(disp_num,0xff,sizeof(disp_num));
		disp_num[0] = menu_item[menu_index];
		for(i = 4,j = 0;i < 8;i++){
			if(i < 8 - fin_counter) disp_num[i] = 0xff;
			else disp_num[i] = input_code[j++];
		}		
	}
	else if(mode == 1){ //提示信息界面
		u8 i;
		memset(disp_num,0xff,sizeof(disp_num));		
		for(i = 0;i < 8;i++){
			disp_num[i] = information[infor_type - 1][i];
		}
	}
	else if(mode == 2){ //自锁界面
		if(self_down == 0){
			mode = 0;
			return;
		}
		memset(disp_num,0xff,sizeof(disp_num));
		if(self_down > 10) disp_num[6] = char_Code[self_down / 10];
		disp_num[7] = char_Code[self_down % 10];
	}
	
	seg_show();
}


//定时器模块
void Timer0Init(void)		//10毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA = 1;
	ET0 = 1;
}

void Timer0Function(void) interrupt 1{ //定时器0中断服务函数
	static u8 key_counter = 0;
	
	if(++key_counter == 1){
		key_scan_flag = 1;
		key_counter = 0;
	}
	
	if(mode == 1){
		if(++counter == 200){
			mode = 0;
		}
	}
	else if(mode == 2){
		if(++counter == 100){
			self_down--;
			counter = 0;
		} 
	}
}

数码管底层代码

数码管用两片74HC595构成的位移缓存器连接,可以减少引脚的使用。

#include "seg.h"

sbit SEG_DIO = P1^0;  
sbit SEG_SCLK = P1^1; 
sbit SEG_RCLK = P1^2;

//写数据
void write_data_595(u8 dat);

void disp_seg(u8 addr,u8 dat){
	write_data_595(addr); //输出位码
	write_data_595(dat);  //输出段码
	SEG_RCLK = 1;     //锁存数据
	SEG_RCLK = 0;
}

void write_data_595(u8 dat){
	u8 i;
	
	for(i = 0;i < 8;i++){
		if(dat & 0x80) SEG_DIO = 1;
		else SEG_DIO = 0;
		
		dat <<= 1;
		SEG_SCLK = 0;
		SEG_SCLK = 1;
	}
}

矩阵按键底层代码

运用了状态机的思想

#include "key.h"
u8 key_read(void){
	static u8 key_state;
	u8 key_rtval = 0,key_press = 0;
	
	R4 = R3 = R2 = R1 = 0;C4 = C3 = C2 = C1 = 1;
	if(C1 == 0) key_press = 0x70;
	else if(C2 == 0) key_press = 0xb0;
	else if(C3 == 0) key_press = 0xd0;
	else if(C4 == 0) key_press = 0xe0;
	else key_press = 0;
	
	R4 = R3 = R2 = R1 = 1;C4 = C3 = C2 = C1 = 0;
	if(R1 == 0) key_press |= 0x07;
	else if(R2 == 0) key_press |= 0x0b;
	else if(R3 == 0) key_press |= 0x0d;
	else if(R4 == 0) key_press |= 0x0e;
	else key_press = 0;
	
	switch(key_state){
		case 0:
			if(key_press != 0) key_state = 1;
			break;
		case 1:
			if(key_press != 0){
				key_rtval = key_press;
				key_state = 2;
			}
			else key_state = 0;
			break;
		case 2:
			if(key_press == 0) key_state = 0;
			break;
	}
	return key_rtval;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值