|
楼主 |
发表于 2014-1-6 10:39:46
|
显示全部楼层
本帖最后由 其实不想走 于 2014-1-6 10:42 编辑
DS1302_clock.rar
(1.1 KB, 下载次数: 508)
DS1302_clock.rar
(3 KB, 下载次数: 540)
/
**********************************************************
数码管显示DS1302时钟程序 (晶振频率=12.000MHz)
2014年1月5日
**********************************************************/
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit A0=P3^5; //定义74HC138的地址线。
sbit A1=P3^7; //同上。
sbit key1=P3^2; //定义键盘1.
sbit key2=P3^3; //定义键盘2.
sbit SCLK=P3^1; //定义1302时钟线接口。
sbit DAT=P3^0; //定义1302数据线接口。
sbit CE=P3^4; //定义1302使能口。
sfr P0M0 = 0x93;
sfr P0M1 = 0x94;
sfr P1M0 = 0x91; //定义STC12系列单片机特殊功能寄存器地址(控制P1口工作模式)
sfr P1M1 = 0x92; //同上。
sfr P2M0 = 0x95;
sfr P2M1 = 0x96;
sfr P3M0 = 0xb1;
sfr P3M1 = 0xb2;
uchar num,num1,x;
uchar code table[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar code table1[10] ={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; //带点数字
void DS1302WriteByte (uchar dat); //此函数向DS1302写入8bit数据
uchar DS1302ReadByte(); //此函数读取DS1302输出的8bit数据
void DS1302Write(uchar cmd,uchar dat); //此函数向cmd相应地址中写入一个字节的数据
uchar DS1302Read(uchar cmd); //此函数从CMD相应地址中读取一个字节的数据
void Init_DS1302(); //DS1302初始化函数。
void display(uchar n,uchar m); //LED显示函数 (正常走时状态的
void display1(uchar n,uchar m); //LED显示函数 (小时位闪烁状态)
void display2(uchar n,uchar m); //LED显示函数 (分钟位闪烁状态)
void Display_time(); //时间显示函数
void Init_check(); //初始化判断函数
uchar BCDtoDEC(uchar bcd);
uchar DECtoBCD(uchar dec);
void Delay_us (uchar i) //执行次函数延时( i+1) us ,注:此函数i最小取值为1 ,且不能改变为其它数据类型,所以此函数最大延时为256us。 (相当精确)
{
do
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
while(--i);
}
void Delay_ms(unsigned int i) //执行此函数延时 i ms。 (比较精确)
{
unsigned char j,k;
do
{
j = 44;
do
{
k = 54;
do
{
_nop_();
}
while(--k);
}
while(--j);
}
while(--i);
}
/*****************************************
主函数
*****************************************/
void main()
{
P1M0 = 0x00; // 设置P1口为
P1M1 = 0xff; // 推挽输出方式 (最大20MA输出能力)。
P3M0=0x00; // 设置P3口为
P3M1=0xff; // 挽输出方式 (最大20MA输出能力)。
TMOD=0x01; //设置定时器T0和T1工作方式为16为定时器。
TL0=(65536-10000)%256;
TH0=(65536-10000)/256;
EA=1; //开总中断。
ET0=1; //打开T0中断
TR0=1; //定时器0的运行控制位,置1启动T0
EX0=1; //打开外部中断0
// EX1=1; //打开外部中断1
IT0=1; //外部中断0触发方式选择,置1为下降沿触发
// IT1=1; //外部中断1触发方式选择,置1为下降沿触发
Init_check();
while(1)
{
Display_time();
}
}
void DS1302WriteByte (uchar dat) //此函数向DS1302写入8bit数据
{
uchar i;
SCLK=0; //初始时钟线设置为0.
Delay_us(2);
for(i=0;i<8;i++) //开始传输8个字节的数据。
{
DAT=dat&0x01; //取最低位,DS1302的数据和地址都是从最低位开始传输的。
Delay_us(2);
SCLK=1; //时钟线拉高,制造上升沿,DAT的数据被传输。
Delay_us(2);
SCLK=0; //时钟线拉低,为下一个上升沿做准备。
dat>>=1; //数据右移一位,准备传输下一位数据。
}
}
uchar DS1302ReadByte() //此函数读取DS1302输出的8bit数据
{
uchar i,dat;
Delay_us(2);
for(i=0;i<8;i++)
{
dat>>=1; //要返回的数据右移一位(DS1302最先输出的是最低位数据)
if(DAT==1)
dat|=0x80; //按位或,若数据线为高,把返回的数据最高位置1,而不改变其它位。
SCLK=1; //拉高时钟线,为下降沿做准备。
Delay_us(2);
SCLK=0; //制造下降沿,DS1302的数据在下降沿输出。
Delay_us(2);
}
return dat;
}
/* ******************************
此函数从CMD相应地址中读取一个字节的数据
cmd为要写入的地址
每次操作都是先写地址,后读数据
********************************/
uchar DS1302Read(uchar cmd)
{
uchar dat;
CE=0;
SCLK=0;
CE=1; //CE设置为1,开始传输
DS1302WriteByte (cmd); //写入要读取的时间/日历的地址
dat=DS1302ReadByte(); //读取要得到的时间日期
SCLK=1;
CE=0; //读取结束,CE设置为0,结束数据的传输
return dat;
}
/*************************************
此函数向cmd相应地址中写入一个字节的数据
cmd 是要写入的地址
dat是要写入的数据
先写地址,后写数据
************************************/
void DS1302Write(uchar cmd,uchar dat)
{
CE=0;
SCLK=0;
CE=1; //CE设置为1,开始传输
DS1302WriteByte (cmd); //写入要修改的时间/日历的地址
DS1302WriteByte (dat); // 写入要修改的时间日期
SCLK=1;
CE=0; //读取结束,CE设置为0,结束数据的传输
}
/*****************************************
DS1302初始化程序
只需要调用一次,写入一个初始值即可
这里初始值的设置如下:
2014年1月4
22:30:00
****************************************/
void Init_DS1302()
{
DS1302Write(0x8e,0x00); //写保护关
DS1302Write(0x8c,0x14); //设置年为14年
DS1302Write(0x88,0x01); // 设置月为1月
DS1302Write(0x86,0x04); // 设置日为4
DS1302Write(0x84,0x00); // 设置时为00
DS1302Write(0x82,0x15); // 设置分为15
DS1302Write(0x80,0x00); // 设置秒为0
DS1302Write(0x90,0xa6); //涓流充电寄存器,这里设置为1个二极管4K电阻模式(如不初始化次寄存器,加电时涓流充电是禁止的)
DS1302Write(0xc0,0xf0); //初始化一次标示***
DS1302Write(0x8e,0x80); //写保护开
}
/************************************
LED显示函数 (正常走时状态的)
把从DS1302中读取的时和分数据显示到LED数码管上
m 为时数据,n 为分数据
************************************/
void display(uchar n,uchar m)
{
uchar shi,ge,ss,gg;
shi=n/10;
ge=n%10;
ss=m/10;
gg=m%10;
if(num<=50)
{
A0=0;
A1=0;
P1=table[ss];
Delay_ms(5);
A0=1;
A1=0;
P1=table1[gg];
Delay_ms(5);
A0=0;
A1=1;
P1=table[shi];
Delay_ms(5);
A0=1;
A1=1;
P1=table[ge];
Delay_ms(5);
}
else
{
A0=0;
A1=0;
P1=table[ss];
Delay_ms(5);
A0=1;
A1=0;
P1=table[gg];
Delay_ms(5);
A0=0;
A1=1;
P1=table[shi];
Delay_ms(5);
A0=1;
A1=1;
P1=table[ge];
Delay_ms(5);
}
}
/************************************
LED显示函数 (小时位闪烁状态)
把从DS1302中读取的时和分数据显示到LED数码管上
m 为时数据,n 为分数据
************************************/
void display1(uchar n,uchar m)
{
uchar shi,ge,ss,gg;
shi=n/10;
ge=n%10;
ss=m/10;
gg=m%10;
if(num1<=20)
{
A0=0;
A1=0;
P1=table[ss];
Delay_ms(5);
A0=1;
A1=0;
P1=table1[gg];
Delay_ms(5);
A0=0;
A1=1;
P1=table[shi];
Delay_ms(5);
A0=1;
A1=1;
P1=table[ge];
Delay_ms(5);
}
else
{
A0=0;
A1=1;
P1=table[shi];
Delay_ms(5);
A0=1;
A1=1;
P1=table[ge];
Delay_ms(5);
}
}
/************************************
LED显示函数 (分钟位闪烁状态)
把从DS1302中读取的时和分数据显示到LED数码管上
m 为时数据,n 为分数据
************************************/
void display2(uchar n,uchar m)
{
uchar shi,ge,ss,gg;
shi=n/10;
ge=n%10;
ss=m/10;
gg=m%10;
if(num1<=20)
{
A0=0;
A1=0;
P1=table[ss];
Delay_ms(5);
A0=1;
A1=0;
P1=table1[gg];
Delay_ms(5);
A0=0;
A1=1;
P1=table[shi];
Delay_ms(5);
A0=1;
A1=1;
P1=table[ge];
Delay_ms(5);
}
else
{
A0=0;
A1=0;
P1=table[ss];
Delay_ms(5);
A0=1;
A1=0;
P1=table1[gg];
Delay_ms(5);
}
}
/*****************************************
时间显示函数
此函数完成按键扫描和判断,数据修改,
并把最终数据通过LED显示函数显示到
LED数码管上
*****************************************/
void Display_time()
{
uchar i,j;
i=BCDtoDEC(DS1302Read(0x85));
j=BCDtoDEC(DS1302Read(0x83));
if(x==0) display(j,i);
else if(x==1)
{
if(key2==0)
{
i+=1;
if(i>=24) i=0;
i=DECtoBCD(i);
DS1302Write(0x8e,0x00); //写保护关
DS1302Write(0x84,i); //修改的时数据,写入DS1302
DS1302Write(0x8e,0x80); //写保护开
while(!key2);
}
display1(j,i);
}
else
{
if(key2==0)
{
j+=1;
if(j>=60) j=0;
j=DECtoBCD(j);
DS1302Write(0x8e,0x00); //写保护关
DS1302Write(0x82,j); // 修改的分数据,写入DS1302
DS1302Write(0x80,0x00); // 设置秒为0
DS1302Write(0x8e,0x80); //写保护开
while(!key2);
}
display2(j,i);
}
}
/*************************************
此程序将从DS1302中读取的BCD码数据
转换成十进制DEC码
*************************************/
uchar BCDtoDEC(uchar bcd)
{
uchar dec;
dec=bcd&0x0f;
bcd=bcd&0x70;
bcd>>=4;
dec=dec+bcd*10;
return dec;
}
/***********************************
初始化判断函数
执行此函数可判断DS1302目前状态
是否需要进行初始化,如果需要,
则执行初始化,如果不需要,
跳过初始化程序继续往下执行
***********************************/
void Init_check()
{
uchar n;
n=DS1302Read(0xc1);
if(n!=0xf0)
Init_DS1302();
}
/***********************************
此程序将十进制DEC码转换成
DS1302可以识别的BCD码
***********************************/
uchar DECtoBCD(uchar dec)
{
uchar bcd;
bcd=dec%10;
dec=dec/10;
dec<<=4;
bcd=bcd+dec;
return bcd;
}
void T0_time() interrupt 1
{
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
num++;
num1++;
if(num==100)num=0;
if(num1==40)num1=0;
}
void INT0_key1() interrupt 0
{
x++;
if(x>=3)x=0;
}
|
|