显示日期
显示时间
显示星期
消隐之后的效果
原理图
74ls138
ds1302
key
数码管
单片机
我这次采用的是STC89C52RC的单片机
代码如下:
main.c
#include
#include
#include
#include
sbit P10=P1^0;sbit P11=P1^1;sbit P12=P1^2;sbit P13=P1^3;
sbit P20=P2^0;sbit P21=P2^1;sbit P22=P2^2;sbit P23=P2^3;sbit P24=P2^4;sbit P25=P2^5;sbit P26=P2^6;sbit P27=P2^7;
code unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00};
code unsigned char write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //秒分时日月周年 最低位读写位
code unsigned char read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
unsigned char l_tmpdate[7]={30,43,21,15,12,2,14};//初始化ds1302的值
unsigned char Result[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};//读取ds1302的结果
unsigned char SetValue[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};//存储已经设置好的值,该值最后要写入ds1302
unsigned char LS138;
unsigned char SetKey;//0x00表示没有按设置键,0x01设置年,0x02设置月,0x03设置日,0x04设置小时,0x05设置分,0x06设置秒
unsigned char Flash,flashTime;
unsigned char HexYear;
void Delay250ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
i = 2;
j = 231;
k = 91;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//设置时间、日期、星期
void SetDateTime()
{
Set_RTC(write_rtc_address,l_tmpdate);
}
void SetTimer0()//用于控制138扫描数码管的时间
{
TL0 = 0x78; //设置定时初值
TH0 = 0xCC; //设置定时初值
TF0 = 0; //清除TF0标志
}
void tm1_isr() interrupt 3 using 1
{
flashTime++;
if(flashTime>50)
{
if(Flash==0x00)
{
Flash=0x01;
}
else
{
Flash=0x00;
}
flashTime=0x00;
}
TL1 = 0xB0; //设置定时初值
TH1 = 0x3C; //设置定时初值
TF1 = 0; //清除TF1标志
}
void tm0_isr() interrupt 1 using 1
{
SetTimer0();
//用于日期显示,因为显示时只用Result[0..2],所以需要将对应的年、月、日赋值到Result[0..2]
if((P21==0)||((SetKey>0x00)&&(SetKey<0x04)))
{
Result[2]=Result[6];
Result[1]=Result[4];
Result[0]=Result[3];
}
//显示星期时不需要数码管轮流显示。
if(P22==0)
{
P0=table[Result[5]&0x0f];
}
else
{
//数码管轮流显示
switch(LS138)
{
case 0:
P10=0;P11=0;P12=0;
P0=table[Result[2]/16];
break;
case 1:
P10=1;P11=0;P12=0;
P0=table[Result[2]&0x0f];
break;
case 2:
P10=0;P11=1;P12=0;
P0=0x40;
break;
case 3:
P10=1;P11=1;P12=0;
P0=table[Result[1]/16];
break;
case 4:
P10=0;P11=0;P12=1;
P0=table[Result[1]&0x0f];
break;
case 5:
P10=1;P11=0;P12=1;
P0=0x40;
break;
case 6:
P10=0;P11=1;P12=1;
P0=table[Result[0]/16];
break;
case 7:
P10=1;P11=1;P12=1;
P0=table[Result[0]&0x0f];
break;
}
}
//当按设置键时,对应的数码管进行闪烁。
switch(SetKey)
{
case 0x01:
case 0x04:
if((Flash==0x01)&&((LS138==0x01)||(LS138==0x00)))
{
P0=0x00;
}
break;
case 0x02:case 0x05:
if((Flash==0x01)&&((LS138==0x03)||(LS138==0x04)))
{
P0=0x00;
}
break;
case 0x03:case 0x06:
if((Flash==0x01)&&((LS138==0x06)||(LS138==0x07)))
{
P0=0x00;
}
break;
}
LS138++;
if(LS138>0x07)
{
LS138=0x00;
}
SetTimer0();
}
//定时器1,初始化,用于控制按设置键后数码管闪烁的频率
void Timer1Init(void) //50毫秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xB0; //设置定时初值
TH1 = 0x3C; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
}
void Timer0Init()
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
SetTimer0();
TR0 = 1; //定时器0开始计时
ET0 = 1;
}
main()
{
unsigned char i;
int Year,Month,Day,Week;
P13=0;SetKey=0x00;Flash=0x00;flashTime=0x00;
SetDateTime();
LS138=0x00;
Timer0Init();Timer1Init();
EA=1;
while(1)
{
if((LS138==0x00)&&(P13==0))
{
if(SetKey==0x00)
{
Read_RTC(read_rtc_address,Result);
for (i=0;i<0x07;i++)
{
SetValue[i]=Result[i];
}
}
}
//关闭数码管
if(P20==0)
{
Delay250ms();
P13=!P13;
}
//按设置键
if(P24==0)
{
SetKey++;
Delay250ms();
if(SetKey>0x06)SetKey=0x01;
TR1=1;
ET1=1;
}
if(SetKey!=0x00)
{
//按+键
if(P25==0)
{
Plus(SetValue, SetKey);
Delay250ms();
}
//按-键
if(P26==0)
{
Sub(SetValue, SetKey);
Delay250ms();
}
for(i=0;i<0x07;i++)
{
Result[i]=SetValue[i];
}
}
//保存结果
if(P27==0)
{
if(SetKey==0x00) continue;
Delay250ms();
SetKey=0x00;TR1=0;ET1=0;
for(i=0;i<7;i++)
{
l_tmpdate[i]=Hex2Bcd(SetValue[i]);
}
//*******************自动获得星期——开始***************************
//获得星期结果如下:
// 0 1 2 3 4 5 6
//星期一,星期二,星期三,星期四,星期五,星期六,星期天
Year=Hex2Bcd(SetValue[6])+2000;
Month=Hex2Bcd(SetValue[4]);
if((Month==1)||(Month==2))
{
Year--;
Month=12+Month;
}
Day=Hex2Bcd(SetValue[3]);
Month=2*Month+3*(Month+1)/5;
Year=Year+Year/4-Year/100+Year/400;
Week=(Day+Month+Year) % 7;
//*******************自动获得星期——开始***************************
l_tmpdate[5]=((unsigned char)(Week+1));//根据获得星期的结果,所以要+1;
SetDateTime();
}
}
}
ds1302.c
#include
#include
#include
#include
sbit SCK=P1^4; //时钟
sbit SDA=P3^4; //数据
sbit RST = P1^6;// DS1302复位
sbit P13=P1^3;
sbit LS138A=P1^0; sbit LS138B=P1^1;sbit LS138C=P1^2;
bit ReadRTC_Flag;//定义读DS1302标志
unsigned char l_tmpdisplay[8];
unsigned char tmpdate[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};//秒分时日月周年08-05-15 12:00:00
/******************************************************************/
/* 函数声明 */
/******************************************************************/
void Write_Ds1302_byte(unsigned char temp);
void Write_Ds1302( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302 ( unsigned char address );
/******************************************************************/
/* 写一个字节 */
/******************************************************************/
void Write_Ds1302_Byte(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++) //循环8次 写入数据
{
SCK=0;
SDA=temp&0x01; //每次传输低字节
temp>>=1; //右移一位
SCK=1;
}
}
/******************************************************************/
/* 写入DS1302 */
/******************************************************************/
void Write_Ds1302( unsigned char address,unsigned char dat )
{
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_(); //启动
Write_Ds1302_Byte(address); //发送地址
Write_Ds1302_Byte(dat); //发送数据
RST=0; //恢复
}
/******************************************************************/
/* 读出DS1302数据 */
/******************************************************************/
unsigned char Read_Ds1302 ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0;
_nop_();
_nop_();
SCK=0;
_nop_();
_nop_();
RST=1;
_nop_();
_nop_();
Write_Ds1302_Byte(address);
for (i=0;i<8;i++) //循环8次 读取数据
{
if(SDA)
temp|=0x80; //每次传输低字节
SCK=0;
temp>>=1; //右移一位
_nop_();
_nop_();
_nop_();
SCK=1;
}
RST=0;
_nop_(); //以下为DS1302复位的稳定时间
_nop_();
RST=0;
SCK=0;
_nop_();
_nop_();
_nop_();
_nop_();
SCK=1;
_nop_();
_nop_();
SDA=0;
_nop_();
_nop_();
SDA=1;
_nop_();
_nop_();
return (temp); //返回
}
/******************************************************************/
/* 读时钟数据 */
/******************************************************************/
extern void Read_RTC(unsigned char *address,unsigned char *Rst) //读取 日历
{
unsigned char i;
for(i=0;i<7;i++) //分7次读取 秒分时日月周年
{
*Rst=Read_Ds1302(*address);
address++;Rst++;
}
}
/******************************************************************/
/* 设定时钟数据 */
/******************************************************************/
extern void Set_RTC(unsigned char *address,unsigned char *value) //设定 日历
{
unsigned char i;
for(i=0;i<7;i++)
{
tmpdate[i]=BCD2Hex(*value);
value++;
}
Write_Ds1302(0x8E,0X00);
for(i=0;i<7;i++) //7次写入 秒分时日月周年
{
Write_Ds1302(*address,tmpdate[i]);
address++;
}
Write_Ds1302(0x8E,0x80);
}
function.c
#include
#include
#include
extern unsigned char Hex2Bcd(unsigned char Hex)
{
unsigned char L,H,Result;
H=(Hex&0xf0)>>0x04;
L=Hex&0x0f;
Result=H*0x0a+L;
return Result;
}
extern unsigned char BCD2Hex(unsigned char bcd)
{
unsigned char Result,tmp;
tmp=bcd/10;
Result=bcd%10;
tmp=tmp*16;
Result=Result+tmp;
return Result;
}
extern void Plus(unsigned char *Val,unsigned char SetKey)
{
int i=0;
unsigned char Tmp[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};
for(i=0;i<7;i++)
{
Tmp[i]=Hex2Bcd(Val[i]);
}
switch(SetKey)
{
case 0x01:
Tmp[6]++;if(Tmp[6]>0x19)Tmp[6]=0x0e;
break;
case 0x02:
Tmp[4]++;if(Tmp[4]>0x0c)Tmp[4]=0x01;
break;
case 0x03:
Tmp[3]++;if(Tmp[3]>0x1f)Tmp[3]=0x01;
switch(Tmp[4])
{
case 0x02:
if((Tmp[6]%0x04)==0x00)
{
if(Tmp[3]>0x1d)
{
Tmp[3]=0x01;
}
}
else
{
if(Tmp[3]>0x1c)
{
Tmp[3]=0x01;
}
}
break;
case 0x04:
case 0x06:
case 0x09:
case 0x0b:
if(Tmp[3]>0x1E)Tmp[3]=0x01;
break;
}
break;
case 0x04:
Tmp[2]++;if(Tmp[2]>0x17)Tmp[2]=0x00;
break;
case 0x05:
Tmp[1]++;if(Tmp[1]>0x3b)Tmp[1]=0x00;
break;
case 0x06:
Tmp[0]++;if(Tmp[0]>0x3b)Tmp[0]=0x00;
break;
}
for(i=0;i<7;i++)
{
Val[i]=BCD2Hex(Tmp[i]);
}
}
extern void Sub(unsigned char *Val,unsigned char SetKey)
{
int i;
unsigned char Tmp[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};
for(i=0;i<7;i++)
{
Tmp[i]=Hex2Bcd(Val[i]);
}
switch(SetKey)
{
case 0x01:
Tmp[6]--;if(Tmp[6]<0x0e)Tmp[6]=0x19;
break;
case 0x02:
Tmp[4]--;if(Tmp[4]<0x01)Tmp[4]=0x0c;
break;
case 0x03:
Tmp[3]--;
switch(Tmp[4])
{
case 0x02:
if(Tmp[3]==0x01)
{
if((Tmp[6]%0x04)==0x00)
{
Tmp[3]=0x1d;
}
else
{
Tmp[3]=0x1c;
}
}
break;
case 0x04:
case 0x06:
case 0x09:
case 0x0b:
if(Tmp[3]<0x01)Tmp[3]=0x1e;
break;
case 0x01:
case 0x03:
case 0x07:
case 0x08:
case 0x0a:
case 0x0c:
if(Tmp[3]<0x01)Tmp[3]=0x1f;
break;
}
break;
case 0x04:
Tmp[2]--;if(Tmp[2]>0x17)Tmp[2]=0x00;
break;
case 0x05:
Tmp[1]--;if(Tmp[0]>0x3b)Tmp[0]=0x00;
break;
case 0x06:
Tmp[0]--;if(Tmp[0]>0x3b)Tmp[0]=0x00;
break;
}
for(i=0;i<7;i++)
{
Val[i]=BCD2Hex(Tmp[i]);
}
}