完整电路图:
完整代码:
#include <reg51.h>
#include <intrins.h> //包含_nop_( )空函数指令的头文件
#define uchar unsigned char
#define uint unsigned int
#define out P2
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
sbit RST=P1^7 ;
sbit SCLK =P1^6;
sbit DSIO=P1^5;
sbit set=P1^0; //设置时间按钮
sbit up=P1^1; // 增加时间
sbit down=P1^2; // 减小时间
void lcd1602_initial(void); //lcd1602初始化函数
void lcd1602_write_command(uchar com); //lcd1602写命令函数
void lcd1602_write_data(uchar dat); //lcd1602写数据函数
void lcd1602_string(uchar ad ,uchar *s);//lcd1602写字符串
void delay(uint); //延时函数
void Ds1302Write(uchar add,uchar dat);
uchar Ds1302Read(uchar add);
void Ds1302Readtime_data();
uchar bcd_decimal(uchar bcd);
void write_time(uchar add,uchar date);
void xinshi_time();
uchar key_bcd(uchar key_decimal);
void key_set();
void key_process();
void key_up_down();
uchar code table1[]={"2021-01-24"};
uchar code table2[]={"23:59:50"};
uchar nian,zhou,yue,ri,shi,fen,miao;
uchar count=0,done=0,flag=1,flag_up=0,flag_down=0;
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar code read_add[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
uchar code write_add[7]= {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
//---DS1302时钟初始化2013年1月1日星期二12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar code time_data[7]= {0x58, 0x40, 0x14, 0x29, 0x01, 0x01, 0x21};
uchar code xingqi1[]={"MON"};
uchar code xingqi2[]={"TUE"};
uchar code xingqi3[]={"WED"};
uchar code xingqi4[]={"THU"};
uchar code xingqi5[]={"FRI"};
uchar code xingqi6[]={"SAT"};
uchar code xingqi7[]={"SUN"};
/**************************************************************
*函数名 :delay
*函数功能 :延时函数
*函数参数 :需要延时的毫秒数:uint j
*函数返回值 :无
****************************************************************/
void delay(uint j){ //1ms延时子程序
uchar i=250;
for(;j>0;j--){
while(--i);
i=249;
while(--i);
i=250;
}
}
/**************************************************************
*函数名 :key_set
*函数功能 :按键设置
*函数参数 :无
*函数返回值 :无
****************************************************************/
void key_set(){
if(set==0){
delay(5);
while(!set);
count++; //计数,按了几次
lcd1602_write_command(0x0f);
if(flag==1){
done=1;
flag=0;
Ds1302Write(0x8e,0x00);
Ds1302Write(0x80,key_bcd(miao)|0x80);
Ds1302Write(0x8e,0x80);
}
}
}
/**************************************************************
*函数名 :key_up_down
*函数功能 :按键增加时间或者减少时间
*函数参数 :无
*函数返回值 :无
****************************************************************/
void key_up_down(){
if(up==0){
delay(5);
flag_up=1;
while(!up);
switch(count){
case 1: miao++;
if(miao>59) miao =0;break;
case 2: fen++;
if(fen>59) fen =0;break;
case 3: shi++;
if(shi>23) shi =0;break;
case 4: ri++;
if(ri>31) ri =1;break;
case 5: yue++;
if(yue>12) yue =1;break;
case 6: zhou++;
if(zhou>7) zhou =1;break;
case 7: nian++;
if(nian>99) miao =0;break;
}
}
if(down==0){
delay(5);
flag_down=1;
while(!down);
switch(count){
case 1: miao--;
if(miao==255) miao =59;break;
case 2: fen--;
if(fen==255) fen =59;break;
case 3: shi--;
if(shi==255) shi =23;break;
case 4: ri--;
if(ri<1) ri =31;break;
case 5: yue--;
if(yue<1) yue =12;break;
case 6: zhou--;
if(zhou<1) zhou =7;break;
case 7: nian--;
if(nian==255) miao =99;break;
}
}
}
/**************************************************************
*函数名 :key_bcd
*函数功能 :可以将十进制数转换成bcd类型数据
*函数参数 :十进制数:uchar key_decimal
*函数返回值 :返回bcd类型数据:uchar temp
****************************************************************/
uchar key_bcd(uchar key_decimal){
uchar temp;
temp=(((key_decimal/10)&0x0f)<<4 )|(key_decimal%10);
return temp;
}
/**************************************************************
*函数名 :key_process
*函数功能 :案件处理函数
*函数参数 :无
*函数返回值 :无
****************************************************************/
void key_process(){
key_set();
if(count!=0){
switch(count){
case 1: do{
lcd1602_write_command(0xc0+7);
key_up_down();
if(flag_up|flag_down){
flag_up=0;flag_down=0;
Ds1302Write(0x8e,0x00);
Ds1302Write(0x80,key_bcd(miao)|0x80);
Ds1302Write(0x8e,0x80);
write_time(0x40+6,miao);
lcd1602_write_command(0xc0+7);
}
}while(count==2);
break;
case 2: do{
lcd1602_write_command(0x80+0x40+4);
key_up_down();
if(flag_up|flag_down){
flag_up=0;flag_down=0;
Ds1302Write(0x8e,0x80);
Ds1302Write(0x82,key_bcd(fen));
Ds1302Write(0x8e,0x80);
write_time(0x40+3,fen);
lcd1602_write_command(0xc0+4);
}
}while(count==3);
break;
case 3: do{
lcd1602_write_command(0x80+0x40+1);
key_up_down();
if(flag_up|flag_down){
flag_up=0;flag_down=0;
Ds1302Write(0x8e,0x80);
Ds1302Write(0x84,key_bcd(shi));
Ds1302Write(0x8e,0x80);
write_time(0x40+0,shi);
lcd1602_write_command(0xc0+1);
}
}while(count==4);
break;
case 4: do{
lcd1602_write_command(0x80+7);
key_up_down();
if(flag_up|flag_down){
flag_up=0;flag_down=0;
Ds1302Write(0x8e,0x00);
Ds1302Write(0x86,key_bcd(ri));
Ds1302Write(0x8e,0x80);
write_time(6,ri);
lcd1602_write_command(0x80+7);
}
}while(count==5);
break;
case 5: do{
lcd1602_write_command(0x80+4);
key_up_down();
if(flag_up|flag_down){
flag_up=0;flag_down=0;
Ds1302Write(0x8e,0x00);
Ds1302Write(0x88,key_bcd(yue));
Ds1302Write(0x8e,0x80);
write_time(3,yue);
lcd1602_write_command(0x80+4);
}
}while(count==6);
break;
case 6: do{
lcd1602_write_command(0x80+15);
key_up_down();
if(flag_up|flag_down){
flag_up=0;flag_down=0;
Ds1302Write(0x8e,0x00);
Ds1302Write(0x8a,key_bcd(zhou));
Ds1302Write(0x8e,0x80);
write_time(13,zhou);
lcd1602_write_command(0x80+15);
}
}while(count==7);
break;
case 7: do{
lcd1602_write_command(0x80+1);
key_up_down();
if(flag_up|flag_down){
flag_up=0;flag_down=0;
Ds1302Write(0x8e,0x00);
Ds1302Write(0x8c,key_bcd(nian));
Ds1302Write(0x8e,0x80);
write_time(0,nian);
lcd1602_write_command(0x80+1);
}
}while(count==8);
break;
case 8:
lcd1602_write_command(0x0c);
flag=1;
done=0;
count =0;
Ds1302Write(0x8e,0x00);
Ds1302Write(0x80,key_bcd(miao)&0x7f);
Ds1302Write(0x8e,0x80);
break;
default:break;
}
}
}
/**************************** ds1302的驱动程序*********************************/
/*******************************************************************************
*函数名 :Ds1302Read
*函数功能 :读取ds1302中的数据
*函数参数 :所需写入的地址:ucahr addr
*函数返回值 :返回写入的数据:ucahr dat
*******************************************************************************/
uchar Ds1302Read(uchar addr){
uchar n,dat,dat1;
RST = 0;
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1;//然后将RST(CE)置高电平。
_nop_();
for(n=0; n<8; n++){ //开始传送八位地址命令
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;//DS1302下降沿时,放置数据
_nop_();
}
_nop_();
for(n=0; n<8; n++){ //读取8位数据
dat1 = DSIO;//从最低位开始接收
dat = (dat>>1) | (dat1<<7);
SCLK = 1;
_nop_();
SCLK = 0;//DS1302下降沿时,放置数据
_nop_();
}
RST = 0;
_nop_(); //以下为DS1302复位的稳定时间,必须的。
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}
/*******************************************************************************
*函数名 : Ds1302Write
*函数功能 : 写入设置的时间
*函数参数 : 地址:ucahr addr,数据:ucahr dat
*函数返回值 : 无
*******************************************************************************/
void Ds1302Write(uchar addr, uchar dat){
uchar n;
RST = 0;
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1; //然后将RST(CE)置高电平。
_nop_();
for (n=0; n<8; n++){ //开始传送八位地址命令
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++){ //写入8位数据
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;//传送数据结束
_nop_();
}
/*******************************************************************************
*函数名 :Ds1302Init
*函数功能 :ds1302的初始化
*函数参数 :无
*函数返回值 :无
*******************************************************************************/
void Ds1302Init(){
uchar n;
Ds1302Write(0x8E,0X00); //禁止写保护,就是关闭写保护功能
for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
{
Ds1302Write(write_add[n],time_data[n]);
}
Ds1302Write(0x8E,0x80); //打开写保护功能
}
/*******************************************************************************
*函数名 :bcd_decimal
*函数功能 :将BCD吗转成10进制数
*函数参数 :需要转化的bcd:ucahr bcd
*函数返回值 : 转化完成的十进制数:ucahr decimal
*******************************************************************************/
uchar bcd_decimal(uchar bcd){
uchar decimal;
decimal = bcd>>4;
decimal = decimal*10+(bcd&=0x0f);
return decimal;
}
/*******************************************************************************
*函数名 :write_time
*函数功能 :将时间显示在lcd上
*函数参数 :地址:ucahr add, 时间:uchar date
*函数返回值 :无
*******************************************************************************/
void write_time(uchar add,uchar date){
uchar shi,ge;
shi = date/10;
ge = date%10;
lcd1602_write_command(0x80+add);
lcd1602_write_data(0x30+shi);
lcd1602_write_data(0x30+ge);
}
/*******************************************************************************
*函数名 :write_week
*函数功能 :将星期显示在lcd上
*函数参数 :星期的表示值:0-6,分别对应周一到周日:uchar dat
*函数返回值 :无
*******************************************************************************/
void write_week(uchar dat){
switch(dat){
case 1: lcd1602_string(0x80+13,xingqi1); break;
case 2: lcd1602_string(0x80+13,xingqi2); break;
case 3: lcd1602_string(0x80+13,xingqi3); break;
case 4: lcd1602_string(0x80+13,xingqi4); break;
case 5: lcd1602_string(0x80+13,xingqi5); break;
case 6: lcd1602_string(0x80+13,xingqi6); break;
case 7: lcd1602_string(0x80+13,xingqi7); break;
}
}
/*******************************************************************************
*函数名 : xianshi_time
*函数功能 : 显示时间
*函数参数 : 无
*函数返回值 : 无
*******************************************************************************/
void xianshi_time(){
//Ds1302Readtime_data();
miao = bcd_decimal(Ds1302Read(0x81));
fen = bcd_decimal(Ds1302Read(0x83));
shi = bcd_decimal(Ds1302Read(0x85));
ri = bcd_decimal(Ds1302Read(0x87));
yue = bcd_decimal(Ds1302Read(0x89));
zhou = bcd_decimal(Ds1302Read(0x8b));
nian = bcd_decimal(Ds1302Read(0x8d));
write_time(0,nian);
lcd1602_write_command(0x80+2);
lcd1602_write_data(0x2d);
write_time(3,yue);
lcd1602_write_command(0x80+5);
lcd1602_write_data(0x2d);
write_time(6,ri);
write_week(zhou);
write_time(0x40+0,shi);
lcd1602_write_command(0xc0+2);
lcd1602_write_data(0x3a);
write_time(0x40+3,fen);
lcd1602_write_command(0xc0+5);
lcd1602_write_data(0x3a);
write_time(0x40+6,miao);
}
/**************************** lcd1602的驱动程序**********************/
/**************************************************************
*函数名 :lcd1602_write_command
*函数功能 :lcd1602的写命令函数
*函数参数 :所要设置的命令:uchar command
*函数返回值 :无
****************************************************************/
void lcd1602_write_command(uchar command) {
E=0;
RS=0;
RW=0;
out=command;
E=1;
_nop_( );
E=0;
delay(1);
}
/**************************************************************
*函数名 :lcd1602_write_data
*函数功能 :lcd1602的写数据函数
*函数参数 :要写入的数据:uchar dat
*函数返回值 :无
****************************************************************/
void lcd1602_write_data(uchar dat){
E=0;
RS=1;
RW=0;
out=dat;
E=1;
_nop_();
E=0;
delay(1);
}
/**************************************************************
*函数名 : lcd1602_initial
*函数功能 : lcd1602的初始化
*函数参数 : 无
*函数返回值 : 无
****************************************************************/
void lcd1602_initial(void){
lcd1602_write_command(0x38); //写入命令0x38:8位两行显示,5×7点阵字符
lcd1602_write_command(0x0C); //写入命令0x0C:开整体显示,光标关,无黑块
lcd1602_write_command(0x06); //写入命令0x06:光标右移
lcd1602_write_command(0x01); //写入命令0x01:清屏
delay(1);
}
/**************************************************************
*函数名 :lcd1602_string
*函数功能 :将字符串写入对应的地址上
*函数参数 :地址:uchar ad 字符串:uchar *s
*函数返回值 :无
****************************************************************/
void lcd1602_string(uchar ad,uchar *s){
lcd1602_write_command(ad);
while(*s>0)
{
lcd1602_write_data(*s++); //输出字符串,且指针增1
delay(100);
}
}
/*********************************主函数************************/
/**************************************************************
*函数名 : 主函数
*函数功能 : 驱动程序
*函数参数 : 无
*函数返回值: 无
****************************************************************/
void main(void){
uchar ch;
lcd1602_initial( ); //调用对LCD初始化函数
ch = Ds1302Read(0x81)>>7;
if(ch){
Ds1302Init();
}
while(1)
{
// lcd1602_string(0x80,table1); //显示的第1行数据
// lcd1602_string(0x80+0x40,table2); //显示第2行数据
if(done==1) {
key_process();
}
if(done==0){
xianshi_time();
key_set();
}
}
}
效果展示: