DS1302ZN+ 实时时钟芯片驱动
正文
最近使用了DS1302ZN+ 实时时钟芯片,浅浅分享一下我写的驱动。代码也是从其他的博主那改过来的,只是将格式和一些小细节优化了一下。具体的原理懒得写了,其他博主那有很详细的。
说明
使用的平台的STM32F103,用的标准库,用IO口模拟通信时序与DS1302进行通讯。
1、如果你同样是准备移植到STM32上,并且准备使用标准库,只需要在H文件中修改对应的引脚,然后对接一下C文件中的delay_us、delay_ms这两个函数即可。
2、如果你准备移植到别的地方,那在1的基础上你还可能还需要更改一下 ds1302_gpio_init 、 ds1032_DATAOUT_init、ds1032_DATAINPUT_init 的引脚初始化;甚至H文件中下图所示的部分也需要对应修改:
3、在移植的时候C文件中的这个地方注意一下,读引脚电平的函数也需要自己对应修改,而且不容易发现,是一个小坑。
好嘞,该文章仅供参考,不严谨请多包涵。上代码:
H文件
#ifndef __DS1302_H
#define __DS1302_H/************管脚配置**************/
// CE 配置
#define DS1302_CE_RCC RCC_APB2Periph_GPIOA
#define DS1302_CE_PORT GPIOA
#define DS1302_CE_PIN GPIO_Pin_5
// SCLK 配置
#define DS1302_SCLK_RCC RCC_APB2Periph_GPIOA
#define DS1302_SCLK_PORT GPIOA
#define DS1302_SCLK_PIN GPIO_Pin_7
// I/O 配置
#define DS1302_DATA_RCC RCC_APB2Periph_GPIOA
#define DS1302_DATA_PORT GPIOA
#define DS1302_DATA_PIN GPIO_Pin_6#define CE_L GPIO_ResetBits(DS1302_CE_PORT,DS1302_CE_PIN) //拉低使能位
#define CE_H GPIO_SetBits(DS1302_CE_PORT,DS1302_CE_PIN) //拉高使能位
#define SCLK_L GPIO_ResetBits(DS1302_SCLK_PORT,DS1302_SCLK_PIN) //拉低时钟线
#define SCLK_H GPIO_SetBits(DS1302_SCLK_PORT,DS1302_SCLK_PIN) //拉高时钟线
#define DATA_L GPIO_ResetBits(DS1302_DATA_PORT,DS1302_DATA_PIN) //拉低数据线
#define DATA_H GPIO_SetBits(DS1302_DATA_PORT,DS1302_DATA_PIN) //拉高数据线//创建TIMEData数据结构方便存储时间日期数据
typedef struct
{uint16_t year;uint8_t month;uint8_t day;uint8_t hour;uint8_t minute;uint8_t second;uint8_t week;
}TIMEData;extern TIMEData TimeData; //全局变量extern void ds1032_init(void); //ds1302初始化函数
extern void ds1302_gpio_init(void); //ds1302端口初始化
extern TIMEData ds1032_read_realTime(void); //获取当前时间
extern void ds1302_wirte_rig(uint8_t address,uint8_t data);//向指定寄存器写一字节数据
extern uint8_t ds1302_read_rig(uint8_t address); //从指定寄存器读一字节数据#endif
C文件
#include "systick.h"
#include "stm32f10x.h"
#include "ds1302.h"TIMEData TimeData; //定义一个存放时间数据的变量TimeData/**********************************************************************************************************
* 函 数 名: ds1302_gpio_init
* 功能说明: 初始化DS1302的CE和SCLK引脚
* 形 参: 无
* 返 回 值: 无
**********************************************************************************************************/
void ds1302_gpio_init(void) //CE,SCLK端口初始化
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(DS1302_CE_RCC, ENABLE);GPIO_InitStructure.GPIO_Pin = DS1302_CE_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(DS1302_CE_PORT, &GPIO_InitStructure);GPIO_ResetBits(DS1302_CE_PORT,DS1302_CE_PIN); RCC_APB2PeriphClockCmd(DS1302_SCLK_RCC, ENABLE);GPIO_InitStructure.GPIO_Pin = DS1302_SCLK_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(DS1302_SCLK_PORT, &GPIO_InitStructure);GPIO_ResetBits(DS1302_SCLK_PORT,DS1302_SCLK_PIN);
}/**********************************************************************************************************
* 函 数 名: ds1032_DATAOUT_init
* 功能说明: 将DS1302的数据引脚配置为输出
* 形 参: 无
* 返 回 值: 无
**********************************************************************************************************/
void ds1032_DATAOUT_init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(DS1302_DATA_RCC, ENABLE);GPIO_InitStructure.GPIO_Pin = DS1302_DATA_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(DS1302_DATA_PORT, &GPIO_InitStructure);GPIO_ResetBits(DS1302_DATA_PORT,DS1302_DATA_PIN);
}/**********************************************************************************************************
* 函 数 名: ds1032_DATAINPUT_init
* 功能说明: 将DS1302的数据引脚配置为输入
* 形 参: 无
* 返 回 值: 无
* 注 : 无
**********************************************************************************************************/
void ds1032_DATAINPUT_init(void)//配置双向I/O端口为输入态
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(DS1302_DATA_RCC, ENABLE);GPIO_InitStructure.GPIO_Pin = DS1302_DATA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(DS1302_DATA_PORT, &GPIO_InitStructure);
}/**********************************************************************************************************
* 函 数 名: ds1302_write_onebyte
* 功能说明: 向DS1302发送一字节数据
* 形 参: data 要发送的数据
* 返 回 值: 无
* 注 : 被读写DS1302寄存器的函数调用
**********************************************************************************************************/
void ds1302_write_onebyte(uint8_t data)
{ds1032_DATAOUT_init(); //配置数据引脚为输出uint8_t count=0;SCLK_L;for(count=0;count<8;count++){ SCLK_L; //拉高时钟线if(data&0x01) DATA_H;else DATA_L; SCLK_H; //拉高时钟线,发送数据data>>=1;}
}/**********************************************************************************************************
* 函 数 名: ds1302_wirte_rig
* 功能说明: 向指定寄存器地址写数据
* 形 参: address:要写的寄存器地址 data:要发送的数据
* 返 回 值: 无
**********************************************************************************************************/
void ds1302_wirte_rig(uint8_t address,uint8_t data)
{uint8_t temp1=address;uint8_t temp2=data;CE_L;SCLK_L;delay_us(1);CE_H;delay_us(2);ds1302_write_onebyte(temp1); //写地址ds1302_write_onebyte(temp2); //写数据CE_L;SCLK_L;delay_us(2);
}/**********************************************************************************************************
* 函 数 名: ds1302_read_rig
* 功能说明: 读取指定寄存器的一字节数据
* 形 参: address:要读的寄存器地址
* 返 回 值: 读到的数据
**********************************************************************************************************/
uint8_t ds1302_read_rig(uint8_t address)
{uint8_t temp3=address;uint8_t count=0;uint8_t return_data=0x00;CE_L;SCLK_L;delay_us(3);CE_H;delay_us(3);ds1302_write_onebyte(temp3);//写寄存器地址ds1032_DATAINPUT_init(); //配置数据引脚为输入delay_us(2);for(count=0;count<8;count++){delay_us(2); //使电平持续一段时间return_data>>=1; //将数据移位保存SCLK_H;delay_us(4); //使高电平持续一段时间SCLK_L;delay_us(14);//延时14us后再去读取电平,更加准确if(GPIO_ReadInputDataBit(DS1302_DATA_PORT,DS1302_DATA_PIN)) //读取数据引脚的电平return_data=return_data|0x80; //记录数据 }delay_us(2);CE_L;DATA_L;return return_data;
}/**********************************************************************************************************
* 函 数 名: ds1032_SetTime
* 功能说明: 更改DS1302的当前时间
* 形 参: year: 年份 mon: 月份 date: 日期 hours:小时 min:分钟 sec:秒钟 week:星期
* 返 回 值: 无
* 注 : 形参为(0x22,0x06,0x30,0x17,0x30,0x25,0x04) 即设置当前时间为 2022-06-30-17:30-25秒-星期四
**********************************************************************************************************/
void ds1032_SetTime(uint8_t year,uint8_t mon,uint8_t date,uint8_t hours,uint8_t min,uint8_t sec,uint8_t week)
{ds1302_wirte_rig(0x8e,0x00); //关闭写保护ds1302_wirte_rig(0x80,sec); //sec ds1302_wirte_rig(0x82,min); //min ds1302_wirte_rig(0x84,hours);//hours ds1302_wirte_rig(0x86,date); //date ds1302_wirte_rig(0x88,mon); //mon ds1302_wirte_rig(0x8a,week); //week ds1302_wirte_rig(0x8c,year); //year ds1302_wirte_rig(0x8e,0x80); //关闭写保护
}/**********************************************************************************************************
* 函 数 名: ds1032_read_time
* 功能说明: 读取当前的时间(BCD格式)
* 形 参: 无
* 返 回 值: 无
**********************************************************************************************************/
TIMEData ds1032_read_realTime(void)
{TIMEData time; //暂时保存时间数据uint8_t read_time[7]; //暂时保存BCD格式的时间数据 //读取BCD格式的时间数据read_time[0]=ds1302_read_rig(0x81);//读秒read_time[1]=ds1302_read_rig(0x83);//读分read_time[2]=ds1302_read_rig(0x85);//读时read_time[3]=ds1302_read_rig(0x87);//读日read_time[4]=ds1302_read_rig(0x89);//读月read_time[5]=ds1302_read_rig(0x8B);//读星期read_time[6]=ds1302_read_rig(0x8D);//读年 //BCD码转换为10进制time.second=(read_time[0]>>4)*10+(read_time[0]&0x0f);time.minute=((read_time[1]>>4)&(0x07))*10+(read_time[1]&0x0f);time.hour =(read_time[2]>>4)*10+(read_time[2]&0x0f);time.day =(read_time[3]>>4)*10+(read_time[3]&0x0f);time.month =(read_time[4]>>4)*10+(read_time[4]&0x0f);time.week =read_time[5];time.year =(read_time[6]>>4)*10+(read_time[6]&0x0f)+2000;return time;
}void ds1032_init(void)
{ds1302_gpio_init(); //初始化ds1302端口delay_ms(5); // ds1032_SetTime(0x22,0x06,0x30,0x17,0x30,0x25,0x04);//设置时间为:2022-06-30-17:30-25秒-星期四delay_ms(5);
}