液晶密码锁(可更改密码)

main.c

/*********************************************************
**  FileName: 		  液晶密码锁

**  Description: 
使用液晶完成一个密码锁功能
初始界面
password:
输入数字在下方显示,按下回车完成输入
初始密码12345
输入正确提示:hello world!	2s返回初始界面
输入错误提示:error!try again 2s返回初始界面
按下向上键提示:old password:
输入正确提示 :new password: 设置完毕提示success! 2s返回初始界面
错误提示:error! 2s返回初始界面
 
**  Author:		      老猫
**  Date:   		  2019/9/2
**  Others:	  E2PRom初始值需要进行烧写,可以写烧进去再删除写语句
*********************************************************/
#include <reg52.h>
#include <string.h>
extern unsigned char TORH;
extern unsigned char TORL;
extern void KeyDriver();
extern void InitLcd1602();
extern void ConfigTimer0(unsigned int ms);
extern void KeyScan();
extern void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str);
extern void LcdFullClear();
extern void E2Write(unsigned char *buf,unsigned char addr,unsigned char len);
extern void E2Read(unsigned char *buf,unsigned char addr,unsigned char len);
unsigned char str[30];
unsigned char password[30]="12345";
unsigned char len=0;
bit change=0;
bit flag1=0;
void delayms(unsigned int xms)//延时函数
{
	unsigned int i,j;
	for (i=xms;i>0;i--)
		for(j=110;j>0;j--);
}
void TurnToInit()
{
	LcdFullClear();	//清屏
	len=0;
	flag1=0;
	change=0;
	memset(str,0,30);
	LcdShowStr(0,0,"password:");
}
void InitMain()
{
	E2Read(password,0x10,sizeof(password));
	InitLcd1602();//液晶初始化
	ConfigTimer0(1);//设置定时时间为1ms
	LcdShowStr(0,0,"password:");
}
void KeyAction(unsigned char keycode)
{
	if((keycode-'0')<=9&&(keycode-'0')>=0)//输入的是数字
	{
		str[len++]=keycode;	
		LcdShowStr(0,1,str);
	}
	else if(keycode==0x0D)//按下回车键
	{
		if(flag1==1&&change==1)
		{
			strcpy(password,str);
			LcdFullClear();
			LcdShowStr(0,0,"success!");
			LcdShowStr(0,1,"new:");
			LcdShowStr(0,4,password);
			E2Write(password,0x10,sizeof(password));
			delayms(2000);
			TurnToInit();
		}
		else if(strcmp(str, password)==0&&change==0)//密码相同
		{
			LcdFullClear();	
			LcdShowStr(0,0,"hello world!");
			delayms(2000);
			TurnToInit();
		}			
		else if(strcmp(str, password)==0&&change==1)//设置新密码
		{
			LcdFullClear();
			memset(str,0,30);
			LcdShowStr(0,0,"new password:");
			len=0;
			flag1=1;
		}
		else if(strcmp(str, password)!=0&&change==0)
		{
			LcdFullClear();	
			LcdShowStr(0,0,"error!try again");
			delayms(2000);
			TurnToInit();			
		}
		else if(strcmp(str, password)!=0&&change==1)
		{
			LcdFullClear();
			LcdShowStr(0,0,"error!");
			delayms(2000);
			TurnToInit();
		} 
	}
	else if(keycode==0x26)//输入向上键进行密码调试
	{
		change=1;
		LcdFullClear();
		LcdShowStr(0,0,"old password:");
	}
	else 
	{
		TurnToInit();
	}
}
void main()
{
	EA=1;
	InitMain();
	while(1)
	{
		KeyDriver();
	}
}
void InterruptTimer0() interrupt 1
{
	TH0=TORH;
	TL0=TORL;
	KeyScan();//按键扫描
}

lcd1602.c

/*
液晶显示相关代码
*/
#include <reg52.h>
#define LCD1602_DB P0
sbit LCD1602_RS=P1^0;
sbit LCD1602_RW=P1^1;
sbit LCD1602_E=P1^5;
void LcdWaitReady()//读状态
{
	unsigned char sta;
	LCD1602_DB=0XFF;//开始就进行读取
	LCD1602_RS=0;
	LCD1602_RW=1;
	do{
		LCD1602_E=1;
		sta=LCD1602_DB;
		LCD1602_E=0;
	}while(sta&0x80);//判断高位为1,即为忙状态
}
void LcdWriteCmd(unsigned char cmd)//写入命令
{
	LcdWaitReady();//写入之前需要判断状态
	LCD1602_RS=0;
	LCD1602_RW=0;
	LCD1602_DB=cmd;
	LCD1602_E=1;
	LCD1602_E=0;
}
void LcdWriteDat(unsigned char dat)//写入数据
{
	LcdWaitReady();	//进行状态的判断
	LCD1602_RS=1;
	LCD1602_RW=0;
	LCD1602_DB=dat;
	LCD1602_E=1;
	LCD1602_E=0;
}
void LcdSetCursor(unsigned char x,unsigned char y)//进行光标位置的判断
{
	unsigned char addr;
	if(y)//y为1
		addr=0x40+x;
	else
		addr=0x00+x;
	LcdWriteCmd(addr|0x80);
}
void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)//对字符进行显示
{
	LcdSetCursor( x, y);
	while(*str!='\0')
	{
	   LcdWriteDat(*str++);
	}
}
//进行液晶显示的初始化
void InitLcd1602()
{
	LcdWriteCmd(0x38);
	LcdWriteCmd(0x0c);
	LcdWriteCmd(0x06);//文字不动,地址加1
	LcdWriteCmd(0x01);//进行清屏显示
}
void LcdFullClear()	//清屏函数
{
	LcdWriteCmd(0x01);
}

configtimer0.c

#include <reg52.h>
unsigned char TORH=0;
unsigned char TORL=0;
void ConfigTimer0(unsigned int ms)
{
	unsigned long tmp;
	tmp=11059200/12*ms/1000;
	tmp=65536-tmp;
	TORH=(unsigned char)(tmp>>8);
	TORL=(unsigned char)(tmp);
	TMOD&=0XF0;
	TMOD|=0X01;
	TH0=TORH;
	TL0=TORL;
	ET0=1;
	TR0=1;
}

keyboard.c

#include <reg52.h>
sbit KEY_IN_1  = P2^4;
sbit KEY_IN_2  = P2^5;
sbit KEY_IN_3  = P2^6;
sbit KEY_IN_4  = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;
unsigned char code KeyCodeMap[4][4] = { //矩阵按键编号到标准键盘键码的映射表
    { '1',  '2',  '3', 0x26 }, //数字键1、数字键2、数字键3、向上键
    { '4',  '5',  '6', 0x25 }, //数字键4、数字键5、数字键6、向左键
    { '7',  '8',  '9', 0x28 }, //数字键7、数字键8、数字键9、向下键
    { '0', 0x1B, 0x0D, 0x27 }  //数字键0、ESC键、  回车键、 向右键
};
unsigned char pdata KeySta[4][4] = {  //全部矩阵按键的当前状态
    {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}
};
extern void KeyAction(unsigned char keycode);
/* 按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 */
void KeyDriver()
{
    unsigned char i, j;
    static unsigned char pdata backup[4][4] = {  //按键值备份,保存前一次的值
        {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}
    };
    for (i=0; i<4; i++)  //循环检测4*4的矩阵按键
    {
        for (j=0; j<4; j++)
        {
            if (backup[i][j] != KeySta[i][j])    //检测按键动作
            {
                if (backup[i][j] != 0)           //按键按下时执行动作
                {
                    KeyAction(KeyCodeMap[i][j]); //调用按键动作函数
                }
                backup[i][j] = KeySta[i][j];     //刷新前一次的备份值
            }
        }
    }
}

/* 按键扫描函数,需在定时中断中调用,推荐调用间隔1ms */
void KeyScan()
{
    unsigned char i;
    static unsigned char keyout = 0;   //矩阵按键扫描输出索引
    static unsigned char keybuf[4][4] = {  //矩阵按键扫描缓冲区
        {0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF},
        {0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF}
    };

    //将一行的4个按键值移入缓冲区
    keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
    keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
    keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
    keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
    //消抖后更新按键状态
    for (i=0; i<4; i++)  //每行4个按键,所以循环4次
    {
        if ((keybuf[keyout][i] & 0x0F) == 0x00)
        {   //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
            KeySta[keyout][i] = 0;
        }
        else if ((keybuf[keyout][i] & 0x0F) == 0x0F)
        {   //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
            KeySta[keyout][i] = 1;
        }
    }
    //执行下一次的扫描输出
    keyout++;         //输出索引递增
    keyout &= 0x03;   //索引值加到4即归零
    switch (keyout)   //根据索引,释放当前输出引脚,拉低下次的输出引脚
    {
        case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
        case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
        case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
        case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
        default: break;
    }
}

I2C.c

//I2C.c文件
#include <reg52.h>
#include <intrins.h>
#define I2CDelay(){_nop_();_nop_();_nop_();_nop_();} //一个_nop_()为一个机器周期
sbit I2C_SCL=P3^7;
sbit I2C_SDA=P3^6;
void I2CStart()//产生起始信号
{
	I2C_SDA=1;
	I2C_SCL=1;
	I2CDelay();
	I2C_SDA=0;
	I2CDelay();
	I2C_SCL=0;
}
void I2CStop() //产生结束信号
{
	I2C_SCL=0;
	I2C_SDA=0;
	I2CDelay();
	I2C_SCL=1;
	I2CDelay();
	I2C_SDA=1;
	I2CDelay();
}
bit I2CWrite(unsigned char dat)	//写操作,返回值为从机应答位值
{
	bit ack;
	unsigned char mask;
	for(mask=0x80;mask!=0;mask>>=1)	//从高位到低位发送数据位
	{
		if((mask&dat)==0)
			I2C_SDA=0;
		else
			I2C_SDA=1;
		I2CDelay();
		I2C_SCL=1;
		I2CDelay();
		I2C_SCL=0;
	}
	I2C_SDA=1; //发送完数据位将这个电平拉高,检测应答位
	I2CDelay();
	I2C_SCL=1;
	ack=I2C_SDA;
	I2CDelay();
	I2C_SCL=0;
	return (~ack);//进行取反以符合正常的逻辑
}
//读操作,并发送非应答信号,返回值为读到的字节
unsigned char I2CReadNAK() //从高位到低位进行读取
{
	unsigned char mask;
	unsigned char dat;
	I2C_SDA=1;
	for(mask=0x80;mask!=0;mask>>=1)
	{
		I2CDelay();
		I2C_SCL=1;//拉高SCL
		if(I2C_SDA==0)//为0对应位为0
			dat&=~mask;
		else
			dat|=mask;//为1对应位为1
		I2CDelay();
		I2C_SCL=0;
	}	
	I2C_SDA=1;
	I2CDelay();
	I2C_SCL=1;
	I2CDelay();
	I2C_SCL=0;
	return dat;
}
unsigned char I2CReadACK()//读操作,并发送应答信号,就可以继续往下读取
{
	unsigned char mask;
	unsigned char dat;
	I2C_SDA=1;
	for(mask=0x80;mask!=0;mask>>=1)
	{
		I2CDelay();
		I2C_SCL=1;//拉高SCL
		if(I2C_SDA==0)//为0对应位为0
			dat&=~mask;
		else
			dat|=mask;//为1对应位为1
		I2CDelay();
		I2C_SCL=0;
	}	
	I2C_SDA=0;
	I2CDelay();
	I2C_SCL=1;
	I2CDelay();
	I2C_SCL=0;
	return dat;
}

E2PROM.c

#include <reg52.h>
extern void I2CStart();
extern void I2CStop();
extern unsigned char I2CReadACK();
extern unsigned char I2CReadNAK();
extern bit I2CWrite(unsigned char dat);
//读取函数,buf为数据指针,addr为E2中的起始地址,len为读取长度
void E2Read(unsigned char *buf,unsigned char addr,unsigned char len)
{
		do{
			I2CStart();
			if(I2CWrite(0x50<<1))
			{
				break;
			}
			I2CStop();
		}while(1);//查询当前是否可以进行读写操作
		I2CWrite(addr);
		I2CStart();
		I2CWrite((0x50<<1)|0x01);
		while(len>1)//连续读取len-1个字节
		{
		   *buf++=I2CReadACK();
		   len--;
		}
		*buf=I2CReadNAK();
		I2CStop();
}
//写入函数,buf为源数据指针,addr为起始地址,len为写入长度
void E2Write(unsigned char *buf,unsigned char addr,unsigned char len)
{
	while(len--)
	{
		do{
			I2CStart();
			if(I2CWrite(0x50<<1))
				break;
			I2CStop();
		} while(1);
		I2CWrite(addr++); 
		I2CWrite(*buf++);
		I2CStop();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王蒟蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值