📄 locker_with_lcd_and_clock.txt
字号:
程序说明:
本程序用到4x4按键中断扫描法,用lcd显示,开机时候显示一个数字钟(时间不可设,稍后加入该功能),钟正常走
如果按下开锁键,进入以请输入密码界面,输入密码,如果密码正确,显示欢迎使用,密码错误蜂鸣器报警
且LCD显示密码错误,请重新输入。
注:数字时钟用的是DS1302实现,由于本人也才学单片机一个多月,所以注释非常详细,初学者很容易看懂。
**************************************************************************************************************/
#include <reg52.h>
#include <intrins.h>
sbit SPK=P3^4; //SPK定义为P3口的第4位,就是驱动蜂鸣器的那个脚
sbit JDQ=P3^5; //JDQ定义为P3口的第5位,就是驱动继电器的那个脚
sbit lcdrs = P1^0; //数据命令选择端 (H/L)
sbit lcdrw = P1^1; //读写选择端 (H/L)
sbit lcde = P1^2; //使能信号
sbit OK = P0^5; //密码输入确认键
sbit H = P0^4;//独立按键定义位
sbit take = P0^6;//开锁键
sbit SCL2 = P1^3; //SCL2定义为P1口的第3位脚,连接DS1302SCL和ADC0831SCL脚
sbit SDA2 = P1^4; //SDA2定义为P1口的第4位脚,连接DS1302SCL和ADC0831SDA脚
sbit RST = P1^5; // DS1302片选脚
#define LCD_Data P2
#define Busy 0x80 //用于检测LCD状态字中的Busy标识
#define uchar unsigned char
#define uint unsigned int
code unsigned char table[]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71};
//共阴数码管 0-9 a-f 表
code unsigned char key_tab[10]={0xed,0x7e,0x7d,0x7b,
0xbe,0xbd,0xbb,0xde,
0xdd,0xdb,};//0x77,0xb7,
// 0xee,0xd7,0xeb,0xe7,0XFF};//========================此数组为键盘编码,
//本人采用类式类似电话按键的编码方式,方便以后设计
// 1 2 3 a 0x01 0x02 0x03 0x0a
// 4 5 6 b 对应16进制码: 0x04 0x05 0x06 0x0b
// 7 8 9 e 0x07 0x08 0x09 0x0e
// * 0 # f 0x0c 0x00 0x0e 0x0f
//打个比方,如果你按下0键,P0口读到数据为0xed
//如果你按下2键,P0口读到数据为0x7d,按下9键为0xdb,
//我们将读到的P0口数据经过查表法就能得到相应的16进制码
//键盘的读取,我们采用中断法,电路用一个4与门(74HC21)接入
//中断口(INT0),利用中断来扫描键盘矩阵,读取数据
unsigned char l_tmpdate1[4]={0,0,0,0};//定义数组变量
uchar table_password[4]={1,2,3,4}; //密码
code uchar table_right[]="welcome use!";
code uchar table_num[]="input password:";
code uchar table_error[]="input error!";
code uchar table_error1[]="Pls try again!";
unsigned char l_key=0; //定义变量,存放键值
unsigned char l_keyold=0xFF; //做为按键松开否的凭证
uchar buzyc,flag=0,mima;
uchar funtion_flag=0,temp_num;
char shi,fen,miao,nian,yue,ri,xin;
unsigned char l_tmpdate[8]={0x00,59,12,19,2,8,2};//显示初值
unsigned char l_tmpdisplay[8]={0x40,0x40,0x40,0x40,0x40,0x40,0x40,0};//待显示的数
code unsigned char write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8c,0x8a}; //1302写入地址
code unsigned char read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8d,0x8b};//1302读出地址
//code unsigned char table[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00};//共阴数码管 0-9 '-' '熄灭‘表
uchar date1[]="MON";
uchar date2[]="TUE";
uchar date3[]="WED";
uchar date4[]="THU";
uchar date5[]="FRI";
uchar date6[]="SAT";
uchar date7[]="SUN";
void ReadKey(void) //读键盘值
{
unsigned char i,j,key,n;
j=0xfe;
key=0xff;//设定初值
for (i=0;i<3;i++)
{
P0=j; //P0口低4位循环输出0,扫描键盘
if ((P0&0xf0)!=0xf0)
{ //如果有键按下,P0口高4位不会为1,
key=P0; //读取P0口,退出循环,否则循环下次
break;
}
j=_crol_(j,1); //此函数功能为左循环移位
}
if (key==0xff)
{ //如果读取不到P0口的值,比如是干扰,我们不做键值处理,返回
l_keyold=0xff;
P0=0xf0; //恢复P0口,等待按键按下
EX0=1; //返回之前,开启外中断
SPK=1;
return;
}
SPK=0; //有键按下,我们驱动蜂鸣器响
if(l_keyold==key)
{ //检测按键放开否,如果一样表明没放开,
TH0=0X2E; //我们继续启动定时器,检测按键松开否
TL0=0;
TR0=1;
return;
}
TH0=0X2E;
TL0=0;
TR0=1; //我们继续启动定时器,检测按键松开否
l_keyold=key; //获取键码做为放开的凭证
for(i=0;i<10;i++)
{ //查表获得相应的16进制值存放l_key变量中
if (key==key_tab[i])
{
l_key=i;
l_tmpdate1[n]=l_key;//将获得的数装入一个新的数组
n++;
if(n==4) //装满四位就从新装入
n=0;
//判断被按下去的数字与设定密码是否相符
if(l_tmpdate1[0]==table_password[0]&l_tmpdate1[1]==table_password[1]&l_tmpdate1[2]==table_password[2]&l_tmpdate1[3]==table_password[3])
mima=1;
break;
}
}
//程序运行到这里,就表明有键值被读取存放于l_key变量中,主程序就可以检测此变量做相应外理,
//此时我们回到主程序
}
//延时函数
void delay(uint z) //延时函数,z的取值为这个函数的延时ms数,如delay(200);大约延时200ms.
{ //delay(500);大约延时500ms.
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
//读状态,忙检测处理函数
unsigned char ReadStatusLCD(void)
{
LCD_Data = 0xFF;
lcdrs = 0;
lcdrw = 1;
lcde = 0;
lcde = 0;
lcde = 1;
while ((LCD_Data & Busy)==Busy); //检测忙信号
return(LCD_Data);
}
//写命令子函数
void write_com(uchar com,buzyc)
{
if(buzyc)
ReadStatusLCD();//忙检测
lcdrw=0;
lcdrs=0;
P2=com;
delay(3);
lcde=1;
delay(6);
lcde=0;
}
//写数据子函数
void write_date(uchar date)
{
ReadStatusLCD();//忙检测
lcdrw=0;
lcdrs=1;
P2=date;
delay(3);
lcde=1;
delay(6);
lcde=0;
}
//初始化函数
void init()
{
H=0;
lcde=0;
delay(15);
write_com(0x38,0);
delay(5);
write_com(0x38,0);
delay(5);
write_com(0x38,0);
write_com(0x38,1); //设置led为16×2显示,5×7点阵,8位数据口
write_com(0x0f,1); //开显示,显示光标,光标闪烁
write_com(0x06,1); //光标自动移动,整屏不动
write_com(0x01,1); //显示清屏,数据指针和地址指针全部清零
write_com(0x80,1); //设置数据指针到屏幕的最开始端
}
/*****************************************************************************************************
字节写入子函数:
将要写入的数字先右移一位,是最低位溢出,然后在scl2的一个上升沿数据被写入DS1302,注意
数据的写入时从低位到高位
*****************************************************************************************************/
void Write_Ds1302_Byte(unsigned char date)
{
uchar j,temp;
temp=date;
for(j=0;j<8;j++)
{
temp=temp>>1; //将数据右移一位使最低位溢出
SDA2=CY; //将待写入数据最低位写入数据缓冲
SCL2=0;
SCL2=1; //在scl的上升延写入数据
}
}
/*****************************************************************************************************
字节读出子函数:
分8次读出数据,将读出的数据存入temp:在时钟信号的下降沿读出一个字节的数据
数据读出也是从低位到高位的
*****************************************************************************************************/
uchar Read_Ds1302_Byte()
{
uchar j,temp;
for(j=0;j<8;j++)
{
temp=temp>>1; //将temp右移一位使最高位变为次高位,最高为为0
SDA2=1;
SCL2=1;
SCL2=0; //在scl2的一个下降沿数据读出
if(SDA2==1)//如果读出的数据为1,即在temp的最高位写入1,为0的时候则写入0
temp=temp|0x80;
temp=temp|0x00;
}
return temp;
}
/***************************************************************************************************************
数据写入DS1302函数:
在指定地址写入指定数据,在rst为低scl2为低的情况下将rst置高,即允许数据写入
先写入地址
然后写入数据
最后将rst拉低结束数据写入
****************************************************************************************************************/
void Write_Ds1302( unsigned char address,unsigned char dat )
{
RST=0;
_nop_();_nop_();_nop_();_nop_();_nop_();
SCL2=0;
_nop_();_nop_();_nop_();_nop_();_nop_();
RST=1;
_nop_();_nop_();_nop_();_nop_();_nop_(); //开启,写入数据地址,这是本串口协议的开始,加入延时防止干扰
Write_Ds1302_Byte(address); //发送地址
Write_Ds1302_Byte(dat); //发送数据
RST=0; //恢复
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -