物联网实战--驱动篇之(七)RTC时钟(DS1302)

目录

一、RTC简介

二、DS1302介绍

三、初始化

四、字节读写

五、功能函数


一、RTC简介

实时时钟,简称RTC,这个在STM32的外设里也有,不过STM32F1系列的RTC实际上只有一个计数器功能,如果需要年月日要自己写软件计算 ,比较麻烦,这时候就可以使用带有年月日的RTC芯片了,常用的有DS1302,可以自己计算闰年,具体资料可以看这里。DS1302Z_(JSMSEMI(杰盛微))DS1302Z中文资料_价格_PDF手册-立创电子商城

二、DS1302介绍

主要是看下DS1302的通讯方式和寄存器,它的通讯方式有点类似于IIC,也是时钟线+数据线,不过还多了个复位(片选)线,时序也是不一样的,没有IIC那么多信号。寄存器看下图:

其中年份是00~99,也就是2000~2099年了,数据格式是BCD码。

下面先从头文件开始:

主要定义了时间结构体、引脚结构体和IO相关函数,寄存器的地址根据手册定义。

三、初始化

首先初始化时钟、数据和复位3个引脚,其中数据脚有时候需要作为输入,具体代码如下:

cpp 复制代码
/*		 
================================================================================
描述 : 硬件初始化
输入 : 
输出 :  
================================================================================
*/
void drv_ds1302_init(GPIO_TypeDef* port_clk, uint32_t pin_clk,
										 GPIO_TypeDef* port_io, uint32_t pin_io,
                     GPIO_TypeDef* port_rst, uint32_t pin_rst,
										Ds1302RtcStruct *rtc_initpara)
{
	g_sDs1302Drv.port_clk=port_clk;
	g_sDs1302Drv.pin_clk=pin_clk;
	g_sDs1302Drv.port_io=port_io;
	g_sDs1302Drv.pin_io=pin_io;
	g_sDs1302Drv.port_rst=port_rst;
	g_sDs1302Drv.pin_rst=pin_rst; 
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Pin = pin_clk;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; 
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(port_clk, &GPIO_InitStruct);	
  
	GPIO_InitStruct.GPIO_Pin = pin_io;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; 
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(port_io, &GPIO_InitStruct);	

	GPIO_InitStruct.GPIO_Pin = pin_rst;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; 
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(port_rst, &GPIO_InitStruct);	
  

	DS1302_RST_0; 	
	DS1302_CLK_0;
	delay_us(5);
	drv_ds1302_set_wp(false);
	drv_ds1302_write(0x90, 0xA7);//充电寄存器
	drv_ds1302_set_wp(true);
	
	drv_ds1302_set_hour_format(true);//24h制
	if(drv_ds1302_read(0x81)&0x80)//查询DS1302时钟是否启动,如果时钟停止走动:启动时钟+初始化时钟
	{		
		printf("DS1302 stop!\n");
		drv_ds1302_set_time(rtc_initpara);
		drv_ds1302_start();
	}

}

/*		 
================================================================================
描述 : 数据脚读写转换
输入 : 
输出 :  
================================================================================
*/
void drv_ds1302_set_io_mode(bool is_out)
{
	if(is_out)
	{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = g_sDs1302Drv.pin_io;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; 
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(g_sDs1302Drv.port_io, &GPIO_InitStruct);			
	}
	else
	{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = g_sDs1302Drv.pin_io;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(g_sDs1302Drv.port_io, &GPIO_InitStruct);
	}
}

如果时钟没断电过就不用再次启动了。

四、字节读写

下面是最基本的字节读写函数,时序具体参考手册。

cpp 复制代码
/*		 
================================================================================
描述 : 写字节
输入 : 
输出 :  
================================================================================
*/
void drv_ds1302_write(u8 reg_addr, u8 reg_data)
{
	DS1302_RST_0;
	DS1302_CLK_0;
	delay_us(2);
	DS1302_RST_1;
	delay_us(5);
	for(u8 i=0; i<8; i++)
	{
		if(reg_addr&0x01)DS1302_IO_1;
		else DS1302_IO_0;
		DS1302_CLK_1;
		delay_us(5);
		DS1302_CLK_0;
		reg_addr=reg_addr>>1;
	}
	
	for(u8 i=0; i<8; i++)
	{
		if(reg_data&0x01)DS1302_IO_1;
		else DS1302_IO_0;
		DS1302_CLK_1;
		delay_us(5);
		DS1302_CLK_0;
		reg_data=reg_data>>1;
	}	
	DS1302_RST_0;
	delay_us(5);
}

/*		 
================================================================================
描述 : 读字节
输入 : 
输出 :  
================================================================================
*/
u8 drv_ds1302_read(u8 reg_addr)
{
	DS1302_RST_1;
	delay_us(5);
	for(u8 i=0; i<8; i++)
	{
		if(reg_addr&0x01)DS1302_IO_1;
		else DS1302_IO_0;
		DS1302_CLK_1;
		delay_us(5);
		DS1302_CLK_0;
		reg_addr=reg_addr>>1;
	}
	
	drv_ds1302_set_io_mode(0);
	u8 value=0;
	for(u8 i=0; i<8; i++)
	{
		value=value>>1;
		if(DS1302_IO_READ()>0)value|=0x80; 

		DS1302_CLK_1;
		delay_us(5);
		DS1302_CLK_0;
	}	
	drv_ds1302_set_io_mode(1);
	DS1302_RST_0;	
	delay_us(5);
	return value;	
}

每次读写复位脚都要拉高才能进行,数据是低位先传输。

五、功能函数

有了基本的读写函数后,就可以根据寄存器地址进行功能设置了。比如下面的启动和停止:

cpp 复制代码
/*		 
================================================================================
描述 : 停止
输入 : 
输出 :  
================================================================================
*/
void drv_ds1302_stop(void)
{
	drv_ds1302_set_wp(false);
	u8 ret=drv_ds1302_read(0x81);
	ret=ret|0x80;
	drv_ds1302_write(0x80,ret);
	drv_ds1302_set_wp(true);
}


/*		 
================================================================================
描述 : 启动
输入 : 
输出 :  
================================================================================
*/
void drv_ds1302_start(void)
{
	drv_ds1302_set_wp(false);
	u8 ret=drv_ds1302_read(0x81);
	ret=ret&0x7F;
	drv_ds1302_write(0x80,ret);
	drv_ds1302_set_wp(true);
}

时间格式设置:

cpp 复制代码
/*		 
================================================================================
描述 : 设置时间格式
输入 : 
输出 :  
================================================================================
*/
void drv_ds1302_set_hour_format(bool is_24h)
{
	drv_ds1302_set_wp(false);
	if(is_24h)
	{
		u8 ret=drv_ds1302_read(0x85);
		ret=ret&0x7F;
		drv_ds1302_write(0x84,ret);		
		printf("ds1302 set 24h\n");
	}
	else
	{
		u8 ret=drv_ds1302_read(0x85);
		ret=ret|0x80;
		drv_ds1302_write(0x84,ret);		
		printf("ds1302 set 12h\n");
	}
	drv_ds1302_set_wp(true);
}

时间设置:

cpp 复制代码
/*		 
================================================================================
描述 : 时间设置
输入 : 
输出 :  
================================================================================
*/
void drv_ds1302_set_time(Ds1302RtcStruct *rtc_initpara)
{
	if(rtc_initpara==NULL)
		return;
	printf("drv_ds1302_set_time=20%02x-%02x-%02x  %02x:%02x:%02x\n", rtc_initpara->rtc_year, rtc_initpara->rtc_month, rtc_initpara->rtc_date,
																																rtc_initpara->rtc_hour, rtc_initpara->rtc_minute, rtc_initpara->rtc_second	);
	drv_ds1302_set_wp(false);
	drv_ds1302_write(DS1302_SEC_ADDR,rtc_initpara->rtc_second);
	drv_ds1302_write(DS1302_MIN_ADDR,rtc_initpara->rtc_minute);
	drv_ds1302_write(DS1302_HOUR_ADDR,rtc_initpara->rtc_hour);
	
	drv_ds1302_write(DS1302_DATE_ADDR,rtc_initpara->rtc_date);
	drv_ds1302_write(DS1302_MONTH_ADDR,rtc_initpara->rtc_month);
	drv_ds1302_write(DS1302_YEAR_ADDR,rtc_initpara->rtc_year);
	
	drv_ds1302_set_wp(true);
}

时间读取:

cpp 复制代码
/*		 
================================================================================
描述 : 时间读取
输入 : 
输出 :  
================================================================================
*/
void drv_ds1302_get_time(Ds1302RtcStruct *rtc_initpara)
{
	if(rtc_initpara==NULL)
		return;
	rtc_initpara->rtc_second=drv_ds1302_read(0x81);
	rtc_initpara->rtc_minute=drv_ds1302_read(0x83);
	rtc_initpara->rtc_hour=drv_ds1302_read(0x85);
	rtc_initpara->rtc_date=drv_ds1302_read(0x87);
	rtc_initpara->rtc_month=drv_ds1302_read(0x89);
	rtc_initpara->rtc_year=drv_ds1302_read(0x8D);
//	printf("drv_ds1302_get_time=20%02x-%02x-%02x  %02x:%02x:%02x\n", rtc_initpara->rtc_year, rtc_initpara->rtc_month, rtc_initpara->rtc_date,
//																																rtc_initpara->rtc_hour, rtc_initpara->rtc_minute, rtc_initpara->rtc_second	);	
}

设置类的都要先解锁写保护才能进行相应操作。

整体来讲,DS1302用起来不复杂,时序有搞清楚,寄存器弄对来就没问题了。

代码链接:https://download.csdn.net/download/ypp240124016/89117651

本项目的交流QQ群:701889554

相关推荐
jkyy20141 小时前
汽车×大健康融合:智慧健康监测座舱成车企新赛道核心布局
大数据·人工智能·物联网·汽车·健康医疗
zy135380675732 小时前
12V输入5V/2A输出升降压芯片AH4002
科技·单片机·物联网·fpga开发·硬件工程·智能电视
绿蕉2 小时前
蜂窝物联网:医疗设备的“全球生命线“,让健康监护无处不在
物联网
华普微HOPERF3 小时前
数字隔离器,如何拉满工业网关的电气安全性能与抗干扰能力?
物联网·安全·数字隔离器
创思通信3 小时前
STM32L151RCT6 BC20 采集温湿度DHT11 采集GPS定位 和ADC发送到最新版本ONENET物联网开放平台
stm32·嵌入式硬件·物联网
MINGNUO明诺3 小时前
科技赋能洁净生活 北京龙威物业引入智能清洁设备升级服务品质
物联网
兆龙电子单片机设计4 小时前
【STM32项目开源】STM32单片机充电桩安全监测系统
stm32·单片机·物联网·开源·毕业设计
TDengine (老段)20 小时前
TDengine Python 连接器进阶指南
大数据·数据库·python·物联网·时序数据库·tdengine·涛思数据
没有故事的Zhang同学1 天前
03-📝物联网组网 | 蓝牙通信: 经典蓝牙与低功耗Ble通信、iBeacon技术
物联网
御控工业物联网1 天前
御控远程监控智慧运维系统
运维·物联网·边缘计算·数据采集·远程监控·mqtt协议·工业智能网关