小鹏STEM
首页
主题
课程
课件
创作
赛事
资源
文章
登录
注册
DS1302实时时钟
所谓实时时钟,是指采用实时时钟芯片为核心构成的时钟,它不需要单片机的软件干预就能自动产生时、分、秒等时间信息,所以也称实时时钟为硬时钟。在学习TWI模块时,曾经介绍过时钟芯片DS1307,它是基于I 17.1
DS1302的功能
DS1302是美国DALLAS(现在改名为MAXIM)公司推出的一种高性能、低功耗、带RAM的实时时钟电路。它可以对年、月、日、星期、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5~5.5V,采用三线接口与CPU进行串行通信,使用普通32.768kHz晶振驱动,并且可以为备用电源提供可编程的充电功能。
17.1.1
DS1302的引脚
双列直插DIP8封装的DS1302实时时钟芯片引脚排列如图17-1所示。从图中可以看出,DS1302有两个电源引脚,其中Vcc1为后备电源,Vcc2为主电源。在主电源关闭的情况下,时钟依靠后备电源保持运行。在正常工作模式下,DS1302由Vcc1和Vcc2两者中电压值较高的一方供电,当Vcc2大于Vcc1至0.2V时,由Vcc2给DS1302供电,当Vcc2小于Vcc1时,由Vcc1供电。
X1和X2引脚是DS1302的时钟振荡源输入,用于外接32.768kHz晶振。
DS1302的典型应用电路如图17-2所示。其中SCLK、I/O、
17.1.2
BCD码
时间信息在DS1302寄存器是以BCD码的方式存放的,这种编码方式的应用非常广泛,所以我们需要先来了解一下BCD码。所谓BCD码(Binary-Coded Decimal),就是一种二进制转十进制的编码方式。BCD码本身是二进制的数字编码形式,它利用4位二进制数码来表示一个十进制的数码,由于4位二进制数可以表示16种状态,而十进制数只有0~9,所以舍弃四位二进制编码的最后6种状态,只选用0000~1001来表示0~9这十个数字。使用BCD码的好处是方便二进制和十进制之间的转换,十进制数与BCD码的对应关系详见表17-1。
下面我们以8位的分寄存器为例来说明一下BCD码的存放方式。分钟数据的取值范围在0~59之间,在存放分钟数据时,8位的分寄存器分成高四位和低四位两个部分,高四位存放分钟的十位数据,低四位存放分钟的个位数据,如图17-3所示。
如果需要让分寄存器存储“48”分,则将分钟的十位“4”转换成二进制“0100”,存放于分寄存器的高四位,而将分钟的个位“8”转换成二进制的“1000”,存放于分钟寄存器的低四位,这时分寄存器所存储的值为“01001000”。
17.1.3
DS1302的内部结构
DS1302片内有40个寄存器,这些寄存器按功能不同可划分成以下三类:
·7个时钟、日历写读寄存器,用于保存时间信息。
·2个控制寄存器,用于对DS1302的功能控制。
·31个字节的内存单元,用于保存数据。
这些寄存器的功能详见图17-4中寄存器的定义。单片机通过对这些寄存器的读写,可以获得时间信息、实现对芯片的控制或者保存临时数据。
17.1.4
DS1302的寄存器
1)SEC(秒寄存器):最高位CH位(bit7)为时钟暂停位,当该位为1时,时钟振荡器停止工作,DS1302被置为低功耗的备份模式下,此时芯片的电源消耗小于100毫微瓦。当CH位为0时,时钟振荡器启动。秒寄存器的低四位用于存放秒的个位数,bit6-bit4位用于存放秒的十位数。
2)MIN(分寄存器):低四位用于存放分的个位数,bit6-bit4位用于存放分的十位数。
3)HR(小时寄存器):小时寄存器的最高位(bit7)用于定义12或24小时计时方式。当该位为1时,时钟以12小时方式存储。最高位为0时,时钟以24小时方式存储。在12小时存储方式下,bit5位是AM/PM位,当bit5位为1时表示PM,为0时表示AM。在24小时存储方式下,bit5-bit4位用于存放小时的十位数。小时寄存器的低四位始终用于保存小时的个位数。
4)DATE(日期寄存器):日期寄存器的低四位用于存放日期的个位数,bit5-bit4位用于存放日期的十位数。
5)MONTH(月寄存器):月寄存器的低四位用于存放月的个位数,bit4位用于存放月的十位数。
6)DAY(星期寄存器):星期寄存器的低三位用于存放星期数。
7)YEAR(年寄存器):年寄存器的低四位用于存放年的个位数,高四位用于存放年的十位数。
8)CONTROL(控制寄存器):也称写保护寄存器。该寄存器的最高位WP是写保护位,当该位为1时,写保护使能,这时任何对寄存器的写操作都被禁止。
9)TRICKLE CHARGER(涓流充电寄存器):涓流充电寄存器用来控制DS1302对后备电源的充电特性,其充电电路的工作原理如图17-5所示。
涓流充电寄存器的高四位为涓流充电选择位(TCS位),当DS1302上电时,涓流充电被禁止。为了防止偶然的因素使充电器误动作,只有当寄存器高四位的值为“1010”时才能启动涓流充电器;两个DS位为二极管选择位(bit3-bit2),用于设定主电源是通过一个二极管或两个二极管给电池充电;两个RS位为充电限流电阻选择位,用于设定充电限流电阻的阻值。涓流充电控制寄存器的具体功能详见表17-2。
17.1.5
DS1302的控制指令
对DS1302的控制是通过一系列的指令来实现的,这些指令按照操作对象的不同可以分为两类,一类是CLOCK类,一类是RAM类,指令及与目标寄存器的对应关系如表17-3所示。
DS1302的控制指令具有以下特点:
·DS1302控制指令的最高有效位(bit7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中。
·DS1302控制指令的次高位(bit6)为0时,所读写的是时钟及日历寄存器中的数据。当次高位(bit6)为1时,读写的是片内的RAM。
·DS1302控制指令的最低有效位(bit0)为0时,表示接下来要进行写操作,为1时表示要进行读操作。
·DS1302的控制指令总是从最低位开始传输。
17.1.6
DS1302数据传输格式
DS1302有两种数据传输方式,一种是单字节传送(single byte transfer),另一种是多字节传送(burst mode transfer),在这里我们只讨论单字节传送。DS1302单字节传送时的数据格式及时序如图17-6所示。
在单字节传送方式下,每一次数据传送都在16个时钟周期内完成,前8个时钟周期由MCU向DS1302写入一个控制指令字节,之后的8个时钟周期内控制器向DS1302读或写数据。在数据传输过程中,时钟脉冲高的电平期间要保持I/O数据线上数据的稳定。
1)DS1302的读时序:当从DS1302读出信息时,先写入8位的读指令字节,指令的低位在前高位在后,8位的读指令字节分别在SCLK线上8个时钟周期的上升沿写入DS1302。在接下来的8个时钟周期的下降沿,数据从最低位开始依次从DS1302中被读出。
2)DS1302的写时序:当向DS1302写入信息时,同样需要先写入8位的写指令字节,8位的写指令字节分别在8个时钟周期的上升沿写入DS1302,在接下来的8个时钟周期的上升沿,待写入的数据从最低位开始依次写入DS1302中。
17.2
DS1302的应用实例
17.2.1
DS1302初始化
DS1302在第一次加电后,必须进行一次初始化操作,才能使DS1302正常工作。芯片加电时只要初始化一次即可,初始化后的状态会一直保持到其掉电之后。DS1302的初始化方法可以参考以下步骤:
1)寄存器初始化,关闭写保护,暂停振荡器。
2)涓流充电寄存器初始化,定义正确的电池充电方式。
3)秒寄存器初始化,定义秒数值。
4)分寄存器初始化,定义分数值。
5)时寄存器初始化,定义时数值。
6)日期寄存器初始化,定义日期数值。
7)月寄存器初始化,定义月数值。
8)星期寄存器初始化,定义星期数值。
9)年寄存器初始化,定义年数值。
10)重启振荡器,打开写保护。
17.2.2
DS1302数显时钟
使用DS1302实时时钟芯片组建时钟是一件简单而有趣的事情,所需的外围元器件也很少,你可以购买一片DIP8封装的DS1302时钟芯片,另配上一小块多孔电路板及少量元器件,按照图17-2所示的电路图搭建一个硬件时钟电路,使用ATmega32单片机的PD5、PD6和PD7引脚分别驱动DS1302的三个功能引脚,即可体验到真正的实时时钟了。本书为了简化步骤,直接使用了成品的时钟模块与AVR系统板通信,但其工作原理与图17-2所列出的电路完全一致。
打开Atmel Studio 6.1软件,新建一个名为“ds1302”的项目,保存在chapter17文件夹下,软件会自动为项目添加名为ds1302.c的源文件,编辑这个源文件并修改代码,具体代码详见代码清单17-1。
代码清单17-1
DS1302数显时钟
/*
*
ds1302.c *
*
Created: 2013/8/15
15:01:10
*
Author: GAO */
#include
//
包含AVR 头文件
#define F_CPU 16000000UL //
定义系统时钟频率
#include
//
包含延时函数头文件
#define DS_CLK_SET (PORTD|=0x20)
//
置位PD5
(SCLK 线)
#define DS_CLK_CLR (PORTD&=0xDF)
//
清零PD5
#define DS_IO_SET (PORTD|=0x40)
//
置位PD6
(I/O 线)
#define DS_IO_CLR (PORTD&=0xBF)
//
清零PD6
#define DS_RST_SET (PORTD|=0x80)
//
置位PD7
(RESET 线)
#define DS_RST_CLR (PORTD&=0x7F)
//
清零PD7
unsigned char table0[]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f }; //
共阴无点
unsigned char table1[]={0xbf,0x86,0xdb,0xcf,0xe6, 0xed,0xfd,0x87,0xff,0xef }; //
共阴有点
unsigned char t_sec; //
定义全局变量秒
unsigned char t_min; //
定义全局变量分
unsigned char t_hr; //
定义全局变量时
void display(void); //
数码管显示函数声明
void write_1byte(unsigned char TD); //
写入1
个字节数据函数声明
unsigned char read_1byte(void); //
读出1
个字节数据函数声明
void write_ds1302(unsigned char DS_ADD,unsigned char DS_DAT); //
写DS1302
函数声明
unsigned char read_ds1302(unsigned char DS_ADD); //
读DS1302
函数声明
void init_ds1302(); //
初始化DS1320
函数声明(设定时钟)
int main(void)
{
DDRA=0xFF; //
设数码管段驱动端为输出
DDRB=0xF0; //
设数码管位驱动端为输出
init_ds1302(); //
初始化DS1302
,设定时钟
while(1)
{
t_sec=read_ds1302(0x81); //
读秒寄存器
_delay_ms(1); //
延时1ms t_min=read_ds1302(0x83); //
读分寄存器
_delay_ms(1); //
延时1ms t_hr=read_ds1302(0x85); //
读时寄存器
_delay_ms(1); //
延时1ms display(); //
数码管显示
}
}
/**********
数码管显示函数**********/
void display(void)
{
unsigned char NUM4,NUM3,NUM2,NUM1; NUM1=t_min&0x0F; //
取分的个位赋予NUM1
NUM2=t_min&0xF0; //
取分的十位
NUM2=NUM2>>4; //
赋予NUM2
NUM3=t_hr&0x0F; //
取时的个位赋予NUM3
NUM4=t_hr&0xF0; //
取时的十位
NUM4=NUM4>>4; //
赋予NUM4
PORTA=table0[NUM1]; PORTB=0x10; _delay_ms(2); //
延时2ms PORTA=0x00; PORTB=0x00; _delay_ms(1); //
延时1ms PORTA=table0[NUM2]; PORTB=0x20; _delay_ms(2); //
延时2ms PORTA=0x00; PORTB=0x00; _delay_ms(1); //
延时1ms if((
t_sec%2)==1)
//
秒闪烁
{
PORTA=table0[NUM3]; PORTB=0x40; _delay_ms(2); //
延时2ms }
else {
PORTA=table1[NUM3]; PORTB=0x40; _delay_ms(2); //
延时2ms }
PORTA=0x00; PORTB=0x00; _delay_ms(1); //
延时1ms PORTA=table0[NUM4]; PORTB=0x80; _delay_ms(2); //
延时2ms PORTA=0x00; PORTB=0x00; _delay_ms(1); //
延时1ms }
/**********
写入1
个字节数据函数**********/
void write_1byte(unsigned char TD)
{
unsigned char i,TEMP; TEMP=TD; DDRD=DDRD|0xE0; //
将PORTD 高三位设为输出
for(i=8;i>0;i--)
{
if((TEMP&0x01)==1)
//
如果TEMP 最低位值为1
{
DS_IO_SET; //IO 线置1
}
else {
DS_IO_CLR; //IO 线清零
}
DS_CLK_SET; //
产生时钟
_delay_us(1); //
延时1us DS_CLK_CLR; //
产生时钟
TEMP=TEMP>>1; }
}
/**********
读出1
个字节数据函数**********/
unsigned char read_1byte(void)
{
unsigned char i; unsigned char TEMP; TEMP=0x00; //
给TEMP 赋一个初值
DDRD=DDRD|0xE0; //
将PORTD 高三位设为输出
DDRD=DDRD&0xBF; //
将PD6
设为输入
for(i=8;i>0;i--)
{
TEMP=TEMP>>1; if((PIND&0x40)==0x40)
//
如果IO 线读为1
{
TEMP=TEMP|0x80; //TEMP 最高位或1
}
DS_CLK_SET; //
产生时钟
_delay_us(1); //
延时1us DS_CLK_CLR; //
产生时钟
}
return TEMP; }
/**********
写DS1302
函数**********/
void write_ds1302(unsigned char DS_ADD,unsigned char DS_DAT)
{
DS_RST_CLR; DS_CLK_CLR; DS_RST_SET; write_1byte(DS_ADD); //
写入1
个字节指令
write_1byte(DS_DAT); //
写入1
个字节数据
DS_CLK_SET; DS_RST_CLR; }
/**********
读DS1302
函数**********/
unsigned char read_ds1302(unsigned char DS_ADD)
{
unsigned char DS_INF; DS_RST_CLR; DS_CLK_CLR; DS_RST_SET; write_1byte(DS_ADD); //
写入1
个字节指令
DS_INF=read_1byte(); //
读出1
个字节数据
DS_CLK_SET; DS_RST_CLR; return DS_INF; }
/**********
初始化DS1320
函数**********/
void init_ds1302()
{
write_ds1302(0x8e,0x00); //
关闭写保护
write_ds1302(0x90,0xaa); //
定义充电方式
write_ds1302(0x80,0x00); //
定义秒
write_ds1302(0x82,0x30); //
定义分
write_ds1302(0x84,0x08); //
定义时
write_ds1302(0x86,0x16); //
定义日
write_ds1302(0x88,0x08); //
定义月
write_ds1302(0x8a,0x05); //
定义星期
write_ds1302(0x8c,0x13); //
定义年
write_ds1302(0x8e,0x80); //
打开写保护
}
/**********
结束**********/
代码编写完成后,对其进行编译,并将生成的ds1302.hex文件烧写到AVR系统板上的ATmega32单片机中,烧写完成后,程序即开始运行,其状态如图17-7所示。
程序运行后四位数码管显示的是当前时间,时和分之间有一个以秒为周期闪烁的小数点,表示当前时钟正在运行。我们可以进一步修改程序,开发出具有闹钟、整点报时以及按键调时等多功能的闹钟或万年历来。看到这些,你是不是也很想尝试一下,那还等什么,动手吧,你一定行的!
上一节
步进电机的驱动
下一节
红外线解码及发射
微信分享
评论
评论:
提交
AVR单片机应用实例
作者:高显生 共7讲
阅读模式
课程
步进电机的驱动
DS1302实时时钟
红外线解码及发射
DS18B20数字温度传感器
DHT11数字温湿度传感器
1602字符型液晶显示器
12864点阵型液晶显示器
推荐文章
在STEM(科学、技术、工程和数学)教育中推进AI辅助计算思维(Act-STEM)
乐高机械组42215 沃尔沃 EC500 混动挖掘机
Codeblocks 快速入门
树莓派Build HAT
乐高WEDO打印机搭建分享
《2024素质教育行业发展趋势报告》:“AI+素质教育”逐步落地
2025年少儿编程行业五大预测:少儿编程正站在一个新的起点上
乐高反重力悬浮?
Scratch 3.0连接EV3
【有更新,3月考生必看】青少年等级考试---线上考试环境测试
推荐资源
深圳市义务教育人工智能课程纲要(2024年版)
乐高教育 2023 产品解决方案指南
FLL机器人挑战赛2024-2025赛季 SUBMERGED 资料
小学科学课程标准
EV3 Classroom程序创意设计第一部分
技术运用于教育:谁来做主?
乐高教育 WeDo 2.0 计算思维-教师指南
2023中小学阶段的人工智能课程调研报告
Python神经网络编程
微信分享
×
登录
×
手机号:
密码:
忘记密码?
微信扫码登录
×