马伟力AVR笔记八基于DS1302的实时时钟实验Word格式文档下载.docx
《马伟力AVR笔记八基于DS1302的实时时钟实验Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《马伟力AVR笔记八基于DS1302的实时时钟实验Word格式文档下载.docx(18页珍藏版)》请在冰点文库上搜索。
X1和X2是振荡源,外接32.768kHz晶振。
RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。
RST输入有两种功能:
首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;
其次,RST提供终止单字节或多字节数据的传送手段。
当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。
上电运行时,在Vcc≥2.5V之前,RST必须保持低电平。
只有在SCLK为低电平时,才能将RST置为高电平。
I/O为串行数据输入输出端(双向),后面有详细说明。
SCLK始终是输入端。
2、DS1302的控制字节
DS1302的控制字如图2所示。
控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;
位5至位1指示操作单元的地址;
最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出。
3、数据输入输出(I/O)
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。
同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
4、DS1302的寄存器
DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字见表1。
此外,DS1302还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。
时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。
DS1302与RAM相关的寄存器分为两类:
一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;
另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。
8.2.2DS1302实时显示时间的软硬件设计
DS1302与CPU的连接需要三条线,即SCLK(7)、I/O(6)、RST(5)。
图3示出DS1302与89C2051的连接图,其中,时钟的显示用LCD。
1、DS1302与CPU的连接
实际上,在调试程序时可以不加电容器,只加一个32.768kHz的晶振即可。
只是选择晶振时,不同的晶振,误差也较大。
2、DS1302实时时间流程
图4示出DS1302的实时时间流程。
根据此流程框图,不难采集实时时间。
根据在调试中遇到的问题,特作如下说明:
DS1302与微处理器进行数据交换时,首先由微处理器向电路发送命令字节,命令字节最高位MSB(D7)必须为逻辑1,如果D7=0,则禁止写DS1302,即写保护;
D6=0,指定时钟数据,D6=1,指定RAM数据;
D5~D1指定输入或输出的特定寄存器;
最低位LSB(D0)为逻辑0,指定写操作(输入),D0=1,指定读操作(输出)。
在DS1302的时钟日历或RAM进行数据传送时,DS1302必须首先发送命令字节。
若进行单字节传送,8位命令字节传送结束之后,在下2个SCLK周期的上升沿输入数据字节,或在下8个SCLK周期的下降沿输出数据字节、
DS1302与RAM相关的寄存器分为两类:
再一类为突发方式下的RAM寄存器,在此方式下可一次性读、写所有的RAM的31个字节。
要特别说明的是备用电源B1,可以用电池或者超级电容器(0.1F以上)。
虽然DS1302在主电源掉电后的耗电很小,但是,如果要长时间保证时钟正常,最好选用小型充电电池。
如果断电时间较短(几小时或几天)时,就可以用漏电较小的普通电解电容器代替。
100μF就可以保证1小时的正常走时。
DS1302在第一次加电后,必须进行初始化操作。
初始化后就可以按正常方法调整时间。
DS1302存在时钟精度不高,易受环境影响,出现时钟混乱等缺点。
DS1302可以用于数据记录,特别是对某些具有特殊意义的数据点的记录,能实现数据与出现该数据的时间同时记录。
这种记录对长时间的连续测控系统结果的分析及对异常数据出现的原因的查找具有重要意义。
传统的数据记录方式是隔时采样或定时采样,没有具体的时间记录,因此,只能记录数据而无法准确记录其出现的时间;
若采用单片机计时,一方面需要采用计数器,占用硬件资源,另一方面需要设置中断、查询等,同样耗费单片机的资源,而且,某些测控系统可能不允许。
但是,如果在系统中采用时钟芯片DS1302,则能很好地解决这个问题。
8.2电路和连接
8.3电路和连接
串口电路前面已经介绍,本例中不再重复。
本例中DS1302与单片机的连接如上图所示,DS1302的5、6、7脚分别连接单片机的PA1、PB6、PB7脚
8.4程序设计
1、程序功能
程序的功能是使用单片机实现对DS18B20的操作,然后将读出的时间值通过串口发送到计算机。
2函数说明
本程序多个功能函数,分别是:
●端口初始化函数,设置各端口的初始工作状态。
●串口通信相关函数:
voidUsart_Init(void);
//USART寄存器设置
voidUsart_PutChar(unsignedcharcTXData);
//字节发送函数
voidUsart_PutString(unsignedchar*pcString);
//字符串发送函数
这些函数已经在前面的实例中做过介绍,在此不再重复。
●DS1302操作相关函数:
unsignedcharDS1302_ReadByte(void);
//从DS1302读一个字节数据
voidDS1302_WriteByte(unsignedchardat);
//向DS1302写一个字节数据
unsignedcharDS1302_ReadData(unsignedaddr);
//从DS1302的指定地址读一个字节数据
voidDS1302_WriteData(unsignedcharaddr,unsigneddata);
//向DS1302的指定地址写一个字节数据
voidDS1302_SetTime(unsignedchar*time);
//对DS1302设置时间
voidDS1302_GetTime(void);
//从DS1302读取时间
unsignedcharDS1302_Check(void);
//DS1302是否工作检测
voidDS1302_Init(void);
//DS1302初始化
●延时相关函数:
voidDelayus(unsignedintlus);
//us延时函数
voidDelayms(unsignedintlms);
//ms延时函数
由于WINAVR自带函数库中的延时函数使用起来很不方便,并且晶振频率不同,延时时间也有区别,而对DS18B20的操作时序要求比较严格,所以本实例中自己写了两个延时函数。
3、使用WINAVR开发环境,使用的是外部12M的晶振,所以需要将makefile文件中的时钟频率修改为12M。
另外在程序烧录到单片机的时候,熔丝位也要选择为外部12M晶振(注意是晶振,不是外部振荡器,一定不要选择错了,否则会导致单片机不能再烧写程序)。
4、程序说明
关于在对DS1302读写操作时的延时说明。
由于DS1302工作在32.768KHz的时钟条件下,而单片机工作在12MHz时钟环境下,在单片机对DS1302进行操作时,由于单片机的工作速度很快,DS1302可能响应不到,所以在程序中要适当增加一些延时,以使DS1302能够正确接收。
5、程序代码
/***********************************************
****AVRDS1302实时时钟范例***
****MCU:
ATmega16***
****作者:
maweili***
****编译器:
WINAVR***
*******
****2008.11.27***
***********************************************/
#include<
avr/io.h>
util/delay.h>
avr/interrupt.h>
//中断函数头文件
//常量声明
#defineBAUD9600
#defineTURE1
#defineFALSE0
//时钟/日历寄存器
#defineRD0x01//读
#defineWR0x00//写
#defineSECOND0x80//秒
#defineMINUTE0x82//分
#defineHOUR0x84//时
#defineDAY0x86//日
#defineMONTH0x88//月
#defineWEEK0x8A//星期DATE
#defineYEAR0x8C//年
#defineWR_PROTECT0x8E//控制(写保护)
#defineCHARGE0x90//涓流充电
#defineBURST0xBE//时钟多字节
//配置位
#defineCLK_HALT0x80//停止时钟控制位SECONDbit7
#defineCLK_START0x00//启动时钟
#defineM12_240x80//12/24小时值选择位HOURbit7
#definePROTECT0x80//写保护控制位CONTROLbit7
#defineUPROTECT0x00//写保护控制位CONTROLbit7
//涓流充电控制常量
#defineTC_D1R20xA5//充电时选择一个二极管和2K电阻
#defineTC_D2R80xAB//充电时选择二个二极管和8K电阻
#defineTC_DISABLED0x00//禁止充电功能
//RAM命令
#defineRAMBASE0xC0//RAM起始位为0XCO,RAM范围0-31
//全局变量声明
unsignedcharGet_Time[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//函数声明
voidPort_Init(void);
//端口初始化配置
intmain(void)
{
unsignedcharSet_Time[7]={0x59,0x59,0x15,0x05,0x12,0x05,0x08};
//设置秒,分,时,日,月,星期,年
unsignedchari;
Port_Init();
Usart_Init();
Usart_PutString("
DS1302实时时钟试验"
);
设置当前时间为:
"
Usart_PutChar(0x0D);
Usart_PutChar(0x0A);
//发送回车换行
Usart_PutChar('
2'
0'
Usart_PutChar(Set_Time[6]/16+0x30);
Usart_PutChar(Set_Time[6]%16+0x30);
年"
'
Usart_PutChar(Set_Time[4]/16+0x30);
Usart_PutChar(Set_Time[4]%16+0x30);
月"
Usart_PutChar(Set_Time[3]/16+0x30);
Usart_PutChar(Set_Time[3]%16+0x30);
日"
Usart_PutChar(Set_Time[2]/16+0x30);
Usart_PutChar(Set_Time[2]%16+0x30);
时"
Usart_PutChar(Set_Time[1]/16+0x30);
Usart_PutChar(Set_Time[1]%16+0x30);
分"
Usart_PutChar(Set_Time[0]/16+0x30);
Usart_PutChar(Set_Time[0]%16+0x30);
秒"
星期"
//Usart_PutChar(Set_Time[5]/16+0x30);
Usart_PutChar(Set_Time[5]%16+0x30);
//发送回车换行
DS1302_SetTime(Set_Time);
sei();
//使能全局中断
while
(1)
{
DS1302_GetTime();
Usart_PutString("
现在时间"
Usart_PutChar(0x0D);
Usart_PutChar(0x0A);
Usart_PutChar('
Usart_PutChar(Get_Time[6]/16+0x30);
Usart_PutChar(Get_Time[6]%16+0x30);
Usart_PutChar(Get_Time[4]/16+0x30);
Usart_PutChar(Get_Time[4]%16+0x30);
Usart_PutChar(Get_Time[3]/16+0x30);
Usart_PutChar(Get_Time[3]%16+0x30);
Usart_PutChar(Get_Time[2]/16+0x30);
Usart_PutChar(Get_Time[2]%16+0x30);
Usart_PutChar(Get_Time[1]/16+0x30);
Usart_PutChar(Get_Time[1]%16+0x30);
Usart_PutChar(Get_Time[0]/16+0x30);
Usart_PutChar(Get_Time[0]%16+0x30);
//Usart_PutChar(Set_Time[5]/16+0x30);
Usart_PutChar(Get_Time[5]%16+0x30);
for(i=0;
i<
4;
i++)
Delayms(1000);
}
}
//端口状态初始化设置函数
voidPort_Init()
PORTD=0X00;
//USART的发送接收端口分别为PD0和PD1
DDRD|=(1<
<
PD1);
//PD0为接收端口,置为输入口;
PD1为发送端口,置为输出口
DDRB|=(1<
PB6)|(1<
PB7);
//DS1302的SCLK和I/O引脚设为输出
DDRA|=(1<
PA1);
//DS1302的RST引脚设为输出
//USART寄存器配置函数
voidUsart_Init()
UCSRA=0X00;
UCSRC|=(1<
URSEL)|(1<
UCSZ1)|(1<
UCSZ0);
//异步,数据格式8,N,1
//UCSRC寄存器与UBRRH寄存器共用相同的I/O地址,写UCSRC时,URSEL应设置为1。
UBRRL=(F_CPU/BAUD/16-1)%256;
//波特率设置
UBRRH=(F_CPU/BAUD/16-1)/256;
UCSRB|=(1<
RXCIE)|(1<
RXEN)|(1<
TXEN);
//发送使能
//字节发送函数
voidUsart_PutChar(unsignedcharcTXData)
while(!
(UCSRA&
(1<
UDRE)));
//只有数据寄存器为空时才能发送数据
UDR=cTXData;
//发送数据送USARTI/O数据寄存器-UDR
//接收中断函数
ISR(USART_RXC_vect)
unsignedcharRev;
Rev=UDR;
//从USARTI/O数据寄存器-UDR中读出数据
Usart_PutChar(Rev);
//将接收到的数据发送
voidUsart_PutString(unsignedchar*pcString)
while(*pcString)
Usart_PutChar(*pcString++);
}
//从DS1302读一个字节数据
unsignedcharDS1302_ReadByte(void)
unsignedchari,dat=0;
//dat存放读出的数据,初始化为0
PORTB&
=~(1<
PB6);
//DS1302的I/O口上拉不使能,
DDRB&
//DS1302的I/O口设置为输入口,准备读数据
8;
i++)//读8位,低位在前,右