DS1302/GC1302/1302系列时钟芯片驱动程序&注意事项&解析数据手册

开的这个专栏会一直记录自己用过的驱动,以及解析数据手册,有触摸芯片,RFID芯片,语音芯片,显示屏驱动,ADC,各种通讯模块等等,感兴趣的可以一起交流学习

源码查询该文章
专栏地址

一、简介

 概述

  DS1302 可慢速充电实时时钟芯片包含实时时钟/日历和 31 字节的非易失性静态 RAM。实时时钟/日历可对秒,分,时,日,周,月,和年进行计数,对于小于31 天的月,月末的日期自动进行调整,还具有闰年校正的功能。时钟可以采用 24 小时格式或带 AM(上午)/PM(下午)的 12 小时格式。31 字节的 RAM 可以用来临时保存一些重要数据。
  使用同步串行通信,简化了 DS1302 与微处理器的通信。与时钟/RAM 通信仅需 3 根线:
  (1)RST(复位)/又或者叫使能,
  (2)I/O(数据线),
  (3)SCLK(串行时钟)。
  数据可以以每次一个字节的单字节形式或多达 31 字节的多字节形式传输。
  DS1302能在非常低的功耗下工作,消耗小于 1µW 的功率便能保存数据和时钟信息。

 工作原理

  CE信号使能后,移位寄存器单元会在 SCLK 同步脉冲信号的控制下从 I/O 上串行接收 8 位指令字节,然后将 8 位指令字节进行串并转换并送至 ROM 指令译码单元。由 ROM 指令译码单元对 8 位指令字节进行译码,以决定内部寄存器的地址以及读写状态。然后在接下来的 SCLK 同步脉冲信号的控制下将 8 位数据写进或者读出相应的寄存器。数据传送也可以采用多字节方式,先将 8 位相应的指令字节写入,然后在连续的 SCLK 的脉冲信号同步下,将数据字节连续写入或读出日历/时钟寄存器(或者RAM 单元)。SCLK 脉冲的个数在单字节方式下为 8 加 8,在多字节方式下为 8 加最大可达到 248 的数。

二、硬件连接

引脚说明
VCC1备用电源(纽扣电池,掉电使用)
VCC2主电源(设备电池,正常使用)
SCLK时钟信号
I/O数据输入输出信号
CE使能信号(复位)
X1/X2晶振(不需要负载电容)
GND

在这里插入图片描述
 tips

  • 三个通信引脚内部都有下拉电阻
  • VCC1为备用电源,当VCC1大于VCC2的电压0.3V时会自动切换为备用电源。(一般VCC2是恒压源,因此可认为VCC2(即设备电源)断电时自动切换使用VCC1)
  • 内部有6pf负载电容,故只需要合适的32.768khz晶振即可,无需增加外部负载电容。
  • CE高电平来启动所有的数据传送。CE低电平所有的数据传送中止,且 I/O
    引脚变为高阻抗状态。

三、驱动程序

/* 一些宏 */
#define XX1302_DELAY()									delay_us(5)
#define XX1302_WP_EN()									XX1302_WriteByte(CMD_W_CTRL,0x80)		//使能写保护
#define XX1302_WP_DISEN()								XX1302_WriteByte(CMD_W_CTRL,0x00)		//关闭写保护

 1、引脚配置&初始化

/*******  XX1302(RTC)  *******/
/* 数据XX1302_SDA 芯片内部下拉*/
#define XX1302_SDA_PORT								GPIOA
#define XX1302_SDA_PIN								GPIO_PIN_4
#define XX1302_SDA_CLK								RCC_APB2_PERIPH_GPIOA

#define XX1302_SDA_OUT_PP()							outputIO_CFG(XX1302_SDA_PORT,XX1302_SDA_PIN,IO_OUT_PP)
#define XX1302_SDA_OUT_H()							GPIO_SetBits(XX1302_SDA_PORT, XX1302_SDA_PIN)
#define XX1302_SDA_OUT_L()							GPIO_ResetBits(XX1302_SDA_PORT, XX1302_SDA_PIN)

#define XX1302_SDA_IN_NP()							inputIO_CFG(XX1302_SDA_PORT,XX1302_SDA_PIN,IO_IN_NP)
#define XX1302_SDA_READ()							GPIO_ReadInputDataBit(XX1302_SDA_PORT,XX1302_SDA_PIN)

/* 时钟XX1302_SCL 芯片内部下拉*/
#define XX1302_SCL_PORT								GPIOA
#define XX1302_SCL_PIN								GPIO_PIN_3
#define XX1302_SCL_CLK								RCC_APB2_PERIPH_GPIOA

#define XX1302_SCL_OUT_PP()							outputIO_CFG(XX1302_SCL_PORT,XX1302_SCL_PIN,IO_OUT_PP)
#define XX1302_SCL_OUT_H()							GPIO_SetBits(XX1302_SCL_PORT, XX1302_SCL_PIN)
#define XX1302_SCL_OUT_L()							GPIO_ResetBits(XX1302_SCL_PORT, XX1302_SCL_PIN)

/* 使能XX1302_EN 芯片内部下拉*/
#define XX1302_EN_PORT								GPIOA
#define XX1302_EN_PIN								GPIO_PIN_5
#define XX1302_EN_CLK								RCC_APB2_PERIPH_GPIOA

#define XX1302_EN_OUT_PP()							outputIO_CFG(XX1302_EN_PORT,XX1302_EN_PIN,IO_OUT_PP)
#define XX1302_EN_OUT_H()							GPIO_SetBits(XX1302_EN_PORT, XX1302_EN_PIN)
#define XX1302_EN_OUT_L()							GPIO_ResetBits(XX1302_EN_PORT, XX1302_EN_PIN)
/*******************************************
 * @brief  void XX1302Init()
 *   XX1302初始化
 * @param 
 * @return
 * @note 
 *******************************************/
void XX1302Init(void)
{
		XX1302_EN_OUT_PP();					//RTC1302使能配置
		XX1302_SCL_OUT_PP();				//SCL配置推挽输出
		XX1302_SDA_OUT_PP();				//SDA配置推挽输出	

		XX1302_EN_OUT_L();					//所有的数据传输终止,I/O引脚进入高阻抗状态。
		XX1302_SCL_OUT_L();					//使能前,SCL必须为0
}

 2、命令&寄存器

在这里插入图片描述
在这里插入图片描述后面使用时再展开讲

/* 命令和寄存器宏定义 */
/* LSB先行: 1,RAM/nCLK,A4,A3,A2,A1,A0,R/nW */
#define CMD_W_SEC							0x80//写秒寄存器 1000 0000
#define CMD_W_MIN							0x82//写分 1000 0010
#define CMD_W_HOUR							0x84//写小时 1000 0100
#define CMD_W_DAY                    		0x86//写日 1000 0110
#define CMD_W_MONTH                  		0x88//写月 1000 1000
#define CMD_W_WEEK                   		0x8A//写星期 1000 1010
#define CMD_W_YEAR                   		0x8C//写年 1000 1100
#define CMD_W_CTRL							0x8E//写控制寄存器

#define CMD_R_SEC							0x81//读秒寄存器 1000 0001
#define CMD_R_MIN							0x83//读分 1000 0011
#define CMD_R_HOUR							0x85//读小时 1000 0101
#define CMD_R_DAY                    		0x87//读日 1000 0111
#define CMD_R_MONTH                  		0x89//读月 1000 1001
#define CMD_R_WEEK                   		0x8B//读星期 1000 1011
#define CMD_R_YEAR                   		0x8D//读年 1000 1101

 3、写入一个字节

在这里插入图片描述在这里插入图片描述

(1)拉高使能脚开启数据传输功能;
(2)SDA脚配置为输出;
(3)SCLK上升沿时,数据位有效,因此先将SDA脚置位(LSB先行),再拉高SCLK,然后延时后重新拉低SCLK,此为一个时序;
(4)右移数据切换最低位;
(5)8个时序写入一字节;
(6)使用时先写入命令,再写入数据,两者同为8位();
(7)结束时拉低使能脚终止数据传输;

/*******************************************
 * @brief  void XX1302_WriteByte()
 *   XX1302写入单字节数据
 * @param 
 * @return
 * @note 
 *******************************************/
static void XX1302_WriteByte(u8 cmd,u8 data){
		u8 i;
		XX1302_EN_OUT_H();								//启动数据传输
		XX1302_SDA_OUT_PP();							
		XX1302_SCL_OUT_L();
	
		for(i=0;i<8;i++){
				if(cmd&0x01)										
						XX1302_SDA_OUT_H();
				else
						XX1302_SDA_OUT_L();
				cmd>>=1;
				XX1302_DELAY();
				XX1302_SCL_OUT_H();
				XX1302_DELAY();
				XX1302_SCL_OUT_L();
		}
		for(i=0;i<8;i++){
				if(data&0x01)										
						XX1302_SDA_OUT_H();
				else
						XX1302_SDA_OUT_L();
				data>>=1;
				XX1302_DELAY();
				XX1302_SCL_OUT_H();
				XX1302_DELAY();
				XX1302_SCL_OUT_L();
		}
		XX1302_EN_OUT_L();					//所有的数据传输终止,I/O引脚进入高阻抗状态。
}

 4、读出一个字节

在这里插入图片描述在这里插入图片描述

注意上图读出时序和写入时的区别,读出数据时是在8个写命令周期后,再在下降沿读数据;

(1)拉高使能脚开启数据传输功能;
(2)SDA脚配置为输出;
(3)照写入数据的方式写入命令;
(4)注意紧跟命令写入的最后一个上升沿的下一个下降沿就开始输出数据了,因此有效的一共只有15个时序(不同于写入的16个时序)
(5)切换SDA脚配置为输入
(6)要在下降沿后读数据(LSB先输出)下降沿后增加延时以保读数稳定;
(7)8个下降沿后读完数据;
(8)结束时拉低使能脚终止数据传输;

/*******************************************
 * @brief  u8 XX1302_ReadByte()
 *   XX1302读出单字节数据
 * @param 
 * @return
 * @note 
 *******************************************/
static u8 XX1302_ReadByte(u8 cmd){
		u8 i;
		u8 data = 0x00;
		XX1302_EN_OUT_H();								//启动数据传输
		XX1302_SDA_OUT_PP();							
		XX1302_SCL_OUT_L();
	
		for(i=0;i<8;i++){
				if(cmd&0x01)										
						XX1302_SDA_OUT_H();
				else
						XX1302_SDA_OUT_L();
				cmd>>=1;
				XX1302_DELAY();
				XX1302_SCL_OUT_H();
				XX1302_DELAY();
				XX1302_SCL_OUT_L();
		}
		XX1302_SDA_IN_NP();								//切换为输入
		for(i=0;i<8;i++){				
				XX1302_SCL_OUT_L();
				XX1302_DELAY();
				if(XX1302_SDA_READ())										
						data|=0x80;								//最高位置1
				else
						data&=0x7F;								//置0
				if(i<7)				
						data>>=1;									//右移
				XX1302_SCL_OUT_H();
				XX1302_DELAY();
		}
		XX1302_SCL_OUT_L();
		XX1302_EN_OUT_L();					//所有的数据传输终止,I/O引脚进入高阻抗状态。
		return data;
}

 5、其他应用函数

 BCD转换

存储在时钟寄存器中的数据是2-10BCD码,因此其实读出的时候用16进制即可,如下代码。

 写入默认时间

/*******************************************
 * @brief  void XX1302_WriteDefaultTime(void)
 *   写入默认时间
 * @param 
 * @return
 * @note 年 月 日 时 分
 *******************************************/
void XX1302_WriteDefaultTime()
{
		XX1302_WP_DISEN();					//关闭写保护
	
		XX1302_WriteByte(CMD_W_YEAR,0x23);				//2023
		XX1302_WriteByte(CMD_W_MONTH,0x03);				//03
		XX1302_WriteByte(CMD_W_DAY,0x16);				//16
		XX1302_WriteByte(CMD_W_HOUR,0x09);				//09
		XX1302_WriteByte(CMD_W_MIN,0x21);				//21
		XX1302_WriteByte(CMD_W_SEC,0x00);				//00
	
		XX1302_WP_EN();							//使能写保护
}

注意

  • 写保护仅在写入时钟或者RAM时要关闭,因此写入时间前要关闭,但是读出时间时不用,因为读出时虽然写入命令,但没有写入时钟。

  • 小时寄存器的位 7 定义为 12 或 24 小时方式选择位。当它为1时,选择 12 小时方式,在 12 小时方式下,位 5 是 AM/PM 位,此位为1表示 PM。在 24 小时方式下,位 5 是第 2 个 10 小时位(20-23时)。
    在这里插入图片描述

  • 秒寄存器的位 7 定义为时钟暂停位。当此位设置为逻辑 1 时,时钟振荡器停止,DS1302 被置入低功率的备份方式,其电源消耗小于 100 纳安(nanoamp)。当把此位写成逻辑 0 时,时钟将启动。

 读出时间

/*******************************************
 * @brief  void XX1302_readTime(u8 *addr)
 *   读出时间到数组
 * @param 
 * @return
 * @note 年 月 日 时 分 秒
 *******************************************/
void XX1302_readTime(u8 *addr)
{		
		addr[0] = XX1302_ReadByte(CMD_R_YEAR);
		addr[1] = XX1302_ReadByte(CMD_R_MONTH);
		addr[2] = XX1302_ReadByte(CMD_R_DAY);
		addr[3] = XX1302_ReadByte(CMD_R_HOUR);
		addr[4] = XX1302_ReadByte(CMD_R_MIN);
		addr[5] = XX1302_ReadByte(CMD_R_SEC);
}

 main.c

/* 读出的时间的数组 年月日时分秒*/
u8 readTimeArr[6] = {0x22,0x10,0x02,0x06,0x06,0x06};

void main()
{
		ALL_GPIO_RCC_EN(ENABLE);			//GPIO/AFIO时钟开启
		delay_init(SYSCLK_M);				//含滴答定时器初始化
		IWDG_Init();									
		Print_USART_Init();					//打印串口配置
		XX1302Init();						//外部RTC初始化
		IWDG_ReloadKey();					//喂狗
		XX1302_WriteDefaultTime();			//写入默认时间
		while(1)
		{
			IWDG_ReloadKey();
			delay_ms(1000);
			XX1302_readTime(readTimeArr);
			printf("20%x年-%x月%x日-%x:%x:%x\n\r",readTimeArr[0],readTimeArr[1],readTimeArr[2],readTimeArr[3],readTimeArr[4],readTimeArr[5]);
		}
}

串口打印数据:
在这里插入图片描述

该芯片重点就是写入和读出一字节的程序,个中算法因人而异,以上程序皆为个人实际调试程序,MCU是国民技术的G030,和ST的架构很像。

本人调试过程出现的问题分享

  • 第一遍直接根据数据手册写代码的时候,出现了一点小问题,导致读出的数据全是0,后来接上逻辑分析仪发现整个程序只有128个脉冲(即8个写入周期),那很显然就只跑完了XX1302_WriteDefaultTime,而XX1302_readTime函数不知什么情况没有运行或者说无效。但跑一遍流程发现不应该出现没运行的情况,因此将重点排查放在了XX1302_WriteDefaultTime的最后一句XX1302_WP_EN(); 上,很可能是写保护没有关掉,再看时序图,将高低电平解析发现,写入cmd的部分都是正常的(这里要将前8个脉冲的位数据反序排列,因为是LSB先行),但是data部分全部都是低电平,因此去查XX1302_WriteBytedata部分,发现data>>=1;写成了cmd>>=1;(因为两段逻辑一样,直接拷贝只改了上面的cmd),修改后,先是正常打印出时间,后来复位后就又全是0了。重新烧录依旧如此(短暂的正常)。
  • 再次查时序可以发现:在读数据时,下降沿和数据位的上升沿完全重叠,如下图。因此可能就导致读出的都是0,解决方法就是调整XX1302_ReadByte函数后半段读数据的程序,在制造下降沿的时候增加延时,以稳定的读取到数据电平。再重新烧录,一切正常,不管断电还是复位。
  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Python aip是指使用Python语言进行人工智能和图像处理的库。根据引用,在创建一个py文件后,可以通过输入&quot;from aip import AipFace&quot;来引入aip库。该库可以用于人脸识别和人脸属性分析等功能。&lt;span class=&quot;em&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;em&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;em&quot;&gt;3&lt;/span&gt; #### 引用[.reference_title] - *1* [Python学习记录 使用百度aip模块(API Python-SDK)实现人脸识别](https://blog.csdn.net/lx7820336/article/details/124591862)[target=&quot;_blank&quot; data-report-click={&quot;spm&quot;:&quot;1018.2226.3001.9630&quot;,&quot;extra&quot;:{&quot;utm_source&quot;:&quot;vip_chatgpt_common_search_pc_result&quot;,&quot;utm_medium&quot;:&quot;distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1&quot;}}] [.reference_item style=&quot;max-width: 33.333333333333336%&quot;] - *2* [Python库 | ardupy-aip-1.0.0.tar.gz](https://download.csdn.net/download/qq_38161040/85352878)[target=&quot;_blank&quot; data-report-click={&quot;spm&quot;:&quot;1018.2226.3001.9630&quot;,&quot;extra&quot;:{&quot;utm_source&quot;:&quot;vip_chatgpt_common_search_pc_result&quot;,&quot;utm_medium&quot;:&quot;distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1&quot;}}] [.reference_item style=&quot;max-width: 33.333333333333336%&quot;] - *3* [python numpy的常用aip方法及操作!免费开源!!!!](https://blog.csdn.net/luomuwuhuixue/article/details/105038726)[target=&quot;_blank&quot; data-report-click={&quot;spm&quot;:&quot;1018.2226.3001.9630&quot;,&quot;extra&quot;:{&quot;utm_source&quot;:&quot;vip_chatgpt_common_search_pc_result&quot;,&quot;utm_medium&quot;:&quot;distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1&quot;}}] [.reference_item style=&quot;max-width: 33.333333333333336%&quot;] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Diode丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值