STM32F103和DS1302时钟
- DS1302模块讲解
- 源文件演示
- 源文件下载链接
最近在写了一些关于STM32F103C8T6对于模块的时候方面的代码的整合,想把之前用到的代码全部都整合成一个一个的例程来,以后要用直接拖进来改头文件的引脚口就好了。现在也开启第一章关于DS1302模块的使用的来。
DS1302模块讲解
DS1302时钟模块是时钟模块主要的实现方法简单来说就是通过协议往DS1302芯片内的存储空间里面写入当前时间。
然后模块上面自带晶振计数,所以可以实现模块里面的时钟一直在走,然后用一个纽扣电池为整个模块供电,即使单片机重启或者关闭电源还是有纽扣电池提供电力让其继续计时。
读取数据的时候只需要根据协议的方式读取芯片内计时的时间即可了。
芯片的引脚说明
VCC1和VCC2:都是电源脚只是供电的方式问题
X1和X2:晶振电路的引脚用来根据晶振的次数来记录时间
SCLK:单片机和DS1302芯片的时钟线
RST:从低到高的一个上升沿开始允许写数据,拉低RST端则禁止读写数据
I/O(DATA):数据线用来数据的读取或者写入
GND:地线
源文件演示
源文件下载链接
https://download.csdn.net/download/qq_45488746/85280373
贴点演示代码吧,大家关注比较多的也是怎么去实现需要的功能。
主函数
#include "sys.h"
#include "led.h"
#include "ds1302.h"
#include "usart.h"
#include "delay.h"#define Printf_EN 1
/*系统功能:RTC时钟时间:2022/05/04设备:STM32F103C8T6、DS1302时钟、USB转TTL接线:USB转TTLPA9 ---- RXPA10---- TXDS1302:PA5----RSTPA6----DATAPA7----SCK*/
extern struct TIMEData TimeData;int main(void)
{ u8 i = 0;delay_init(); //延时函数初始化 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 LED_Init(); //LED端口初始化uart_init(115200);DS1302_Init(); //引脚口初始化
// DS1302_WriteTime(); //第一次向DS1302芯片写入时间printf("DS1302初始化成功\r\n");while(1) { i++;if(i == 200){i=0;LED_Pout = !LED_Pout;//系通功能运行DS1302_GetTime();#if Printf_ENprintf("时间:%d-%d-%d %d:%d:%d %d \r\n",TimeData.year,TimeData.month,TimeData.day,TimeData.hour,TimeData.minute,TimeData.second,TimeData.week); #endif}delay_ms(5);} }
部分ds1302.c,主要是根据DS1302芯片的通信方式用代码去实现,代码中有部分是参考别人的代码去实现的,当然不可能重头造轮子啦。
//DS1302初始化函数
void DS1302_Init()
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = RST_Pin; //RSTGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_Init(RST_GPIO, &GPIO_InitStructure); //初始化GPIO_ResetBits(RST_GPIO,RST_Pin); GPIO_InitStructure.GPIO_Pin = SCLK_Pin; //SCLKGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_Init(SCLK_GPIO, &GPIO_InitStructure); //初始化GPIO_ResetBits(SCLK_GPIO,SCLK_Pin);
}//向DS1302写入一字节数据
void DS1302_WriteByte(u8 addr,u8 data)
{u8 i;DS1302_RST=0; //禁止数据传输 !!!这条很重要DS1302_CLK=0; //确保写数据前SCLK为低电平DS1302_RST=1; //启动DS1302总线 DS1302_OutPut_Mode();addr=addr&0xFE; //最低位置零,寄存器0位为0时写,为1时读for(i=0;i<8;i++) //写入目标地址:addr{if (addr&0x01) DS1302_OUT=1;else DS1302_OUT=0;DS1302_CLK=1; //时钟上升沿写入数据DS1302_CLK=0;addr=addr>>1;} for (i=0;i<8;i++) //写入数据:data{if(data&0x01) DS1302_OUT=1;else DS1302_OUT=0;DS1302_CLK=1; //时钟上升沿写入数据DS1302_CLK=0;data = data >> 1;}DS1302_CLK=1; // 将时钟电平置于高电平状态 ,处于已知状态DS1302_RST=0; //停止DS1302总线
}//从DS1302读出一字节数据
u8 DS1302_ReadByte(u8 addr)
{u8 i,temp; DS1302_RST=0; //这条很重要DS1302_CLK=0; //先将SCLK置低电平,确保写数居前SCLK被拉低DS1302_RST=1; //启动DS1302总线DS1302_OutPut_Mode();//写入目标地址:addraddr=addr|0x01; //最低位置高,寄存器0位为0时写,为1时读for(i=0;i<8;i++) {if (addr&0x01) DS1302_OUT=1;else DS1302_OUT=0;DS1302_CLK=1; //写数据DS1302_CLK=0;addr = addr >> 1;} //从DS1302读出数据:tempDS1302_InPut_Mode();for(i=0;i<8;i++){temp=temp>>1;if (DS1302_IN) temp|=0x80;else temp&=0x7F;DS1302_CLK=1;DS1302_CLK=0;} DS1302_CLK=1; //将时钟电平置于已知状态DS1302_RST=0; //停止DS1302总线return temp;
}
//向DS1302写入时钟数据,用于时间校准修改
void DS1302_WriteTime()
{DS1302_WriteByte(DS1302_CONTROL_ADDR,0x00); //关闭写保护 DS1302_WriteByte(DS1302_SEC_ADDR,0x80); //暂停时钟 //DS1302_WriteByte(DS1302_CHARGER_ADDR,0xa9); //涓流充电 DS1302_WriteByte(DS1302_YEAR_ADDR,time_buf[1]); //年 DS1302_WriteByte(DS1302_MONTH_ADDR,time_buf[2]); //月 DS1302_WriteByte(DS1302_DAY_ADDR,time_buf[3]); //日 DS1302_WriteByte(DS1302_HOUR_ADDR,time_buf[4]); //时 DS1302_WriteByte(DS1302_MIN_ADDR,time_buf[5]); //分DS1302_WriteByte(DS1302_SEC_ADDR,time_buf[6]); //秒DS1302_WriteByte(DS1302_WEEK_ADDR,time_buf[7]); //周
// DS1302_WriteByte(DS1302_CHARGER_ADDR,0xA5); //打开充电功能 选择2K电阻充电方式DS1302_WriteByte(DS1302_CONTROL_ADDR,0x80); //打开写保护
}
//从DS1302读出时钟数据
void DS1302_ReadTime(void)
{time_buf[1]=DS1302_ReadByte(DS1302_YEAR_ADDR); //年 time_buf[2]=DS1302_ReadByte(DS1302_MONTH_ADDR); //月 time_buf[3]=DS1302_ReadByte(DS1302_DAY_ADDR); //日 time_buf[4]=DS1302_ReadByte(DS1302_HOUR_ADDR); //时 time_buf[5]=DS1302_ReadByte(DS1302_MIN_ADDR); //分 time_buf[6]=(DS1302_ReadByte(DS1302_SEC_ADDR))&0x7f; //秒,屏蔽秒的第7位,避免超出59time_buf[7]=DS1302_ReadByte(DS1302_WEEK_ADDR); //周
}//DS1302获取完时间后进行数据的计算
void DS1302_GetTime()
{ DS1302_ReadTime(); //读取时间TimeData.year =(time_buf[0]>>4)*1000 +(time_buf[0]&0x0F)*100+(time_buf[1]>>4)*10+(time_buf[1]&0x0F); //计算年份TimeData.month =(time_buf[2]>>4)*10 +(time_buf[2]&0x0F); //计算月份TimeData.day =(time_buf[3]>>4)*10 +(time_buf[3]&0x0F); //计算日期TimeData.hour =(time_buf[4]>>4)*10 +(time_buf[4]&0x0F); //计算小时TimeData.minute =(time_buf[5]>>4)*10 +(time_buf[5]&0x0F); //计算分钟TimeData.second =(time_buf[6]>>4)*10 +(time_buf[6]&0x0F); //计算秒钟TimeData.week =(time_buf[7]&0x0F); //计算星期
}
ds1302.h
主要也都是根据DS1302芯片资料上面的芯片内部地址做一些宏定义,方便操作
//DS1302地址定义
#define DS1302_SEC_ADDR 0x80 //秒数据地址
#define DS1302_MIN_ADDR 0x82 //分数据地址
#define DS1302_HOUR_ADDR 0x84 //时数据地址
#define DS1302_DAY_ADDR 0x86 //日数据地址
#define DS1302_MONTH_ADDR 0x88 //月数据地址
#define DS1302_WEEK_ADDR 0x8a //星期数据地址
#define DS1302_YEAR_ADDR 0x8c //年数据地址
#define DS1302_CONTROL_ADDR 0x8e //控制数据地址
#define DS1302_CHARGER_ADDR 0x90 //充电功能地址
#define DS1302_CLKBURST_ADDR 0xbe#define DS1302_IN PAin(6)
#define DS1302_OUT PAout(6)
#define DS1302_RST PAout(5)
#define DS1302_CLK PAout(7)#define RST_GPIO GPIOA
#define RST_Pin GPIO_Pin_5#define SCLK_GPIO GPIOA
#define SCLK_Pin GPIO_Pin_7#define DATA_GPIO GPIOA
#define DATA_Pin GPIO_Pin_6struct TIMEData
{u16 year;u8 month;u8 day;u8 hour;u8 minute;u8 second;u8 week;
};
extern struct TIMEData TimeData;
extern u8 readtime[15];
void DS1302_Init(void);
void DS1302_WriteByte(u8 addr,u8 data);
u8 DS1302_ReadByte(u8 addr);
void DS1302_WriteTime(void);
void DS1302_ReadTime(void);
void DS1302_GetTime(void);