当前位置:宠物百科>综合>资讯>正文

正点原子的stm32全部教程合集:STM32F103开发板资料连载第十九章

人气:437 ℃/2024-10-19 05:55:02

1)实验平台:【正点原子】 NANO STM32F103 开发板

2)摘自《正点原子STM32 F1 开发指南(NANO 板-HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子

第十九章 RTC 实时时钟实验

前面我们介绍了两款液晶模块,这一章我们将介绍 STM32F1 的内部实时时钟(RTC)。在本章中,我们将使用数码管来显示日期和时间,实现一个简单的时钟,并可以设置闹铃。另外,本章将顺带向大家介绍 BKP 的使用。本章分为如下几个部分:

19.1 STM32F1 RTC 时钟简介

19.2 硬件设计

19.3 软件设计

19.4 下载验证

19.1 STM32F1 RTC 时钟简介

STM32 的实时时钟(RTC)是一个独立的定时器。STM32 的 RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。RTC 模块和时钟配置系统(RCC_BDCR 寄存器)是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前, 先要取消备份区域(BKP)写保护。RTC 的简化框图,如图 19.1.1 所示:

图 19.1.1 RTC 框图

RTC 由两个主要部分组成(参见图 19.1.1),第一部分(APB1 接口)用来和 APB1 总线相连。

此单元还包含一组 16 位寄存器,可通过 APB1 总线对其进行读写操作。APB1 接口由 APB1 总

线时钟驱动,用来与 APB1 总线连接。

另一部分(RTC 核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是 RTC 的

预分频模块,它可编程产生 1 秒的 RTC 时间基准 TR_CLK。RTC 的预分频模块包含了一个 20

位的可编程分频器(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每个

TR_CLK 周期中 RTC 产生一个中断(秒中断)。第二个模块是一个 32 位的可编程计数器,可被

初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算,可以记录 4294967296 秒,

约合 136 年左右,作为一般应用,这已经是足够了的。

RTC 还有一个闹钟寄存器 RTC_ALR,用于产生闹钟。系统时间按 TR_CLK 周期累加并与

存储在 RTC_ALR 寄存器中的可编程时间相比较,如果 RTC_CR 控制寄存器中设置了相应允许

位,比较匹配时将产生一个闹钟中断。

RTC 内核完全独立于 RTC APB1 接口,而软件是通过 APB1 接口访问 RTC 的预分频值、计

数器值和闹钟值的。但是相关可读寄存器只在 RTC APB1 时钟进行重新同步的 RTC 时钟的上升

沿被更新,RTC 标志也是如此。这就意味着,如果 APB1 接口刚刚被开启之后,在第一次的内

部寄存器更新之前,从 APB1 上读取的 RTC 寄存器值可能被破坏了(通常读到 0)。因此,若

在读取 RTC 寄存器曾经被禁止的 RTC APB1 接口,软件首先必须等待 RTC_CRL 寄存器的 RSF

位(寄存器同步标志位,bit3)被硬件置 1。

要理解 RTC 原理,我们必须先通过对寄存器的讲解,让大家有一个全面的了解。接下来,

我们介绍一下 RTC 相关的几个寄存器。首先要介绍的是 RTC 的控制寄存器,RTC 总共有 2 个

控制寄存器 RTC_CRH 和 RTC_CRL,两个都是 16 位的。RTC_CRH 的各位描如图 19.1.2 所示:

图 19.1.2 RTC_CRH 寄存器各位描述

该寄存器用来控制中断的,我们本章将要用到秒钟中断,所以在该寄存器必须设置最低位

为 1,以允许秒钟中断。我们再看看 RTC_CRL 寄存器。该寄存器各位描述如图 19.1.3 所示:

图 19.1.3 RTC_CRL 寄存器各位描述

本章我们用到的是该寄存器的 0、3~5 这几个位,第 0 位是秒钟标志位,我们在进入闹钟

中断的时候,通过判断这位来决定是不是发生了秒钟中断。然后必须通过软件将该位清零(写

0)。第 3 位为寄存器同步标志位,我们在修改控制寄存器 RTC_CRH/CRL 之前,必须先判断

该位,是否已经同步了,如果没有则等待同步,在没同步的情况下修改 RTC_CRH/CRL 的值是

不行的。第 4 位为配置标位,在软件修改 RTC_CNT/RTC_ALR/RTC_PRL 的值的时候,必须先

软件置位该位,以允许进入配置模式。第 5 位为 RTC 操作位,该位由硬件操作,软件只读。通

过该位可以判断上次对 RTC 寄存器的操作是否完成,如果没有,我们必须等待上一次操作结束

才能开始下一次操作。

第二个要介绍的寄存器是 RTC 预分频装载寄存器,也有 2 个寄存器组成,RTC_PRLH 和

RTC_PRLL。这两个寄存器用来配置 RTC 时钟的分频数的,比如我们使用外部 32.768K 的晶振

作为时钟的输入频率,那么我们要设置这两个寄存器的值为 32767,以得到一秒钟的计数频率。

RTC_PRLH 的各位描述如图 19.1.4 所示:

图 19.1.4 RTC_PRLH 寄存器各位描述

从图 19.1.4 可以看出,RTC_PRLH 只有低四位有效,用来存储 PRL 的 19~16 位。而 PRL

的前 16 位,存放在 RTC_PRLL 里面,寄存器 RTC_PRLL 的各位描述如图 19.1.5 所示:

图 19.1.5 RTC_PRLL 寄存器各位描述

在介绍完这两个寄存器之后,我们介绍 RTC 预分频器余数寄存器,该寄存器也有 2 个寄存

器组成 RTC_DIVH 和 RTC_DIVL,这两个寄存器的作用就是用来获得比秒钟更为准确的时钟,

比如可以得到 0.1 秒,或者 0.01 秒等。该寄存器的值自减的,用于保存还需要多少时钟周期获

得一个秒信号。在一次秒钟更新后,由硬件重新装载。这两个寄存器和 RTC 预分频装载寄存器

的各位是一样的,这里我们就不列出来了。

接着要介绍的是 RTC 最重要的寄存器,RTC 计数器寄存器 RTC_CNT。该寄存器由 2 个 16

位的寄存器组成 RTC_CNTH 和 RTC_CNTL,总共 32 位,用来记录秒钟值(一般情况下)。此

两个计数器也比较简单,我们也不多说了。注意一点,在修改这个寄存器的时候要先进入配置

模式。

最后我们介绍 RTC 部分的最后一个寄存器,RTC 闹钟寄存器,该寄存器也是由 2 个 16 为

的寄存器组成 RTC_ALRH 和 RTC_ALRL。总共也是 32 位,用来标记闹钟产生的时间(以秒为

单位),如果 RTC_CNT 的值与 RTC_ALR 的值相等,并使能了中断的话,会产生一个闹钟中

断。该寄存器的修改也要进入配置模式才能进行。

因为我们使用到备份寄存器来存储 RTC 的相关信息(我们这里主要用来标记时钟是否已经

经过了配置),我们这里顺便介绍一下 STM32 的备份寄存器。

备份寄存器是 42 个 16 位的寄存器(NANO 开发板就是中容量的),可用来存储 20 个字

节的用户应用程序数据。他们处在备份域里,当 VDD 电源被切断,他们仍然由 VBAT 维持供

电。即使系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。

此外,BKP 控制寄存器用来管理侵入检测和 RTC 校准功能,这里我们不作介绍。

复位后,对备份寄存器和 RTC 的访问被禁止,并且备份域被保护以防止可能存在的意外的

写操作。执行以下操作可以使能对备份寄存器和 RTC 的访问:

1)通过设置寄存器 RCC_APB1ENR 的 PWREN 和 BKPEN 位来打开电源和后备接口的时

2)电源控制寄存器(PWR_CR)的 DBP 位来使能对后备寄存器和 RTC 的访问。

我们一般用 BKP 来存储 RTC 的校验值或者记录一些重要的数据,相当于一个 EEPROM,

不过这个 EEPROM 并不是真正的 EEPROM,而是需要电池来维持它的数据。关于 BKP 的详细

介绍请看《STM32 参考手册》的第 47 页,5.1 一节。

最后,我们还要介绍一下备份区域控制寄存器RCC_BDCR。该寄存器的个位描述如图19.1.6

所示:

图 19.1.6 RCC_ BDCR 寄存器各位描述

RTC 的时钟源选择及使能设置都是通过这个寄存器来实现的,所以我们在 RTC 操作之前

先要通过这个寄存器选择 RTC 的时钟源,然后才能开始其他的操作。

寄存器介绍就给大家介绍到这里了,我们下面来看看要经过哪几个步骤的配置才能使 RTC

正常工作,这里我们将对每个步骤通过库函数的实现方式来讲解。

RTC 相关的库函数在文件 stm32f1xx_hal_rtc.c 和 stm32f1xx_hal_rtc.h 文件中,BKP 相关的

库函数在文件 stm32f1xx_hal_rtc_ex.c 和文件 stm32f1xx_hal_rtc_ex.h 文件中。

RTC 正常工作的一般配置步骤如下:

1)使能电源时钟和备份区域时钟。

前面已经介绍了,我们要访问 RTC 和备份区域就必须先使能电源时钟,然后使能 RTC 后

备区域访问。电源时钟使能,通过 RCC_APB1ENR 寄存器来设置;RTC 及 RTC 备份寄存器的

写访问,通过 PWR_CR 寄存器的 DBP 位设置。HAL 库设置方法为:

__HAL_RCC_PWR_CLK_ENABLE();//使能电源时钟 PWR

__HAL_RCC_BKP_CLK_ENABLE(); //使能 BKP 时钟

HAL_PWR_EnableBkUpAccess(); //取消备份区域写保护

2)开启外部低速振荡器 LSE,选择 RTC 时钟,并使能。

配置开启 LSE 的函数为 HAL_RCC_OscConfig,使用方法为:

RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_LSE;//LSE 配置

RCC_OscInitStruct.PLL.PLLState=RCC_PLL_NONE;

RCC_OscInitStruct.LSEState=RCC_LSE_ON; //RTC 使用 LSE

HAL_RCC_OscConfig(&RCC_OscInitStruct);

选择 RTC 时钟源函数为 HAL_RCCEx_PeriphCLKConfig,使用方法:

PeriphClkInitStruct.PeriphClockSelection=RCC_PERIPHCLK_RTC;//外设为 RTC

PeriphClkInitStruct.RTCClockSelection=RCC_RTCCLKSOURCE_LSE;//RTC时钟源为LSE

HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

使能 RTC 时钟方法为:

__HAL_RCC_RTC_ENABLE();//RTC 时钟使能

3) 初始化 RTC,设置 RTC 的分频,以及配置 RTC 参数。

在 HAL 中,初始化 RTC 是通过函数 HAL_RTC_Init 实现的,该函数声明为:

HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc);

同样按照以前的方式,我们来看看 RTC 初始化参数结构体 RTC_HandleTypeDef 定义:

typedef struct

{

RTC_TypeDef *Instance;

RTC_InitTypeDef Init;

RTC_DateTypeDef DateToUpdate;

HAL_LockTypeDef Lock;

__IO HAL_RTCStateTypeDef State;

}RTC_HandleTypeDef;

这里我们着重讲解成员变量 Init 含义,因为它是真正的 RTC 初始化变量,它是 RTC_Init

TypeDef 结构体类型,结构体 RTC_InitTypeDef 定义为:

typedef struct

{

uint32_t AsynchPrediv; //预分频系数

uint32_t OutPut; //选择连接到 RTC_ALARM 输出的标志

}RTC_InitTypeDef;

该结构体有 2 个成员变量。

AsynchPrediv 用来设置 RTC 时钟分频系数,也就是通过 RTC_PRLH 和 RTC_PRLL 来设置,

参数最大值为 0xFFFF。

OutPut 用来选择要设置 RTC Tamper 引脚上输出的输出源,有四个取值分别为:

RTC_OUTPUTSOURCE_NONE(TAMPER 引脚上没有输出),

RTC_OUTPUTSOURCE_CALIBCLOCK(RTC 时钟的 TAMPER 引脚上的频率除以 64)

RTC_OUTPUTSOURCE_ALARM(TAMPER 引脚上的报警脉冲信号)

RTC_OUTPUTSOURCE_SECOND (TAMPER 引脚上的第二个脉冲信号)

OutPut 参数一般我们不用配置,直接默认就可以了。

接下来我们看看 RTC 初始化的一般格式:

RTC_Handler.Instance=RTC;

RTC_Handler.Init.AsynchPrediv=32767;

HAL_RTC_Init(&RTC_Handler);

同样,HAL 库也提供了 RTC 初始化 MSP 函数。函数声明为:

void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc);

该函数内部一般存放时钟使能,时钟源选择等操作程序。

4) 设置 RTC 的时间:

HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc,

RTC_TimeTypeDef *sTime, uint32_t Format);

实际上,根据我们前面寄存器的讲解,RTC_SetTime 函数是用来设置时间寄存器

RTC_CNTH 和 RTC_CNTL 的值。

RTC_SetTime 函数的第三个参数 Format,用来设置输入的时间格式为 BIN 格式还是 BCD

格式,可选值为 RTC_FORMAT_BIN 和 RTC_FORMAT_BCD,由于 STM32F103RBT6 的 RTC

只有 BIN 模式,所以选择 RTC_FORMAT_BIN。

我们接下来看看第二个初始化参数结构体 RTC_TimeTypeDef 的定义:

typedef struct

{

uint8_t Hours;

uint8_t Minutes;

uint8_t Seconds;

}RTC_TimeTypeDef;

这个几个成员变量比较好理解,分别用来设置 RTC 时间参数的小时,分钟,秒钟,而

STM32F103RBT6 的 RTC 寄存器只有计数寄存器,也就是秒,所以这里设置的小时,分钟,通

过 RTC_SetTime 函数会都会转换成秒钟写入寄存器中。

HAL_RTC_SetTime 函数参考实例如下:

RTC_TimeTypeDef RTC_TimeStructure:

RTC_TimeStructure.Hours=1;

RTC_TimeStructure.Minutes=1;

RTC_TimeStructure.Seconds=1;

HAL_RTC_SetTime(&RTC_Handler,&RTC_TimeStructure,RTC_FORMAT_BIN);

5 ) 设置 RTC 的日期。

设置 RTC 的日期函数为:

HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc,

RTC_DateTypeDef *sDate, uint32_t Format);

HAL_RTC_SetDate 设置日期函数,该函数有三个入口参数,我们着重讲解第二个入口参数

sDate,它是结构体 RTC_DateTypeDef 结构体类型变量,结构体 RTC_DateTypeDef 定义如下:

typedef struct

{

uint8_t WeekDay; //星期几

uint8_t Month; //月份

uint8_t Date //日期;

uint8_t Year; //年份

}RTC_DateTypeDef;

结构体一共四个成员变量,这四个成员变量非常好理解,分别用来设置 RTC 时间参数的星

期,月份,日期,以及年份,而 STM32F103RBT6 的 RTC 寄存器只有计数寄存器,也就是秒,

所以这里设置的参数,通过 HAL_RTC_SetDate 函数会都会转换成秒钟写入寄存器中。

6)获取 RTC 当前日期和时间:

获取当前 RTC 时间的函数为:

HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc,

RTC_TimeTypeDef *sTime, uint32_t Format);

获取当前 RTC 日期的函数为:

HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc,

RTC_DateTypeDef *sDate, uint32_t Format);

这两个函数非常简单,实际就是读取 RTC_CNTH/RTC_CNTL 寄存器的值转换为时间和日

期的值,然后将值存放到相应的结构体中。

通过以上 6 个步骤,我们就完成了对 RTC 的配置,RTC 即可正常工作,而且这些操作不

是每次上电都必须执行的,可以视情况而定。当然,我们还需要设置时间、日期、秒中断、闹

钟等,这些将在后面介绍。

19.2 硬件设计

本实验用到的硬件资源有:

1) 指示灯 DS0

2) 串口

3) 数码管

4) RTC

前面 3 个都介绍过了,而 RTC 属于 STM32F1 内部资源,其配置也是通过软件设置好就可

以了。不过 RTC 不能断电,否则数据就丢失了,我们如果想让时间在断电后还可以继续走,那

么必须确保开发板的电池有电(ALIENTEK NANO STM32 开发板标配是有电池的)。

19.3 软件设计

同样,打开我们光盘的 RTC 时钟实验,可以看到,我们的工程中加入了 rtc.c 源文件和 rtc.h

头文件,同时,引入了 stm32f1xx_hal_rtc.c 和 stm32f1xx_hal_rtc_ex.c 库文件。

由于篇幅所限,rtc.c 中的代码,我们不全部贴出了,这里针对几个重要的函数,进行简要

说明,首先是 RTC_Init,其代码如下:

//实时时钟配置

//初始化 RTC 时钟,同时检测时钟是否工作正常

//BKP->DR1 用于保存是否第一次配置的设置

//返回 0:正常

//其他:错误代码

u8 RTC_Init(void)

{

RTC_Handler.Instance=RTC;

RTC_Handler.Init.AsynchPrediv=32767;

//时钟周期设置(有待观察,看是否跑慢了?)理论值:32767

if(HAL_RTC_Init(&RTC_Handler)!=HAL_OK) return 1;

if(HAL_RTCEx_BKUPRead(&RTC_Handler,RTC_BKP_DR1)!=0X5050)

//是否第一次配置

{

RTC_Set(2018,5,27,17,7,0);

//设置日期和时间,2018 年 5 月 27 日,17 点 07 分 0 秒

HAL_RTCEx_BKUPWrite(&RTC_Handler,RTC_BKP_DR1,0X5050);

//标记已经初始化过了

printf("FIRST TIME\n");

}

__HAL_RTC_ALARM_ENABLE_IT(&RTC_Handler,RTC_IT_SEC); //允许秒中断

__HAL_RTC_ALARM_ENABLE_IT(&RTC_Handler,RTC_IT_ALRA); //允许闹钟中断

HAL_NVIC_SetPriority(RTC_IRQn,0x01,0x02); //抢占优先级 1,子优先级 2

HAL_NVIC_EnableIRQ(RTC_IRQn);

RTC_Get();//更新时间

return 0; //ok

}

该函数用来初始化 RTC 时钟,但是只在第一次的时候设置时间,以后如果重新上电/复位

都不会再进行时间设置了(前提是备份电池有电),在第一次配置的时候,我们是按照上面介

绍的 RTC 初始化步骤调用函数(HAL_RTC_Init)来实现的,这里这里就不在多说了。

这里我们设置时间是通过时间设置函数 RTC_Set 函数来实现的(没有使用 HAL 库函数),

该函数将在后续进行介绍。这里我们默认将时间设置为 2018 年 5 月 2714 日,17 点 07 分 0 秒。

在设置好时间之后,我们通过 HAL_RTCEx_BKUPWrite()函数向 BKP->DR1 写入标志字

0X5050 , 用 于 标 记 时 间 已 经 被 设 置 了 。 这 样 , 再 次 发 生 复 位 的 时 候 , 该 函 数 通 过

HAL_RTCEx_BKUPRead()读取 BKP->DR1 的值,来判断决定是不是需要重新设置时间,如果

不需要设置,则跳过时间设置,这样不会重复设置时间,使得我们设置的时间不会因复位或者

断电而丢失。然后通过调用__HAL_RTC_ALARM_ENABLE_IT 使能秒中断和闹钟中断,配置

中断的优先级,最后调用 RTC_Get 函数获取当前最新的时间(没有使用 HAL 库函数),该函

数将在后续进行介绍。

RTC_Init 函数还有返回值,返回值代表此次操作的成功与否,如果返回 0,则代表初始化

RTC 成功,如果返回值非零则代表错误代码了。

这里我们来看看读备份区域和写备份区域寄存器的两个函数为:

uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister);

void HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister,

uint32_t Data)

这两个函数的使用方法就非常简单,分别用来读和写 BKR 寄存器的值。

介绍完 RTC_Init,我们来介绍一下 RTC_Set 函数,该函数代码如下:

//设置时钟

//把输入的时钟转换为秒钟

//以 1970 年 1 月 1 日为基准

//1970~2099 年为合法年份

//返回值:0,成功;其他:错误代码.

//月份数据表

u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表

//平年的月份日期表

const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};

//syear,smon,sday,hour,min,sec:年月日时分秒

//返回值:设置结果。0,成功;1,失败。

u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)

{

u16 t;

u32 seccount=0;

if(syear<1970||syear>2099)return 1;

for(t=1970;t<syear;t ) //把所有年份的秒钟相加

{

if(Is_Leap_Year(t))seccount =31622400;//闰年的秒钟数

else seccount =31536000;

//平年的秒钟数

}

smon-=1;

for(t=0;t<smon;t ) //把前面月份的秒钟数相加

{

seccount =(u32)mon_table[t]*86400;//月份秒钟数相加

if(Is_Leap_Year(syear)&&t==1)seccount =86400;//闰年 2 月份增加一天的秒钟数

}

seccount =(u32)(sday-1)*86400;//把前面日期的秒钟数相加

seccount =(u32)hour*3600;//小时秒钟数

seccount =(u32)min*60;

//分钟秒钟数

seccount =sec;//最后的秒钟加上去

//设置时钟

__HAL_RCC_PWR_CLK_ENABLE();

//使能电源时钟 PWR

__HAL_RCC_BKP_CLK_ENABLE();//使能 BKP 时钟

HAL_PWR_EnableBkUpAccess();

//取消备份区域写保护

//上面三步是必须的!

RTC->CRL|=1<<4; //允许配置

RTC->CNTL=seccount&0xffff;

RTC->CNTH=seccount>>16;

RTC->CRL&=~(1<<4);//配置更新

while(!(RTC->CRL&(1<<5)));//等待 RTC 寄存器操作完成

RTC_Get();//设置完之后更新一下数据

return 0;

}

该函数用于设置时间,把我们输入的时间,转换为以 1970 年 1 月 1 日 0 时 0 分 0 秒当做起

始时间的秒钟信号,后续的计算都以这个时间为基准的,由于 STM32 的秒钟计数器可以保存

136 年的秒钟数据,这样我们可以计时到 2106 年。

接着,我们介绍 RTC_Alarm_Set 函数,该函数用于设置闹钟时间,同 RTC_Set 函数几乎一

模一样,主要区别,就是将调用 RTC->CNTL 和 RTC->CNTH 改为 RTC->ALRL 和 RTC->ALRH,

用于设置闹钟时间,具体代码请参考本例程源码。

接着,我们介绍一下 RTC_Get 函数,该函数用于获取时间和日期等数据,其代码如下:

//得到当前的时间,结果保存在 calendar 结构体里面

//返回值:0,成功;其他:错误代码.

u8 RTC_Get(void)

{

static u16 daycnt=0;

u32 timecount=0;

u32 temp=0;

u16 temp1=0;

timecount=RTC->CNTH;//得到计数器中的值(秒钟数)

timecount<<=16;

timecount =RTC->CNTL;

temp=timecount/86400; //得到天数(秒钟数对应的)

if(daycnt!=temp)//超过一天了

{

daycnt=temp;

temp1=1970; //从 1970 年开始

while(temp>=365)

{

if(Is_Leap_Year(temp1))//是闰年

{

if(temp>=366)temp-=366;//闰年的秒钟数

else break;

}

else temp-=365;

//平年

temp1 ;

}

calendar.w_year=temp1;//得到年份

temp1=0;

while(temp>=28)//超过了一个月

{

if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2 月份

{

if(temp>=29)temp-=29;//闰年的秒钟数

else break;

}

else

{

if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年

else break;

}

temp1 ;

}

calendar.w_month=temp1 1; //得到月份

calendar.w_date=temp 1; //得到日期

}

temp=timecount

搜索更多有关“正点原子的stm32全部教程合集:STM32F103开发板资料连载第十九章”的信息 [百度搜索] [SoGou搜索] [头条搜索] [360搜索]
CopyRight © 2021-2024 宠物百科 All Rights Reserved. 手机版