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(); // 等待最后一个任务结束
}
}
这里需要注意,闹钟中断里需要清除两个中断标志位,否则会一直触发中断。
标签:NVIC,RTC,STM32,start,tm,time,EXTI,时钟 From: https://www.cnblogs.com/tqht7h/p/18051420