杰理AC63系列驱动时钟芯片DS1302
1.DS1302时钟芯片介绍
DS1302可慢速充电实时时钟芯片包含实时时钟/日历和31字节的非易失性静态 RAM。它经过一个简单的串行接口与微处理器通信。实时时钟/日历可对秒,分,时,日,周,月,和年进行计数,对于小于31 天的月,月末的日期自动进行调整,还具有闰年校正的功能。时钟可以采用 24 小时格式或带 AM(上午)/PM(下午)的 12 小时格式。31 字节的 RAM 可以用来临时保存一些重要数据。使用同步串行通信,简化了 DS1302 与微处理器的通信。与时钟/RAM 通信仅需 3 根线:(1)RST(复位),(2)I/O(数据线)和(3)SCLK(串行时钟)。(数据可以以每次一个字节的单字节形式或多达 31 字节的多字节形式传输。DS1302能在非常低的功耗下工作,消耗小于 1µW 的功率便能保存数据和时钟信息。
注意:可能是芯片制造商或者版本的原因,有些芯片手册的RST引脚也叫做CE引脚,其功能都是一样的,不用刻意关注。
芯片读写时序图:
需要注意的是:读时序的时候需要根据情况加一些延时,一般是us级。
芯片相关寄存器概要:
2.驱动程序开发
头文件DS1302.h:
#ifndef __DS1302_H__
#define __DS1302_H__
#include "app.h"
extern unsigned char DS1302_Time[8];
#define DS1302_SCLK IO_PORTA_03
#define DS1302_IO IO_PORTA_04
#define DS1302_CE IO_PORTA_05 //CE同RST,其功能一样
void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,unsigned char Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_ReadTime(void);
void DS1302_SetTime(void);
#endif
头文件DS1302.c:
#include "DS1302.h"
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E
//初始化时间存放在该数组,左到右依次为年月日时分秒周 -- 2024.5.17 15:10:30 星期五
unsigned char DS1302_Time[8] = {20, 24, 05, 17, 15, 10, 30, 05};
//阻塞延时
void block_delay(uint16_t count){
for(uint16_t i = 0;i < count;i++){
asm volatile("nop");
}
}
/**
* @brief 初始化DS1302
* @param 无
* @retval 无
*/
void DS1302_Init(void)
{
//引脚初始化--输出
gpio_port_init(DS1302_SCLK, 0 ,1);
gpio_port_init(DS1302_IO, 0 ,1);
gpio_port_init(DS1302_CE, 0 ,1);
gpio_write(DS1302_SCLK, 0);
gpio_write(DS1302_CE, 0);
}
/**
* @brief 写入
* @param Command 地址/命令字节 Data 数据
* @retval 无
*/
void DS1302_WriteByte(unsigned char Command, unsigned char Data)
{
unsigned char i;
uint16_t cnt = 100;
//IO--输出
gpio_port_init(DS1302_IO, 0 ,1);
gpio_write(DS1302_CE, 0);
gpio_write(DS1302_SCLK, 0);
gpio_write(DS1302_CE, 1);
for(i=0; i<8; i++)
{
if(Command & 0x01)
gpio_write(DS1302_IO, 1);
else
gpio_write(DS1302_IO, 0);
Command >>=1;
gpio_write(DS1302_SCLK, 0);
gpio_write(DS1302_SCLK, 1);
}
for(i=0; i<8; i++)
{
if(Data & 0x01)
gpio_write(DS1302_IO, 1);
else
gpio_write(DS1302_IO, 0);
Data >>=1;
gpio_write(DS1302_SCLK, 0);
gpio_write(DS1302_SCLK, 1);
}
gpio_write(DS1302_SCLK, 1);
gpio_write(DS1302_CE, 0);
}
/**
* @brief 读出
* @param Command 地址/命令字节
* @retval 读出的数据
*/
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i, Data = 0x00;
gpio_write(DS1302_CE, 0);
gpio_write(DS1302_SCLK, 0);
gpio_write(DS1302_CE, 1);
//IO--输出
gpio_port_init(DS1302_IO, 0 ,1);
Command |= 0x01;
for(i=0; i<8; i++)
{
if(Command & 0x01)
gpio_write(DS1302_IO, 1);
else
gpio_write(DS1302_IO, 0);
Command>>=1;
gpio_write(DS1302_SCLK, 0);
gpio_write(DS1302_SCLK, 1);
}
//IO--输入
gpio_port_init(DS1302_IO, 1 ,1);
for(i=0; i<8;i++)
{
gpio_write(DS1302_SCLK, 1);
gpio_write(DS1302_SCLK, 0);
//阻塞延时
block_delay(1);
if(gpio_read(DS1302_IO)){Data = Data | (0x01<<i);}
}
gpio_write(DS1302_SCLK, 1);
gpio_write(DS1302_CE, 0);
gpio_port_init(DS1302_IO, 0 ,1);
gpio_write(DS1302_IO, 0);
// //系统退出临界保护区
// OS_EXIT_CRITICAL();
return Data;
}
/**
* @brief DS1302设置时间,调用之后,DS1302_Time数组的数字会被设置到DS1302中
* @param 无
* @retval 无
*/
void DS1302_SetTime(void)
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[1]/10*16+DS1302_Time[1]%10);//十进制转BCD码后写入
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_DATE,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[7]/10*16+DS1302_Time[7]%10);
DS1302_WriteByte(DS1302_WP,0x80);
}
/**
* @brief DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中
* @param 无
* @retval 无
*/
void DS1302_ReadTime(void)
{
unsigned char Temp = 0;
Temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[1]=Temp/16*10+Temp%16;//BCD码转十进制后读取
Temp=DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[2]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DATE);
DS1302_Time[3]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[4]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[5]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_SECOND);//屏蔽秒的第7位,避免超出59
DS1302_Time[6]=Temp/16*10+Temp%16;//&0x7f
Temp=DS1302_ReadByte(DS1302_DAY);
DS1302_Time[7]=Temp/16*10+Temp%16;
}
3.实验结果
经测试,上述驱动代码可正常驱动DS1302模块,若有疑问,欢迎留言咨询。