物联网实战--驱动篇之(七)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

相关推荐
2401_882727572 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
畅联云平台5 小时前
美畅物联丨智能分析,安全管控:视频汇聚平台助力智慧工地建设
人工智能·物联网
东芝、铠侠总代136100683937 小时前
浅谈TLP184小型平面光耦
单片机·嵌入式硬件·物联网·平面
BY—-组态8 小时前
web组态软件
前端·物联网·工业互联网·web组态·组态
Vodka~11 小时前
物联网——UNIX时间戳、BKP备份寄存器、RTC时钟
物联网·实时音视频
电子科技圈12 小时前
XMOS携手合作伙伴晓龙国际联合推出集成了ASRC等功能的多通道音频板
科技·嵌入式硬件·mcu·物联网·音视频·iot
IT枫斗者13 小时前
如何解决Java EasyExcel 导出报内存溢出
java·服务器·开发语言·网络·分布式·物联网
7yewh14 小时前
嵌入式硬件杂谈(四)-高速板PCB设计 高速信号全面讲解 蛇形线 等长线 差分对 阻抗对
驱动开发·嵌入式硬件·mcu·物联网·硬件工程·pcb工艺·精益工程
南门听露15 小时前
适用于资源受限IoT系统的非对称语义图像压缩技术
深度学习·神经网络·物联网
启明云端wireless-tag15 小时前
乐鑫ESP32物联网方案,设备人机交互技术应用,启明云端乐鑫代理商
物联网·esp32·无线通信·乐鑫