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();
}
}
3071

被折叠的 条评论
为什么被折叠?



