STM32标准库RTC时钟

STM32标准库RTC时钟

1. RTC时钟配置

1.1 头文件引用

需要引用以下头文件或打开以下模块:

#include "stm32f10x_rcc.h"      // 包含RCC时钟配置头文件
#include "stm32f10x_pwr.h"      // 包含PWR时钟配置头文件
#include "stm32f10x_rtc.h"      // 包含RTC时钟配置头文件
#include "time.h"               // 包含时间头文件

其中stm32f10x_rcc.h头文件用于配置RTC相关的时钟频率,stm32f10x_pwr.h头文件用于启用对RTC和备份域寄存器的访问,stm32f10x_rtc.h用于配置RTC模块,time.h用于在STM32上建立较为完善的时间管理机制。

1.2. RTC时钟初始化

void RTC_Init()                                           
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE); // 使能PWR和BKP时钟
	PWR_BackupAccessCmd(ENABLE);                            // 使能RTC和后备寄存器访问
//	RCC_LSEConfig(RCC_LSE_ON);
//	while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
//	
//	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
	
	RCC_LSICmd(ENABLE);                                     // 使能LSI时钟
	
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);     // 等待LSI时钟准备就绪
	
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);                 // 选择LSI作为RTC时钟源
	
	RCC_RTCCLKCmd(ENABLE);                                  // 使能RTC时钟
	
	RTC_WaitForSynchro();                                   // 等待RTC时钟同步
	
	RTC_WaitForLastTask();                                  // 等待上一次RTC操作完成
	
	RTC_ITConfig(RTC_IT_SEC,ENABLE);                        // 使能秒中断
	RTC_ITConfig(RTC_IT_ALR,ENABLE);                        // 使能闹钟中断
	
	RTC_WaitForLastTask();                                  // 等待上一次RTC操作完成
	
	//RTC_SetPrescaler(32768-1);
	RTC_SetPrescaler(40000-1);                              //设定RTC频率            
	
	RTC_WaitForLastTask();                                  // 等待上一次RTC操作完成
	
	NVIC_InitTypeDef NVIC_InitStructure;                    // 定义NVIC_InitTypeDef结构体
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;          // 选择RTC中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   // 设置抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      // 设置子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         // 使能中断
	
	NVIC_Init(&NVIC_InitStructure);                         // 初始化NVIC_InitTypeDef结构体
	
	NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;     // 选择闹钟中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   // 设置抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      // 设置子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         // 使能中断
	
	NVIC_Init(&NVIC_InitStructure);                         // 初始化NVIC_InitTypeDef结构体
	
	EXTI_InitTypeDef EXTI_Instructure;                      // 定义EXTI_InitTypeDef结构体
	EXTI_Instructure.EXTI_Line = EXTI_Line17;               // 选择EXTI17中断
	EXTI_Instructure.EXTI_Mode = EXTI_Mode_Interrupt;       // 选择中断模式
	EXTI_Instructure.EXTI_Trigger = EXTI_Trigger_Rising;    // 选择上升沿触发
	EXTI_Instructure.EXTI_LineCmd = ENABLE;                 // 使能中断线
	EXTI_Init(&EXTI_Instructure);                           // 初始化EXTI_InitTypeDef结构体
}

在这里我使用了LSI时钟作为RTC时钟源,也可使用LSE时钟作为时钟源,不过打开方式略有不同,只要将上面注释的部分打开,删除代码中的LSI相关代码,并将RTC时钟频率修改为1Hz即可。
需要注意, RTCAlarm_IRQn中断的优先级必须要比RTC_IRQn高,否则会陷入中断嵌套,导致程序卡死。其次RTC的闹钟中断属于外部中断,需要同时打开对应的外部中断。

2. RTC时钟操作

2.1 设置时间


void RTC_SetTime(uint32_t time)    
{
	RTC_SetCounter(time);       // 设置RTC计数器
	RTC_WaitForLastTask();      // 等待上一次RTC操作完成
}

函数非常简单,但是这里要注意,向RTC时钟输入的时间为Unix时间戳,即从1970年1月1日0时0分0秒开始计算的秒数。开头时引用的time.h头文件便是为了更简便实现正常时间与时间戳的转换。具体转换操作如下所示:

struct tm time_start;               // 定义一个时间结构体,该结构体内存储的时间格式为正常时间
time_start.tm_year = year_start;    // 设置年,这个年指的是当前年数减1900的得到数字,范围为0-128
time_start.tm_mon = mon_start;      // 设置月,这个月指的是当前月数减1得到的数字,范围为0-12,因为Unix时间是从1月开始算的
time_start.tm_mday = mday_start;    // 设置日
time_start.tm_wday = wday_start;    // 设置星期
time_start.tm_yday = yday_start;    // 设置一年的天数
time_start.tm_hour = hour_start;    // 设置小时
time_start.tm_min = min_start;      // 设置分钟
time_start.tm_sec = sec_start;      // 设置秒数
RTC_SetTime(mktime(&time_start));   // 设置RTC时间,mktime函数会将时间结构体转换为Unix时间戳

2.2 获取时间

void RTC_GetTime()                  // 获取RTC时间
{
	struct tm *time;                // 定义一个时间结构体
	time_t time_temp = RTC_GetCounter();   // 获取RTC计数器
	time = localtime(&time_temp);   // 将Unix时间戳转换为时间结构体
	printf("unix:%d\n",time_temp);
	printf("%d-%d-%d-%d-%d",time->tm_year+1900,time->tm_mon+1,time->tm_mday,time->tm_wday,time->tm_yday);
	printf("-%d-%d-%d\n",time->tm_hour,time->tm_min,time->tm_sec);
}

在time.h头文件中,time.t = uint32_t.

2.3 设置闹钟

void RTC_SetAlarmTime(uint32_t time)
{
	PWR_BackupAccessCmd(ENABLE);
	RTC_SetAlarm(time);
	RTC_WaitForLastTask();
}

设置闹钟与设置时间差不多,区别在于设置闹钟要先打开备份寄存器,然后才能设置闹钟时间。

3. 中断函数

RTC的中断没什么特别,就是正常的进中断、清标志位。

3.1 秒中断

void RTC_IRQHandler()                           // RTC中断处理函数
{
	if(RTC_GetITStatus(RTC_IT_SEC) != RESET)    // 判断是否是秒中断
	{
		TimeRead_Flag = 1;                      // 设置读秒标志位
		RTC_ClearITPendingBit(RTC_IT_SEC);      // 清除秒中断标志位
		RTC_WaitForLastTask();                  // 等待最后一个任务结束
	}
}

3.2 闹钟中断

void RTCAlarm_IRQHandler()                      // 闹钟中断处理函数
{
	if(RTC_GetITStatus(RTC_IT_ALR) != RESET)    // 判断是否是闹钟中断
	{
		printf("Alarm is OK\n");                // 输出提示信息
		EXTI_ClearITPendingBit(EXTI_Line17);    // 清除闹钟中断的外部标志位
		RTC_ClearITPendingBit(RTC_IT_ALR);      // 清除闹钟中断标志位
		RTC_WaitForLastTask();                  // 等待最后一个任务结束
	}
}

这里需要注意,闹钟中断里需要清除两个中断标志位,否则会一直触发中断。

posted @ 2024-03-04 11:08  T7H  阅读(69)  评论(0编辑  收藏  举报