×

基于DS1307的简易时钟显示程序分享

发布时间:2020-06-05 发布时间:
|

目前家用的数字电子钟,多数只能显示小时、分钟等信息,功能单一,而且大都采用LED数码管作为显示器件,功耗大,不能令消费者满意。

DS1307简介

AM/PM 标志位决定时钟工作于24小时或12小时模式,芯片有一个内置的电源感应电路,具有掉电检测和电池切换功能。

是一款低功耗,具有56字节非失性RAM的全BCD码时钟日历实时时钟芯片,地址和数据通过两线双向的串行总线的传输,芯片可以提供秒,分,小时等信息,每一个月的天数能自动调整。并且有闰年补偿功能

特点:

可对秒,时,分,每月的天数,月份,每周的天数进行计数,并具有闰年补偿功能。计年上限2100。

56字节非失性的RAM

两线串行接口

可编程方波输出

自动掉电检测和切换电路

在电池备份模式下,功耗小于500nA

工业级的工作温度: -40 到80

8脚DIP和SOIC封装

下面分享一下基于DS1307的简易时钟显示程序给大家:

* Coder:NUIST_XKFYT

* E-mail:weilun_fong@nuist.edu.cn(Welcome to get help info about this program)

* Date:2016-7-17

*

* Device:STC89C54RD,DS1307Z+

* Function:简易时钟显示

* Note:

* 1.DS1307四位固定地址位为1101,三位可编程地址位为000

*/

#include 《STC89C5xRC.h》 /* 可更换为《reg52.h》或《AT89x52.h》 */

#include 《intrins.h》

//#include 《time.h》 /* Keil v4中无法调用该标准库函数 */

#define uchar unsigned char

#define uint unsigned int

/* DS1307操作指令 */

#define DS1307_WRITE 0xD0

#define DS1307_READ 0xD1

#define DS1307_DISABLE 0x80

#define DS1307_ENABLE 0x7F

#define DS1307_12HOUR_MODE 0x20

#define DS1307_24HOUR_MODE 0xDF

/* DS1307内部寄存器地址 */

#define ADDR_SEC 0x00

#define ADDR_MIN 0x01

#define ADDR_HOUR 0x02

#define ADDR_DAY 0x03

#define ADDR_DATE 0x04

#define ADDR_MONTH 0x05

#define ADDR_YEAR 0x06

#define ADDR_COR 0x07

/* 模块自带AT24C02》》预留接口 */

//#define AT24C02_WRITE 0xA0

//#define AT24C02_READ 0xA1

sbit I2C_SCL = P1^0;

sbit I2C_SDA = P1^1;

uchar min = 0;

uchar sec = 0;

uchar code tab[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};

/* 重新自定义《time.h》中的tm结构体 */

struct tm

{

uchar tm_sec; /* 秒 – 取值区间为[0,59] */

uchar tm_min; /* 分 - 取值区间为[0,59] */

uchar tm_hour; /* 时 - 取值区间为[0,23] */

uchar tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */

uchar tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[1,12] */

uchar tm_year; /* 年份 */

uchar tm_wday; /* 星期 – 取值区间为[1,7] */

};

/* delay 5us */

void delay_5us(void)

{

_nop_();

}

/* delay par*1ms */

void delay_ms(uint par)

{

uchar cnt = 0;

while(par--)

for(cnt = 120;cnt 》 0;cnt--);

}

void I2C_Start(void)

{

I2C_SDA = 1;

I2C_SCL = 1;

delay_5us(); /* 实际延时4.7us即可 */

I2C_SDA = 0; /* SCL为高电平时,SDA为下降沿表示起始信号 */

delay_5us();

}

void I2C_Stop(void)

{

I2C_SDA = 0;

I2C_SCL = 1;

delay_5us();

I2C_SDA = 1; /* SCL为高电平时,SDA为上升沿表示结束信号 */

delay_5us();

}

void I2C_Ack(void)

{

uchar cnt = 0;

I2C_SCL = 0; /* 在SCL为高电平期间等待应答 */

delay_5us();

while((I2C_SDA == 1)&&(cnt 《 250)) /* 若为应答0即退出,从机向主机发送应答信号 */

cnt++; /* 等待一段时间 */

I2C_SCL = 0;

delay_5us();

}

void I2C_noAck(void)

{

I2C_SCL = 1; /* 在scl为高电平期间,由主机向从机发送一个1,非应答信号 */

delay_5us();

I2C_SDA = 1;

I2C_SCL = 0;

delay_5us();

}

void I2C_sendByte(uchar dat)

{

uchar cnt = 0;

uchar dat_buf = 0;

dat_buf = dat;

for(cnt = 0;cnt 《 8;cnt++)

{

dat_b

uf = dat_buf 《《 1;/* 将数据的最高位移入到PSW中的CY位中 */

I2C_SCL = 0;

delay_5us();

I2C_SDA = CY; /* 将CY里的数据发送到sda数据线上 */

delay_5us();

I2C_SCL = 1; /* 在scl为高电平时,不允许sda上的数据变化,使数据稳定 */

delay_5us();

I2C_SCL = 0; /* 允许sda数据线的数据变化,等待下一个数据的传输 */

delay_5us();

}

/* wait ack */

I2C_SCL = 0; /* 允许SDA变化 */

delay_5us();

I2C_SCL = 1;

delay_5us(); /* SDA拉高等待应答,当SDA = 0时,表示从机的应答 */

}

uchar I2C_receiveByte(void)

{

bit bit_buf = 0;

uchar cnt = 0;

uchar dat = 0;

I2C_SCL = 0; /* 读之前允许SDA变化 */

delay_5us();

for(cnt = 0;cnt 《 8;cnt++)

{

I2C_SCL = 1; /* 拉高SCL禁止SDA变化 */

delay_5us();

bit_buf = I2C_SDA; /* 读出SDA上的数据 */

dat = (dat 《《 1)|bit_buf;

I2C_SCL = 0; /* 允许SDA变化等待下次数据的到来 */

delay_5us();

}

return dat;

}

void I2C_Init(void)

{

I2C_SDA = 1;

delay_5us();

I2C_SCL = 1;

delay_5us();

}

void DS1307_writeByte(uchar addr,uchar dat) /* 读取单字节 */

{

I2C_Start();

I2C_sendByte(DS1307_WRITE);

I2C_Ack();

I2C_sendByte(addr); /* addr为目标地址 */

I2C_Ack();

I2C_sendByte(dat);

I2C_Ack();

I2C_Stop();

}

void DS1307_writeData(uchar addr_st,uchar dat[],uint num) /* num为要传入的字节数 */

{

uchar cnt = 0;

I2C_Start();

I2C_sendByte(DS1307_WRITE);

I2C_Ack();

I2C_sendByte(addr_st); /* addr_st为起始地址 */

I2C_Ack();

for(cnt = 0;cnt 《 num;cnt++)

{

I2C_sendByte(dat[cnt]);

I2C_Ack();

}

I2C_Stop();

}

uchar DS1307_readByte(uchar addr)

{

uchar dat_buf = 0;

I2C_Start();

I2C_sendByte(DS1307_WRITE);

I2C_Ack();

I2C_sendByte(addr);

I2C_Ack();

I2C_Start(); /* 再次启动I2C传送数据 */

I2C_sendByte(DS1307_READ);

I2C_Ack();

dat_buf = I2C_receiveByte();

I2C_noAck();

I2C_Stop();

return dat_buf;

}

void DS1307_setTime(struct tm setValue)

{

DS1307_writeByte(ADDR_SEC,setValue.tm_sec);

DS1307_writeByte(ADDR_MIN,setValue.tm_min);

DS1307_writeByte(ADDR_HOUR,setValue.tm_hour);

DS1307_writeByte(ADDR_DAY,setValue.tm_wday);

DS1307_writeByte(ADDR_MONTH,setValue.tm_mon);

DS1307_writeByte(ADDR_YEAR,setValue.tm_year);

}

void DS1307_setEnableStatus(uchar setValue)

{

uchar buf = 0;

buf = DS1307_readByte(ADDR_SEC);

if(setValue == DS1307_ENABLE)

{

buf = buf&DS1307_ENABLE;

DS1307_writeByte(ADDR_SEC,buf);

}

else if(setValue == DS1307_DISABLE)

{

buf = buf|DS1307_DISABLE;

DS1307_writeByte(ADDR_SEC,buf);

}

else

buf = 0;

}

void DS1307_setHourMode(uchar setValue)

{

uchar buf = 0;

buf = DS

1307_readByte(ADDR_HOUR);

if(setValue == DS1307_12HOUR_MODE)

{

buf = buf|DS1307_12HOUR_MODE;

DS1307_writeByte(ADDR_HOUR,buf);

}

else if(setValue == DS1307_24HOUR_MODE)

{

buf = buf&DS1307_24HOUR_MODE;

DS1307_writeByte(ADDR_HOUR,buf);

}

else

buf = 0;

}

uchar DS1307_readSecond(void)

{

uchar sec_buf = 0;

uchar sec_l = 0;

uchar sec_h = 0;

sec_buf = DS1307_readByte(ADDR_SEC);

sec_h = (sec_buf 》》 4)&0x0F;

sec_l = sec_buf&0x0F;

return (sec_h*10 + sec_l);

}

uchar DS1307_readMinute(void)

{

uchar min_buf = 0;

uchar min_l = 0;

uchar min_h = 0;

min_buf = DS1307_readByte(ADDR_MIN);

min_h = (min_buf 》》 4)&0x0F;

min_l = min_buf&0x0F;

return (min_h*10 + min_l);

}

uchar DS1307_readHour(void)

{

uchar hour_buf = 0;

uchar hour_h = 0;

uchar hour_l = 0;

hour_buf = DS1307_readByte(ADDR_HOUR);

hour_h = (hour_buf 》》 4)&0x10;

hour_l = hour_buf&0x0f;

return (hour_h*10 + hour_l);

}

uchar DS1307_readDay(void)

{

uchar day_buf = 0;

day_buf = DS1307_readByte(ADDR_DAY);

return day_buf;

}

uchar DS1307_readDate(void)

{

uchar date_buf = 0;

uchar date_h = 0;

uchar date_l = 0;

date_buf = DS1307_readByte(ADDR_DATE);

date_h = (date_buf 》》 4)&0x0F;

date_l = date_buf&0x0F;

return (date_h*10 + date_l);

}

uchar DS1307_readMonth(void)

{

uchar month_buf = 0;

uchar month_h = 0;

uchar month_l = 0;

month_buf = DS1307_readByte(ADDR_MONTH);

month_h = (month_buf 》》 4)&0x0F;

month_l = month_buf&0x0F;

return (month_h*10 + month_l);

}

uchar DS1307_readYear(void)

{

uchar year_buf = 0;

uchar year_h = 0;

uchar year_l = 0;

year_buf = DS1307_readByte(ADDR_YEAR);

year_h = (year_buf 》》 4)&0x0F;

year_l = year_buf&0x0F;

return (year_buf*10 + year_l);

}

//struct tm DS1307_readTime(void)

void display(void)

{

P0 = tab[min/10]; /* P0为段选口 */

P2 = 0xFE; /* P2低四位为位选口 */

delay_ms(1);

P2 = 0xFF;

P0 = tab[min%10]&0x7F;

P2 = 0xFD;

delay_ms(1);

P2 = 0xFF;

P0 = tab[sec/10];

P2 = 0xFB;

delay_ms(1);

P2 = 0xFF;

P0 = tab[sec%10];

P2 = 0xF7;

delay_ms(1);

P2 = 0xFF;

}

void main(void)

{

uchar cnt = 0;

struct tm Init_t;

/* 初始时间全部置0(必须初始化!此步不可少!) */

Init_t.tm_sec = 0;

Init_t.tm_min = 0;

Init_t.tm_hour = 0;

Init_t.tm_wday = 0;

Init_t.tm_mon = 0;

Init_t.tm_year = 0;

I2C_Init();

DS1307_setTime(Init_t); /* 必须初始化!此步不可少! */

/* 主程序可根据需求自由修改 */

while(1)

{

sec = DS1307_readSecond();

min = DS1307_readMinute();

display();

}

}


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
用于个人局域网的超宽带技术研究