📄 ds1302.c
字号:
/***************************************************
Function:DS1302时钟读写,在LCD1602上显示并可以调整
Author:Tecman
E-mail:tecman@126.com
Great Date:2008.07.15
****************************************************/
#include <REG51.H>
#include <string.h>
#include<intrins.h>
#include <PIO.H>
#define DPORT P0
sbit RS=P2^0;
sbit RW=P2^1;
sbit E =P2^2;
//LCD1602接口定义
sbit CLK=P1^0;
sbit IO =P1^1;
sbit RST=P1^2; //DS1302时间显示定义部分
sbit key1=P1^4;
sbit key2=P1^5;
sbit key3=P1^6;
sbit key4=P1^7; //按键定义
unsigned char ID,timecount;
bdata unsigned char flag1; //标志位集合1
sbit sec = flag1^0;
sbit min = flag1^1;
sbit hour = flag1^2;
sbit year = flag1^3;
sbit mon = flag1^4;
sbit week = flag1^5;
sbit day = flag1^6;
sbit flag = flag1^7; //flag是闪烁标志
unsigned char code date[]={"Week:"};
void DISP_L1(void); //显示屏幕第一行
void DISP_L2(void); //显示屏幕第二行
void setkey(void); //时间调整
void Delay(unsigned int n ); //延时,毫秒数由n决定
void Set(unsigned char sel,bit Ads); //根据选择调整相应项目
void write1302(unsigned char Addr, unsigned char Data); // 向DS1302写入一个字节
unsigned char read1302(unsigned char byte); // 从DS1302读出一个字节
void Write_Data(unsigned char Data); //写LCD数据
void Write_Instruction(unsigned char Cmd); //写LCD指令
void busy(void); //忙检查
void LCD_Init(void); //LCD初始化
void LCD_DISP(unsigned char X, //水平坐标0-15
unsigned char Y, //垂直坐标0-1
unsigned char Data); //显示内容
void DISP_STR(unsigned char X,
unsigned char Y,
unsigned char code *P); //显示字符串
void main(void)
{
Delay(40000); //启动等待,等LCD讲入工作状态
LCD_Init(); //LCD初始化
TMOD=0x01;
TH0=0x3C;
TL0=0xAF; //50ms计时
EA=1;
TR0=1;
ET0=1;
write1302(0x90,0xA5); //打开充电二级管 一个二级管串联一个2K电阻
write1302(0x8E,0x80); //写保护,禁止写操作
while(1)
{
if (key3==0) // 设置和选择项目键
{
Delay(10000);
if(key3==0)
{
ID++;
if(ID>7) ID=0;
}
while(key3==0);
}
switch(ID)
{
case 0:
sec=0;
DISP_L1();
DISP_L2();
break;
case 1: //年
year=1;
DISP_L1();
DISP_L2();
setkey();
break;
case 2: //月
year=0;
mon=1;
DISP_L1();
DISP_L2();
setkey();
break;
case 3: //日
mon=0;
day=1;
DISP_L1();
DISP_L2();
setkey();
break;
case 4: //星期
day=0;
week=1;
DISP_L1();
DISP_L2();
setkey();
break;
case 5: //小时
week=0;
hour=1;
DISP_L1();
DISP_L2();
setkey();
break;
case 6: //分钟
hour=0;
min=1;
DISP_L1();
DISP_L2();
setkey();
break;
case 7: //秒
min=0;
sec=1;
DISP_L1();
DISP_L2();
setkey();
break;
}
}
}
//------------定时中断-----------
void timer(void) interrupt 1
{
TH0=0x3C;
TL0=0xAF;
timecount++;
if(timecount>9)
{
timecount=0;
flag=~flag;
}
}
//------------调整--------------
void setkey()
{
if (key2==0) //增加
{
Delay(10000);
if(key2==0) Set(ID,0);
if(ID!=7) while(key2==0);
}
if (key1==0) //减少
{
Delay(10000);
if(key1==0) Set(ID,1);
if(ID!=7) while(key1==0);
}
}
//-------根据选择调整相应项目并写入DS1302-------
void Set(unsigned char sel,bit Ads)
{
signed char Addr,temp;
signed char Up,Down;
if(sel==7)
{
Addr=0x80;
Up=0;
Down=0;
} //秒
if(sel==6)
{
Addr=0x82;
Up=59;
Down=0;
} //分钟
if(sel==5)
{
Addr=0x84;
Up=23;
Down=0;
} //小时
if(sel==4)
{
Addr=0x8a;
Up=7;
Down=1;
} //星期
if(sel==3)
{
Addr=0x86;
Up=31;
Down=1;} //日
if(sel==2)
{
Addr=0x88;
Up=12;
Down=1;
} //月
if(sel==1)
{
Addr=0x8c;
Up=99;
Down=0;
} //年
temp=read1302(Addr+1)/16*10+read1302(Addr+1)%16;
if (!Ads) temp++;
else temp--;
if(temp>Up) temp=Down;
if(temp<Down) temp=Up;
write1302(0x8e,0x00); //允许写操作
write1302(Addr,temp/10*16+temp%10);
write1302(0x8e,0x80); //写保护,禁止写操作
}
//-------------屏幕显示第一行 时间--------------
void DISP_L1(void)
{
LCD_DISP(6,0,0x3A);
LCD_DISP(9,0,0x3A); //显示冒号
if(sec==1) //秒闪烁标志位
{
if(flag==1)
{
LCD_DISP(10,0,read1302(0x81)/16+0x30); //显示秒
LCD_DISP(11,0,read1302(0x81)%16+0x30);
}
else
{
LCD_DISP(10,0,0x20);
LCD_DISP(11,0,0x20);
}
}
else
{
LCD_DISP(10,0,read1302(0x81)/16+0x30);
LCD_DISP(11,0,read1302(0x81)%16+0x30);
}
if(min==1) //分钟闪烁标志位
{
if(flag==1)
{
LCD_DISP(7,0,read1302(0x83)/16+0x30); //显示分钟
LCD_DISP(8,0,read1302(0x83)%16+0x30);
}
else
{
LCD_DISP(7,0,0x20);
LCD_DISP(8,0,0x20);
}
}
else
{
LCD_DISP(7,0,read1302(0x83)/16+0x30);
LCD_DISP(8,0,read1302(0x83)%16+0x30);
}
if(hour==1) //小时闪烁标志位
{
if(flag==1)
{
LCD_DISP(4,0,read1302(0x85)/16+0x30); //显示小时
LCD_DISP(5,0,read1302(0x85)%16+0x30);
}
else
{
LCD_DISP(4,0,0x20);
LCD_DISP(5,0,0x20);
}
}
else
{
LCD_DISP(4,0,read1302(0x85)/16+0x30);
LCD_DISP(5,0,read1302(0x85)%16+0x30);
}
}
//----------屏幕显示第二行 日期和星----------
void DISP_L2(void)
{
LCD_DISP(3,1,0x2F); //显示固定字符
LCD_DISP(6,1,0x2F);
DISP_STR(10,1,date);
if(year==1) //年闪烁标志位
{
if(flag==1)
{
LCD_DISP(1,1,read1302(0x8d)/16+0x30); //显示年
LCD_DISP(2,1,read1302(0x8d)%16+0x30);
}
else
{
LCD_DISP(1,1,0x20); //显示年
LCD_DISP(2,1,0x20);
}
}
else
{
LCD_DISP(1,1,read1302(0x8d)/16+0x30);
LCD_DISP(2,1,read1302(0x8d)%16+0x30);
}
if(mon==1) //月闪烁标志位
{
if(flag==1)
{
LCD_DISP(4,1,read1302(0x89)/16+0x30); //显示月
LCD_DISP(5,1,read1302(0x89)%16+0x30);
}
else
{
LCD_DISP(4,1,0x20);
LCD_DISP(5,1,0x20);
}
}
else
{
LCD_DISP(4,1,read1302(0x89)/16+0x30);
LCD_DISP(5,1,read1302(0x89)%16+0x30);
}
if(day==1) //日闪烁标志位
{
if(flag==1)
{
LCD_DISP(7,1,read1302(0x87)/16+0x30); //显示日
LCD_DISP(8,1,read1302(0x87)%16+0x30);
}
else
{
LCD_DISP(7,1,0x20);
LCD_DISP(8,1,0x20);
}
}
else
{
LCD_DISP(7,1,read1302(0x87)/16+0x30);
LCD_DISP(8,1,read1302(0x87)%16+0x30);
}
if(week==1) //星期闪烁标志位
{
if(flag==1)
{
LCD_DISP(15,1,read1302(0x8b)%16+0x30); //显示星期
}
else
{
LCD_DISP(15,1,0x20);
}
}
else
{
LCD_DISP(15,1,read1302(0x8b)%16+0x30);
}
}
//===============以下是LCD1602驱动================
//--------------写数据---------------
void Write_Data(unsigned char Dat)
{
busy(); //检测忙
RS=1;
RW=0;
DPORT=Dat; //将待写数据送到数据端口
E = 0; //若晶振速度太高可以在这后加小的延时
_nop_();
E = 1;
}
//---------------写指令--------------
void Write_Instruction(unsigned char Cmd)
{
busy();
RS=0;
RW=0;
DPORT=Cmd;
E=1;
_nop_();
E=0;
}
//-----------忙检查------------
void busy(void)
{
DPORT = 0xFF;
RS = 0;
RW = 1;
E = 0;
_nop_();
E = 1;
while (DPORT&0x80); //检测忙信号
}
//-----------LCD初始化----------
void LCD_Init(void)
{
Delay(500);
Write_Instruction(0x38); //显示模式设置,开始要求每次检测忙信号
Write_Instruction(0x08); //关闭显示
Write_Instruction(0x01); //显示清屏
Write_Instruction(0x06); // 显示光标移动设置
Write_Instruction(0x0C); // 显示开及光标设置
}
//----------在指定位置显示一个字符----------
void LCD_DISP(unsigned char X,
unsigned char Y,
unsigned char Data)
{
unsigned char temp;
X&=0x0F; //x位置范围是0~15
Y&=0x01; //y位置范围是0~1
if(Y==0) temp=X; //显示第一行
else
temp=X+0x40;
temp|=0x80;
Write_Instruction(temp);
Write_Data(Data);
}
//-----------在指定位置显示一串字符---------
void DISP_STR(unsigned char X,
unsigned char Y,
unsigned char code *P)
{
unsigned char Length,j;
Length = strlen(P); //计算字符长度
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (X <= 0xF) //X坐标应小于0xF
{
for(j=0;j<Length;j++)
{
LCD_DISP(X,Y,P[j]); //显示单个字符
X++;
}
}
}
//=============以下是DS1302读写程序===========
//-------------实时时钟发送1字节-----------
void sentbyte(unsigned char byte)
{
unsigned char bitcnt=8;
while(bitcnt!=0)
{
CY=byte&0x01;
byte=ACC;
IO=CY;
CLK = 1;
CLK = 0;
bitcnt--;
}
}
//-------------实时时钟接收1字节--------------
unsigned char rcvbyte(void)
{
unsigned char bitcnt=8;
while(bitcnt!=0)
{
CY=IO;
CY=ACC&0x01;
CLK = 1;
CLK = 0;
bitcnt--;
}
return(ACC);
}
//---------------往DS1302写入数据-------------------
void write1302(unsigned char Addr, unsigned char Data)
{
RST = 0;
CLK = 0;
RST = 1;
sentbyte(Addr); // 地址,命令
sentbyte(Data); //写1Byte数据
CLK = 1;
RST = 0;
}
//---------------读取DS1302某地址的数据---------------
unsigned char read1302(unsigned char Addr)
{
unsigned char temp;
RST = 0;
CLK = 0;
RST = 1;
sentbyte(Addr); // 地址,命令
temp = rcvbyte(); //读1Byte数据
CLK = 1;
RST = 0;
return(temp);
}
//-------------延时----------------
void Delay(unsigned int n)
{
while(n--); //延时时间 ≈ (n*9+17)*12/fo
} //n ≈ (t*fo/12-17)/9
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -