本文包含原理图、PCB、源代码、封装库、中英文PDF等资源
您需要 登录 才可以下载或查看,没有账号?注册会员
×
一、简单原理
DS1302是一种高性能、低功耗、带RAM的实时时钟芯片,它可以对年、月、日、星期、天、时、分、秒自动计时,并且具有闰年补偿功能。
DS1302具有宽电压工作范围:2.7-5.5v。
DS1302采用3线串行接口与单片机进行同步通信,并可采用突发方式一次传送多字节的时钟信号或RAM数据。
DS1302内部有一个31字节的用于临时存放数据的RAM寄存器。
DS1302还具备主电源/后备电源供电的双电源引脚,可以自动切换电源,并且提供了对后备电源进行涓细电流充电的能力。
DS1302的引脚说明如下:
Vcc1为后备电源,VCC2为主电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302由Vcc1或Vcc2两者中的较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。当Vcc2小于Vcc1时,DS1302由Vcc1供电。X1和X2是振荡源,外接32.768kHz晶振。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc≥2.5V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。I/O为串行数据输入输出端(双向),SCLK始终是输入端。
DS1302的控制字节
DS1302的控制字如下图所示。控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出。
数据输入输出(I/O)
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。 DS1302的寄存器
DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字请查阅DS1302的数据手册。
二、电路实现
如下是本实例中DS1302的电路连接图。由于只是学习DS1302的基本功能,所以本电路没有使用后备电源。
三、 程序设计
下面是DS1302的完整程序,程序实现将一个初始化时间写入DS1302,然后读出DS1302的实时时间,并发送到串口,在计算机上通过串口助手观察程序执行结果。 -
- #include<AVR/io.h>
- #include <util/delay.h>
- #include <avr/interrupt.h> //中断函数头文件
- //常量声明
- #define BAUD 9600
- #define TURE 1
- #define FALSE 0
- //时钟/日历寄存器
- #define RD 0x01 //读
- #define WR 0x00 //写
- #define SECOND 0x80 //秒
- #define MINUTE 0x82 //分
- #define HOUR 0x84 //时
- #define DAY 0x86 //日
- #define MONTH 0x88 //月
- #define WEEK 0x8A //星期 DATE
- #define YEAR 0x8C //年
- #define WR_PROTECT 0x8E //控制(写保护)
- #define CHARGE 0x90 //涓流充电
- #define BURST 0xBE //时钟多字节
- //配置位
- #define CLK_HALT 0x80 //停止时钟控制位 SECOND bit7
- #define CLK_START 0x00 //启动时钟
- #define M12_24 0x80 //12/24小时值选择位 HOUR bit7
- #define PROTECT 0x80 //写保护控制位 CONTROL bit7
- #define UPROTECT 0x00 //写保护控制位 CONTROL bit7
- //涓流充电控制常量
- #define TC_D1R2 0xA5 //充电时选择一个二极管和2K电阻
- #define TC_D2R8 0xAB //充电时选择二个二极管和8K电阻
- #define TC_DISABLED 0x00 //禁止充电功能
- //RAM 命令
- #define RAMBASE 0xC0 //RAM起始位为0XCO,RAM范围0-31
- //全局变量声明
- unsigned char Get_Time[7] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00};
- //函数声明
- void Delayus(unsigned int lus); //us延时函数
- void Delayms(unsigned int lms); //ms延时函数
- void Port_Init(void); //端口初始化配置
- void Usart_Init(void); //USART寄存器设置
- void Usart_PutChar(unsigned char cTXData); //字节发送函数
- void Usart_PutString(unsigned char *pcString); //字符串发送函数
- unsigned char DS1302_ReadByte(void); //从DS1302读一个字节数据
- void DS1302_WriteByte(unsigned char dat); //向DS1302写一个字节数据
- unsigned char DS1302_ReadData(unsigned addr); //从DS1302的指定地址读一个字节数据
- void DS1302_WriteData(unsigned char addr,unsigned data);
- //向DS1302的指定地址写一个字节数据
- void DS1302_SetTime(unsigned char *time); //对DS1302设置时间
- void DS1302_GetTime(void); //从DS1302读取时间
- unsigned char DS1302_Check(void); //DS1302是否工作检测
- void DS1302_Init(void); //DS1302初始化
- int main(void)
- {
- unsigned char Set_Time[7] = {0x59,0x59,0x10,0x20,0x01,0x02,0x09};
- //设置秒,分,时,日,月,星期,年
- unsigned char i;
- Port_Init();
- Usart_Init();
- Usart_PutString("DS1302实时时钟试验");
- Usart_PutString("设置当前时间为:");
- Usart_PutChar(0x0D);
- Usart_PutChar(0x0A); //发送回车换行
- Usart_PutChar('2');
- Usart_PutChar('0');
- Usart_PutChar(Set_Time[6] / 16 + 0x30);
- Usart_PutChar(Set_Time[6] % 16 + 0x30);
- Usart_PutString("年");
- Usart_PutChar(' ');
- Usart_PutChar(Set_Time[4] / 16 + 0x30);
- Usart_PutChar(Set_Time[4] % 16 + 0x30);
- Usart_PutString("月");
- Usart_PutChar(' ');
- Usart_PutChar(Set_Time[3] / 16 + 0x30);
- Usart_PutChar(Set_Time[3] % 16 + 0x30);
- Usart_PutString("日");
- Usart_PutChar(' ');
- Usart_PutChar(Set_Time[2] / 16 + 0x30);
- Usart_PutChar(Set_Time[2] % 16 + 0x30);
- Usart_PutString("时");
- Usart_PutChar(' ');
- Usart_PutChar(Set_Time[1] / 16 + 0x30);
- Usart_PutChar(Set_Time[1] % 16 + 0x30);
- Usart_PutString("分");
- Usart_PutChar(' ');
- Usart_PutChar(Set_Time[0] / 16 + 0x30);
- Usart_PutChar(Set_Time[0] % 16 + 0x30);
- Usart_PutString("秒");
- Usart_PutChar(' ');
- Usart_PutString("星期");
- Usart_PutChar(' ');
- //Usart_PutChar(Set_Time[5] / 16 + 0x30);
- Usart_PutChar(Set_Time[5] % 16 + 0x30);
- Usart_PutChar(0x0D);
- Usart_PutChar(0x0A); //发送回车换行
- DS1302_SetTime(Set_Time);
- sei(); //使能全局中断
- while(1)
- {
- DS1302_GetTime();
-
- Usart_PutString("现在时间");
- Usart_PutChar(0x0D);
- Usart_PutChar(0x0A); //发送回车换行
- Usart_PutChar('2');
- Usart_PutChar('0');
- Usart_PutChar(Get_Time[6] / 16 + 0x30);
- Usart_PutChar(Get_Time[6] % 16 + 0x30);
- Usart_PutString("年");
- Usart_PutChar(' ');
- Usart_PutChar(Get_Time[4] / 16 + 0x30);
- Usart_PutChar(Get_Time[4] % 16 + 0x30);
- Usart_PutString("月");
- Usart_PutChar(' ');
- Usart_PutChar(Get_Time[3] / 16 + 0x30);
- Usart_PutChar(Get_Time[3] % 16 + 0x30);
- Usart_PutString("日");
- Usart_PutChar(' ');
- Usart_PutChar(Get_Time[2] / 16 + 0x30);
- Usart_PutChar(Get_Time[2] % 16 + 0x30);
- Usart_PutString("时");
- Usart_PutChar(' ');
- Usart_PutChar(Get_Time[1] / 16 + 0x30);
- Usart_PutChar(Get_Time[1] % 16 + 0x30);
- Usart_PutString("分");
- Usart_PutChar(' ');
- Usart_PutChar(Get_Time[0] / 16 + 0x30);
- Usart_PutChar(Get_Time[0] % 16 + 0x30);
- Usart_PutString("秒");
- Usart_PutChar(' ');
- Usart_PutString("星期");
- Usart_PutChar(' ');
-
- //Usart_PutChar(Set_Time[5] / 16 + 0x30);
- Usart_PutChar(Get_Time[5] % 16 + 0x30);
- Usart_PutChar(0x0D);
- Usart_PutChar(0x0A); //发送回车换行
- for(i = 0;i < 4;i++)
- {
- Delayms(1000);
- }
- }
- }
- //端口状态初始化设置函数
- void Port_Init()
- {
- PORTD = 0X00; //USART的发送接收端口分别为PD0和PD1
- DDRD |= (1 << PD3); //PD0为接收端口,置为输入口;PD1为发送端口,置为输出口
- DDRE |= (1 << PE2) | (1 << PE3) | (1 << PE6); //DS1302的SCLK和I/O引脚设为输出
- //DDRE |= (1 << PE6); //DS1302的RST引脚设为输出
- }
- //USART寄存器配置函数
- void Usart_Init()
- {
- UCSR1A = 0X00;
- UCSR1C |= (1 << UCSZ11) | (1 << UCSZ10); //异步,数据格式8,N,1
-
- UBRR1L = (F_CPU / BAUD / 16 - 1) % 256; //波特率设置
- UBRR1H = (F_CPU / BAUD / 16 - 1) / 256;
- UCSR1B |= (1 << RXCIE1) | (1 << RXEN1) | (1 << TXEN1); //发送使能
- }
- //字节发送函数
- void Usart_PutChar(unsigned char cTXData)
- {
- while( !(UCSR1A & (1 << UDRE1)) ); //只有数据寄存器为空时才能发送数据
- UDR1 = cTXData; //发送数据送USART I/O数据寄存器-UDR
- }
- //接收中断函数
- ISR(USART1_RX_vect)
- {
- unsigned char Rev;
- Rev = UDR1; //从USART I/O数据寄存器-UDR中读出数据
- Usart_PutChar(Rev); //将接收到的数据发送
- }
- void Usart_PutString(unsigned char *pcString)
- {
- while (*pcString)
- {
- Usart_PutChar(*pcString++);
- }
- }
- //从DS1302读一个字节数据
- unsigned char DS1302_ReadByte(void)
- {
- unsigned char i,dat = 0; //dat存放读出的数据,初始化为0
- PORTE &= ~(1 << PE3); //DS1302的I/O口上拉不使能,
- DDRE &= ~(1 << PE3); //DS1302的I/O口设置为输入口,准备读数据
- for(i = 0;i < 8;i++) //读8位,低位在前,右移
- {
- dat >>= 1; //读出的数据右移一位
- PORTE |= (1 << PE2); //DS1302的SCLK端口拉高
- Delayus(10); //
- PORTE &= ~(1 << PE2); //DS1302的SCLK端口拉低,产生下降沿,
- Delayus(10);
- if(PINE & (1 << PE3)) //读数据端口状态
- {
- dat |= 0x80; //如果数据端口位高,相应数据位置1
- }
- }
- DDRE |= (1 << PE3); //最后将数据端口设置为输出
- return dat; //返回读出的数据
- }
- //向DS1302写一个字节数据
- void DS1302_WriteByte(unsigned char dat)
- {
- unsigned char i;
- for(i = 0;i < 8;i++) //写8位,低位在前
- {
- PORTE &= ~(1 << PE2); //DS1302的SCLK置低
- if(dat & 0x01) //写数据位
- {
- PORTE |= (1 << PE3); //如果该位为1,则I/O口置高
- }
- else
- {
- PORTE &= ~(1 << PE3); //如果该位为0,则I/O口置低
- }
- Delayus(10); //
- PORTE |= (1 << PE2); //DS1302的SCLK置高,产生上升沿
- dat >>= 1; //数据右移1位
- }
- }
- //从DS1302的指定地址读一个字节数据
- unsigned char DS1302_ReadData(unsigned addr)
- {
- unsigned char data;
- PORTE &= ~(1 << PE6); //拉低片选端
- PORTE &= ~(1 << PE2);//拉低时钟端
- Delayus(10);
- PORTE |= (1 << PE6);//拉高片选端
- Delayus(10);
- DS1302_WriteByte(addr);//写入操作命令(地址)
- Delayus(10);
- data = DS1302_ReadByte();//读出数据
- Delayus(10);
- PORTE &= ~(1 << PE2); //拉低时钟端
- PORTE &= ~(1 << PE6); //拉低片选端
- return data;
- }
- //向DS1302的指定地址写一个字节数据
- void DS1302_WriteData(unsigned char addr,unsigned data)
- {
- PORTE &= ~(1 << PE6); //拉低片选端
- PORTE &= ~(1 << PE2);//拉低时钟端
- Delayus(10);
- PORTE |= (1 << PE6);//拉高片选端
- Delayus(10);
- DS1302_WriteByte(addr);//写入操作命令(地址)
- Delayus(10);
- PORTE &= ~(1 << PE2);//拉低时钟端
- Delayus(10);
- DS1302_WriteByte(data);//写入数据
- PORTE &= ~(1 << PE2); //拉低时钟端
- Delayus(10);
- PORTE &= ~(1 << PE6); //拉低片选端
- }
- //对DS1302设置时间
- void DS1302_SetTime(unsigned char *time)
- {
- unsigned char i;
- unsigned char addr = 0x80;//写入地址从秒寄存器开始
- DS1302_WriteData(WR_PROTECT | WR,UPROTECT);//控制命令,WP位为0,允许写操作
- Delayms(5);
- for(i = 0;i < 7;i++)
- {
- DS1302_WriteData(addr | WR,time);// 秒 分 时 日 月 星期 年
- addr += 2;
- Delayms(1);
- }
- DS1302_WriteData(WR_PROTECT | WR,PROTECT);//控制命令,WP位为1,不允许写操作
- }
- //从DS1302读取时间
- void DS1302_GetTime(void)
- {
- unsigned char i;
- /*
- //
- unsigned char addr;
- PORTA &= ~(1 << PA1);
- for(i = 0;i < 7;i++)
- {
- tim = DS1302_ReadData(addr | RD);
- addr += 2;
- }
- */
- ////////////////////
- PORTE &= ~(1 << PE6);
- Delayus(10);
- PORTE |= (1 << PE6);
- Delayus(10);
- DS1302_WriteByte(0xbf);
- for(i = 0;i < 8;i++)
- {
- Get_Time = DS1302_ReadByte();
- }
- PORTE &= ~(1 << PE6);
- ///////////////////////////////////
- PORTE &= ~(1 << PE2);
- }
- //DS1302是否工作检测
- unsigned char DS1302_Check(void)
- {
- DS1302_WriteData(WR_PROTECT | WR,UPROTECT);
- DS1302_WriteData(RAMBASE | WR,0x31);
- if(DS1302_ReadData(RAMBASE | WR) == 0x31)
- {
- return TURE;
- }
- else
- {
- return FALSE;
- }
- }
- //DS1302初始化
- void DS1302_Init(void)
- {
- DS1302_WriteData(WR_PROTECT | WR,UPROTECT); //写入写允许命令
- DS1302_WriteData(SECOND | WR,CLK_START); //启动振荡器,DS1302开始工作
- DS1302_WriteData( WR_PROTECT | WR,PROTECT); //控制命令,WP位为1,不允许写操作
- }
- //us级别的延时函数
- void Delayus(unsigned int lus)
- {
- while(lus--)
- {
- _delay_loop_2(4); //_delay_loop_2(1)是延时4个时钟周期,参数为3则延时12
- //个时钟周期,本实验用12M晶体,则12个时钟周期为12/12=1us
- }
- }
- //ms级别的延时函数
- void Delayms(unsigned int lms)
- {
- while(lms--)
- {
- Delayus(1000); //延时1ms
- }
- }
复制代码 |