基于STM32F103——DS1302日期时间+串口打印

最近终于又腾出时间写写学习笔记了,其实当时写是最好的,能对出的问题更深刻,现在呜呜呜。忘差不多了。主要的问题就是 STM32不像51 不需要设置输入输出模式,直接操作IO就行,但是STM32 得设置,就是因为对这个不了解 所以卡了一两天。STM32要根据不用应用状态设置不同的模式。

DS1302时钟模块相关介绍

基本介绍

概述

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

特点

在这里插入图片描述

各引脚功能

在这里插入图片描述
各引脚的功能:
Vcc1:主电源;Vcc2:备份电源。 当Vcc2>Vcc1+0.2V时,由Vcc2向DS1302供电,当Vcc2<Vcc1时,由Vcc1向DS1302供电。
SCLK: 串行时钟,输入,控制数据的输入与输出;
I/O: 三线接口时的双向数据线;
CE: 输入信号,在读和写的器件必须为高。该引脚有两个功能:1.开始控制字访问移位寄存器的控制逻辑;2.提供结束单字节或多字节数据传输的方法。

相关寄存器

有关日历、时间的寄存器共12个,其中有7个寄存器(读时81H——8DH,写时80H——8CH==)存放的数据格式是BCD码形式。如图所示
在这里插入图片描述
小时寄存器
位7用于定义DS1302是采用12小时模式还是24小时模式。高:12小时模式。在12小时模式时,位5 为1时,表示PM。在24小时模式时,为5是第二个10小时位。
秒寄存器
的就位7定义为时钟暂停标志(CH)。1:时钟振荡器停止,DS1302进入低功耗状态,当该位置为0时,时钟开始运行。
控制寄存器
的位7是写保护位(WP),其他7位均置0,对时钟和RAM进行写操作时,WP必须为0,也就是关闭写保护,当WP为1时,就是只读模式。
DS1302相关的RAM地址
DS1302中附加31字节静态RAM的地址如下图
在这里插入图片描述
DS1302的工作模式寄存器
所谓的突发模式(BURST模式)就是一次性传送多个字节的时钟信号和RAM数据。比如我可以一次性把时间和日期写入,也可以一次性的读出时间和日期。
在这里插入图片描述
通过对 31(十进制)位地址寻址(地址/命令位于 1 至 5=逻辑 1),可以把时钟/日历或 RAM 寄存器规定为多字节方式。如前所述,位 6 规定时钟或 RAM 而位 0 规定读或写。在时钟\日历寄存器中的地址 9 至 31或 RAM 寄存器中的地址 31 不能存储数据。在多字节方式中读或写从地址 0 的位 0 开始。当以多字节方式写时钟寄存器时必须按数据传送的次序写最先 8 个寄存器。意思就是写我们不是只有7个吗?时分秒、年月日、周一共七个 但是吧它得字节数为8 所有要写够8次。
但是,当以多字节方式写 RAM 时,为了传送数据不必写所有 31 个字节。不管是否写了全部 31 个字节,所写的每一个字节都将传送至 RAM。
在这里插入图片描述

DS1302充电寄存器
这个我没整过,全部复制手册的。哈哈

这个寄存器控制 DS1302 的慢速充电特性。图 4 的简化电路表示慢速充电器的基本组成。慢速充电选择(TCS)位(位 4-7)控制慢速充电器的选择。为了防止偶然的因素使之工作,只有 1010 模式才能使慢
速充电器工作,所有其它的模式将禁止慢速充电器。DS1302 上电时,慢速充电器被禁止。二极管选择(DS)位(位 2-3)选择是一个二极管还是两个二极管连接在 Vcc2 与 Vcc1 之间。如果 DS 为 01,那么选择一个二极管;如果 DS 为 10,则选择两个二极管。如果 DS 为 00 或 11,那么充电器被禁止,与 TCS 无关。RS 位(位0-1)选择连接在 Vcc2 与 Vcc1 之间的电阻。电阻选择(RS)位选择的电阻如下:
在这里插入图片描述
如果 RS 为 00,充电器被禁止,与 TCS 无关。
二极管和电阻的选择用户根据电池和超容量电容充电所需的最大电流决定。最大充电电流可以如下列
所说明的那样进行计算。假定 5V 系统电源加到 Vcc2 而超容量电容接至 Vcc1。再假设慢速充电器工作时在Vcc2 和 Vcc1 之间接有一个二极管和电阻 R1。因而最大电流可计算如下:
Imax =(5.0V-二极管压降)/R1
=(5.0V-0.7V)/2kΩ
= 2.2mA
显而易见,当超容量电容充电时,Vcc2 和 Vcc1 之间的电压减少,因而充电电流将会减小。

时序图

我们首先得给DS1302时钟模块写入时间和日期,然后呢这个时钟会自己走,我们之后只需要读取时间和日期即可。我们直接看时序图 编写代码
在这里插入图片描述

单字节写时序

数据输入
跟随在输入写命令字节的 8 个 SCLK 周期之后,在下 8 个 SCLK 周期的上升沿输入数据。如果有额外的SCLK 周期,它们将被忽略。输入从位 0 开始。
在这里插入图片描述
在这里插入图片描述

上面时序图是前8位是地址,后8位是数据。
我们根据上面的时序图 来编写 单字节写的一个函数
根据上面的编写一些代码

/******************************************************************
描述: DS1302 写一字节 函数
*******************************************************************/
void ds1302_write_byte(uint8_t addr_or_data)
{
    
    
	uint8_t i;
	DS1302_SET_OUT;		//DS1302设置成输出模式(推挽输出)
	for(i=0;i<8;i++)
	{
    
    
		if(addr_or_data & 0x01)		//从低位开始传输
		{
    
    
			DS1302_DAT_HIGH;		//DAT引脚拉高电平
		}
		else
		{
    
    
			DS1302_DAT_LOW;			//DAT引脚拉低电平
		}
		addr_or_data >>= 1;		//右移一位 为下一位写做准备
		DS1302_CLK_HIGH;		//拉高时钟表示已经发送 让对方读
		DS1302_CLK_LOW;			//拉低时钟准备继续放新的数据位
	}
}

/******************************************************************
描述: DS1302 写命令 函数
*******************************************************************/
void ds1302_write_cmd(uint8_t addr,uint8_t dat)
{
    
    
	DS1302_RST_LOW;		//RST拉低
	DS1302_CLK_LOW;		//时钟SCLK也拉低
	DS1302_RST_HIGH;	//准备开始写
	ds1302_write_byte(addr);	//写入要写的地址
	ds1302_write_byte(dat);		//写入地址的数据
	DS1302_RST_LOW;		//关闭 表示结束	
}

在这里插入图片描述
看上面的图,比如我想写入时 为18点 的写寄存器是84H 数据就是18点 但是DS1302存储格式为 BCD 码那就是 0x18。
那写入 时 为18点 的代码则是:

ds1302_write_cmd(0x84,0x18); //设置当前 时  为 18点

单字节读时序

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

/******************************************************************
描述: DS1302 读一字节 函数
*******************************************************************/
uint8_t ds1302_read_byte(void)
{
    
    
	uint8_t i;
	uint8_t dat = 0;//用于存放读取到的数据
	DS1302_SET_IN;	//这里DAT引脚要设置输入模式了(上拉输入) 浮空输入我试过也可以
	for(i=0;i<8;i++)
	{
    
    
		dat >>= 1;		//左移一次 低位开始 共有效左移7次
		if( GPIO_ReadInputDataBit(DS1302_DAT_PORT, DS1302_DAT_PIN) == SET)
		{
    
    
			dat = dat | 0x80;
		}
//		else
//		{
    
    
//			dat = dat & 0x7f;
//		}
		DS1302_CLK_HIGH;	//时钟拉高
		DS1302_CLK_LOW;		//时钟拉低 准备判断下一位数据
	}
	return dat;	//返回读取到的数据
}
/*DS1302读取数据函数*/
unsigned char ds1302_read_data(unsigned char addr)
{
    
    
	unsigned char data; //用于存放接收的数据
	RST = 0; //RST拉低
	SCLK = 0; //时钟SCLK也拉低
	RST = 1; //准备开始写	
	ds1302_write_byte(addr); 	//写入要读取的地址
	data = ds1302_read_byte(data); //读取地址的数据
	RST = 0;//关闭 表示结束
	
	return data;	//返回读取到的数据
}
/******************************************************************
描述: DS1302 读数据 函数
参数: addr:要读取数据的地址
*******************************************************************/
uint8_t ds1302_read_data(uint8_t addr)
{
    
    
	uint8_t dat = 0;		//用于存放读取到的数据
	DS1302_RST_LOW;			//RST拉低
	DS1302_CLK_LOW;			//CLK拉高
	DS1302_RST_HIGH;		//RST拉高 开始
	ds1302_write_byte(addr);	//先写要读取的数据的地址
	dat = ds1302_read_byte();	//然后进行读取数据
	DS1302_RST_LOW;			//RST拉低 结束
	return dat;	//返回读取到的数据
}

我们想读取时 里面时间 看看现在是几点 时 读寄存器是85H

time = ds1302_read_data(0x85);
/*time就是当前小时数据啦*/

在这里插入图片描述

写保护寄存器
当我们进行写的时候 比如写入当前的小时时间 当前的秒啊 啥的 就必须 WP位为0

例如:设置DS1302当前的小时为 12点 那么BCD码就是 0X12

/*在写入之前 我们必须要让 WP这位 置 0  
  也就是关闭写保护 寄存器0X8E*/
ds1302_write_cmd(0X8E,0X00);	//关闭写保护

/*设置DS1302时间*/
ds1302_write_cmd(0X84,0x12);	//设置当前小时为 12点

/*那我们再设置完DS1302时间我们一般就 WP 位置1
  开始写保护(只读模式)防止错改时间*/
ds1302_write_cmd(0X8E,0X80);	//开启写保护(只读模式)  

写保护寄存器的位 7 是写保护位。开始 7 位(位 0-6)置为零,在读操作时总是读出零。在对时钟或
功能 字节数 脉冲数
CLOCK 8 72
RAM 31 256
DS1302
RAM 进行写操作之前,位 7 必须为零。当它为高电平时,写保护位禁止对任何其它寄存器进行写操作。

时钟/日历多字节(Burst)方式

所谓的突发模式(BURST模式)就是一次性传送多个字节的时钟信号和RAM数据。比如我可以一次性把时间和日期写入,也可以一次性的读出时间和日期。
这里没写。。。。。略过0.0
在这里插入图片描述

BCD转十进制和十进制转BCD

由于DS1302是以BCD码存放的,那么如果我们读出来为了方便查看我这里是转十进制。
写入的时候 先十进制转BCD 再写入
读出的时候 先BCD转十进制 再运用
这样我们就可以一直是十进制啦。

十进制转BCD

比如 12 转成 BCD 也就是 0X12了对吧。
那么其实就是 取出十位 1 然后放到高4位 然后取出个位 2 放到低4位
就是十六进制 0X12 代码如下

/******************************************************************
描述: 十进制 转 BCD 函数 例如 12 转成 0X12
参数: dec:需要转换的十进制数据 转换的个数
*******************************************************************/
void dec_to_bcd(uint8_t *dec,uint8_t times)
{
    
    
	uint8_t i;
	for(i=0;i<times;i++)
	{
    
    
		dec[i] = ((dec[i]/10)<<4) | (dec[i]%10);
	}
}

/********************运用*************************/
//日期和时间定义22年5月27日14点22分0秒周五 		  
uint8_t ds1302_time[8] = {
    
    22,5,27,14,22,00,2};//年 月 日 时 分 秒 周

/*写入先转成BCD在写入*/
dec_to_bcd(ds1302_time,7);	//将时间十进制转成BCD格式 一共7个

BCD转十进制

/******************************************************************
描述: BCD 转 十进制 函数 例如 0X24 转成 24
参数: dec:需要转换的BCD数据 转换的个数
*******************************************************************/
void bcd_to_dec(uint8_t *bcd,uint8_t times)
{
    
    
	uint8_t i;
	for(i=0;i<times;i++)
	{
    
    
		bcd[i] = ((bcd[i]>>4)*10) + (bcd[i]&0x0f);
	}
}

/********************运用*************************/
uint8_t hour;	//存放小时
hour = ds1302_read_data(0X85);	//读取小时
bcd_to_dec(&hour ,1);			//将BCD码转成十进制 转1个

代码

部分代码呈现

ds1302.c

#include "ds1302.h"

//日期和 时间 定义 		  年 月 日 时 分 秒 周
uint8_t ds1302_time[8] = {
    
    22,4,19,14,22,00,0X02};

/******************************************************************
描述: DS1302 DAT设置成输入模式 函数
*******************************************************************/
void ds1302_set_input_mode(void)
{
    
    
	GPIO_InitTypeDef DS1302_Struction;				//定义结构体成员
	RCC_APB2PeriphClockCmd(DS1302_DAT_RCC, ENABLE);	//打开时钟
	
	DS1302_Struction.GPIO_Pin  = DS1302_DAT_PIN;		//引脚
	DS1302_Struction.GPIO_Mode = GPIO_Mode_IPU;			//上拉输入 或者 浮空输入 GPIO_Mode_IN_FLOATING 都可以
		
	GPIO_Init(DS1302_DAT_PORT,&DS1302_Struction);		//对成员进行初始化	
}


/******************************************************************
描述: DS1302 DAT设置成输出模式 函数
*******************************************************************/
void ds1302_set_output_mode(void)
{
    
    
	GPIO_InitTypeDef DS1302_Struction;				//定义结构体成员
	RCC_APB2PeriphClockCmd(DS1302_DAT_RCC, ENABLE);	//打开时钟
	
	DS1302_Struction.GPIO_Pin  = DS1302_DAT_PIN;		//引脚
	DS1302_Struction.GPIO_Mode = GPIO_Mode_Out_PP;		//推挽输出
	DS1302_Struction.GPIO_Speed = GPIO_Speed_50MHz;		//速率	

	GPIO_Init(DS1302_DAT_PORT,&DS1302_Struction);		//对成员进行初始化	
}


/******************************************************************
描述: DS1302 配置 函数
*******************************************************************/
void ds1302_config(void)
{
    
    
	GPIO_InitTypeDef DS1302_Struction;				//定义结构体成员

	RCC_APB2PeriphClockCmd(DS1302_CLK_RCC, ENABLE);	//打开时钟
	RCC_APB2PeriphClockCmd(DS1302_DAT_RCC, ENABLE);	//打开时钟
	RCC_APB2PeriphClockCmd(DS1302_RST_RCC, ENABLE);	//打开时钟

	//DS1302 CLK
	DS1302_Struction.GPIO_Pin  = DS1302_CLK_PIN;		//引脚
	DS1302_Struction.GPIO_Mode = GPIO_Mode_Out_PP;		//推挽输出	
	DS1302_Struction.GPIO_Speed = GPIO_Speed_50MHz; 	//50MHz
	GPIO_Init(DS1302_CLK_PORT,&DS1302_Struction);		//对成员进行初始化		
	//DS1302 DAT
	DS1302_Struction.GPIO_Pin  = DS1302_DAT_PIN;		//引脚
	DS1302_Struction.GPIO_Mode = GPIO_Mode_Out_PP;		//推挽输出	
	DS1302_Struction.GPIO_Speed = GPIO_Speed_50MHz; 	//50MHz
	GPIO_Init(DS1302_DAT_PORT,&DS1302_Struction);		//对成员进行初始化	
	//DS1302 RST
	DS1302_Struction.GPIO_Pin  = DS1302_RST_PIN;		//引脚
	DS1302_Struction.GPIO_Mode = GPIO_Mode_Out_PP;		//推挽输出	
	DS1302_Struction.GPIO_Speed = GPIO_Speed_50MHz; 	//50MHz
	GPIO_Init(DS1302_RST_PORT,&DS1302_Struction);		//对成员进行初始化	

}
/******************************************************************
描述: DS1302 写一字节 函数
*******************************************************************/
void ds1302_write_byte(uint8_t addr_or_data)
{
    
    
	uint8_t i;
	DS1302_SET_OUT;
	for(i=0;i<8;i++)
	{
    
    
		if(addr_or_data & 0x01)		//从低位开始传输
		{
    
    
			DS1302_DAT_HIGH;
		}
		else
		{
    
    
			DS1302_DAT_LOW;
		}
		addr_or_data >>= 1;		//右移一位
		DS1302_CLK_HIGH;		//拉高时钟表示已经发送
		DS1302_CLK_LOW;			//拉低时钟准备继续放新的数据位
	}
}

/******************************************************************
描述: DS1302 写命令 函数
*******************************************************************/
void ds1302_write_cmd(uint8_t addr,uint8_t dat)
{
    
    
	DS1302_RST_LOW;
	DS1302_CLK_LOW;
	DS1302_RST_HIGH;
	ds1302_write_byte(addr);
	ds1302_write_byte(dat);
	DS1302_RST_LOW;
}

/******************************************************************
描述: DS1302 读一字节 函数
*******************************************************************/
uint8_t ds1302_read_byte(void)
{
    
    
	uint8_t i;
	uint8_t dat = 0;
	DS1302_SET_IN;
	for(i=0;i<8;i++)
	{
    
    
		dat >>= 1;		//左移一次 低位开始 共有效左移7次
		if( GPIO_ReadInputDataBit(DS1302_DAT_PORT, DS1302_DAT_PIN) == SET)
		{
    
    
			dat = dat | 0x80;
		}
//		else
//		{
    
    
//			dat = dat & 0x7f;
//		}
		DS1302_CLK_HIGH;
		DS1302_CLK_LOW;
	}
	return dat;
}


/******************************************************************
描述: DS1302 读数据 函数
*******************************************************************/
uint8_t ds1302_read_data(uint8_t addr)
{
    
    
	uint8_t dat = 0;
	DS1302_RST_LOW;
	DS1302_CLK_LOW;
	DS1302_RST_HIGH;
	ds1302_write_byte(addr);
	dat = ds1302_read_byte();
	DS1302_RST_LOW;
	return dat;
}

/******************************************************************
描述: BCD 转 十进制 函数 例如 0X24 转成 24
*******************************************************************/
void bcd_to_dec(uint8_t *bcd,uint8_t times)
{
    
    
	uint8_t i;
	for(i=0;i<times;i++)
	{
    
    
		bcd[i] = ((bcd[i]>>4)*10) + (bcd[i]&0x0f);
	}
}

/******************************************************************
描述: 十进制 转 BCD 函数 例如 12 转成 0X12
*******************************************************************/
void dec_to_bcd(uint8_t *dec,uint8_t times)
{
    
    
	uint8_t i;
	for(i=0;i<times;i++)
	{
    
    
		dec[i] = ((dec[i]/10)<<4) | (dec[i]%10);
	}
}




/******************************************************************
描述: DS1302 初始化 日期和时间 函数
*******************************************************************/
void ds1302_init(void)
{
    
    
	ds1302_config();	//引脚配置

	dec_to_bcd(ds1302_time,7);	//十进制转BCD码
	ds1302_write_cmd(DS1302_WRITE_PROTECT,0x00); //关闭写保护	
	
	ds1302_write_cmd(DS1302_WRITE_YEAR,	ds1302_time[0]);	//年
	ds1302_write_cmd(DS1302_WRITE_MONTH,ds1302_time[1]);	//月
	ds1302_write_cmd(DS1302_WRITE_DAY,	ds1302_time[2]);  	//日
	ds1302_write_cmd(DS1302_WRITE_HOUR,	ds1302_time[3]);   	//时
	ds1302_write_cmd(DS1302_WRITE_MINUTE,ds1302_time[4]); 	//分
	ds1302_write_cmd(DS1302_WRITE_SECOND,ds1302_time[5]);  	//秒
	ds1302_write_cmd(DS1302_WRITE_WEEK,	ds1302_time[6]);  	//周	

	ds1302_write_cmd(DS1302_WRITE_PROTECT,0x80); //开启写保护	
}

/******************************************************************
描述: DS1302 读取 日期和时间 函数
*******************************************************************/
void ds1302_read(void)
{
    
    
	ds1302_time[0] = ds1302_read_data(DS1302_READ_YEAR);  //读取年
	ds1302_time[1] = ds1302_read_data(DS1302_READ_MONTH); //读取月
	ds1302_time[2] = ds1302_read_data(DS1302_READ_DAY);   //读取日
	ds1302_time[3] = ds1302_read_data(DS1302_READ_HOUR);  //读取时
	ds1302_time[4] = ds1302_read_data(DS1302_READ_MINUTE);//读取分
	ds1302_time[5] = ds1302_read_data(DS1302_READ_SECOND);//读取秒
	ds1302_time[6] = ds1302_read_data(DS1302_READ_WEEK);  //读取周

	bcd_to_dec(ds1302_time,7);	//BCD码转成十进制
}


ds1302.h

#ifndef __DS1302_H
#define __DS1302_H
#include "stm32f10x.h"

#define DS1302_CLK_RCC		RCC_APB2Periph_GPIOB		//时钟
#define DS1302_CLK_PORT		GPIOB						//端口
#define DS1302_CLK_PIN		GPIO_Pin_13					//引脚

#define DS1302_DAT_RCC		RCC_APB2Periph_GPIOB		//时钟
#define DS1302_DAT_PORT		GPIOB						//端口
#define DS1302_DAT_PIN		GPIO_Pin_14					//引脚

#define DS1302_RST_RCC		RCC_APB2Periph_GPIOB		//时钟
#define DS1302_RST_PORT		GPIOB						//端口
#define DS1302_RST_PIN		GPIO_Pin_15					//引脚


#define DS1302_CLK_HIGH		GPIO_SetBits(DS1302_CLK_PORT, DS1302_CLK_PIN)			//引脚输出高电平
#define DS1302_CLK_LOW		GPIO_ResetBits(DS1302_CLK_PORT, DS1302_CLK_PIN)			//引脚输出低电平

#define DS1302_DAT_HIGH		GPIO_SetBits(DS1302_DAT_PORT, DS1302_DAT_PIN)			//引脚输出高电平
#define DS1302_DAT_LOW		GPIO_ResetBits(DS1302_DAT_PORT, DS1302_DAT_PIN)			//引脚输出低电平

#define DS1302_RST_HIGH		GPIO_SetBits(DS1302_RST_PORT, DS1302_RST_PIN)			//引脚输出高电平
#define DS1302_RST_LOW		GPIO_ResetBits(DS1302_RST_PORT, DS1302_RST_PIN)			//引脚输出低电平

#define DS1302_SET_IN		ds1302_set_input_mode()							//设置输入模式
#define DS1302_SET_OUT 		ds1302_set_output_mode()						//设置输出模式		


/*读相关寄存器地址*/
#define DS1302_READ_SECOND 	0X81   	//秒
#define DS1302_READ_MINUTE 	0X83	//分
#define DS1302_READ_HOUR   	0X85	//时
#define DS1302_READ_DAY		0X87	//日
#define DS1302_READ_MONTH 	0X89	//月
#define DS1302_READ_WEEK 	0X8B	//周
#define DS1302_READ_YEAR 	0X8D	//年
//#define DS1302_READ_TIME 	0XBF	//读取全部时间

/*写相关寄存器地址*/
#define DS1302_WRITE_SECOND 0X80   	//秒
#define DS1302_WRITE_MINUTE 0X82	//分
#define DS1302_WRITE_HOUR   0X84	//时
#define DS1302_WRITE_DAY	0X86	//日
#define DS1302_WRITE_MONTH 	0X88	//月
#define DS1302_WRITE_WEEK 	0X8A	//周
#define DS1302_WRITE_YEAR 	0X8C	//年
#define DS1302_WRITE_PROTECT 0X8E	//保护
//#define DS1302_WRITE_TIME 	0XBE 	//写全部时间


extern uint8_t ds1302_time[8];	//存放日期和时间

void ds1302_write_byte(uint8_t addr_or_data);			//DS1302 写一字节 函数
void ds1302_write_cmd(uint8_t addr,uint8_t dat);		//DS1302 写命令	  函数
uint8_t ds1302_read_byte(void);							//DS1302 读一字节 函数
uint8_t ds1302_read_data(uint8_t addr);					//DS1302 写一字节 函数
void bcd_to_dec(uint8_t *bcd,uint8_t times);			//BCD 转 十进制 函数
void dec_to_bcd(uint8_t *dec,uint8_t times);			//十进制 转 BCD 函数
void ds1302_init(void);									//DS1302 初始化日期和时间 函数
void ds1302_read(void);									//DS1302 读取  日期和时间 函数

#endif

usart.c

/* 配置串口1 优先级 函数 */
static void NVIC_USART1_configuration(void)
{
    
    
	NVIC_InitTypeDef NVIC_initStruction;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);				//组
	NVIC_initStruction.NVIC_IRQChannel = USART1_IRQn;			//串口1中断
	NVIC_initStruction.NVIC_IRQChannelPreemptionPriority = 0;   //主优先级
	NVIC_initStruction.NVIC_IRQChannelSubPriority = 0;			//次优先级
	NVIC_initStruction.NVIC_IRQChannelCmd = ENABLE;				//使能
	NVIC_Init(&NVIC_initStruction);
}

/* 配置串口1 函数*/
void usart1_init(uint32_t baudRate)
{
    
    
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//打开GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	//打开串口1时钟
	
	GPIO_InitTypeDef GPIO_initStruction;
	USART_InitTypeDef USART_initStruction;

	/*配置GPIOA  TX */
	GPIO_initStruction.GPIO_Pin = USART1_TX; 		// TX
	GPIO_initStruction.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_initStruction.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_initStruction);
	
	/*配置GPIOA RX */
	GPIO_initStruction.GPIO_Pin = USART1_RX; 		// RX
	GPIO_initStruction.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
	GPIO_Init(GPIOA, &GPIO_initStruction);
	
	/*配置USART1 TX和RX */
	USART_initStruction.USART_BaudRate = baudRate;	//波特率
	USART_initStruction.USART_WordLength = USART_WordLength_8b; //8位有效数据位
	USART_initStruction.USART_StopBits = USART_StopBits_1;	//1个停止位
	USART_initStruction.USART_Parity = USART_Parity_No;		//无奇偶校验位
	USART_initStruction.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不硬件控制流
	USART_initStruction.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送 和 接收
	USART_Init(USART1, &USART_initStruction);
	
	NVIC_USART1_configuration();	//串口1中断优先级配置
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能接收中断
	USART_Cmd(USART1, ENABLE); //使能串口1
}



/*重定向C库函数printf到串口*/
int fputc(int ch, FILE *f)
{
    
    
	USART_SendData(USART1, (uint8_t)ch);; //发送一字节到串口
	while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送寄存器为空 证明发送完
	
	return ch;
}

/*重定向C库函数 scanf到串口*/
int fgetc(FILE *f)
{
    
    
	while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); //如果读数据寄存器非空
	return (int)USART_ReceiveData(USART1);
}


usart.h

#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include "stdio.h"

#define USART1_TX	GPIO_Pin_9
#define USART1_RX	GPIO_Pin_10

void usart1_init(uint32_t baudRate);


#endif



main.c

#include "stm32f10x.h"
#include "delay.h"
#include "ds1302.h"
#include "usart.h"
int  main()
{
    
    
	ds1302_init();			//DS1302初始化
	usart1_init(115200);	//串口1初始化
	while(1)
	{
    
    
		ds1302_read();	//读取日期和时间
		printf("20%d年%d月%d日 %d时%d分%d秒 星期%d\r\n",ds1302_time[0],ds1302_time[1],ds1302_time[2],ds1302_time[3],ds1302_time[4],ds1302_time[5],ds1302_time[6]);
		delay_ms(500);
	}  
}



项目展示

运行结果

在这里插入图片描述

总结和注意事项

一:以前玩51比较多,STM32玩得少,主要的区别是STM32有多个模式,不同场景需要切换不同模式来进行。比如这里的DS1302 CLK 和 RST 这种直接一直推挽输出没问题,但是DAT引脚则不行了,咱们去拉低拉高是推挽输出,但是到我们读取这个DAT电平则需要设置成上拉输入。(浮空貌似也行)不像51不用考虑 直接操作。
二:如果你发现采取样不准,请检查是否把DS1302的 VCC接到STM32的5V引脚。
三:重定向printf(); 如果你发现并没有输出数据。那么请查看一下你是否勾选了(如下图)
在这里插入图片描述
学了51 其实上手32不难,反正我觉得还可以,就是配置啥的麻烦了一丢丢主要是IO的模式

如果觉得这篇文章对你有用。欢迎大家点赞、评论哈哈
需要整个工程代码,欢迎大家打赏,请o( ̄︶ ̄)o

需要整个工程代码,欢迎大家打赏。
printf("+meQ:844797079\n")

在这里插入图片描述

继续加油!!!

猜你喜欢

转载自blog.csdn.net/weixin_47457689/article/details/125003837