一、设计效果
- 配置RTC时钟,初始化为2000年1月1日00:00:00;
- 通过RTC时钟秒中断串口每秒打印一次当前时刻,并切换一次流水灯状态;
- 配置闹铃为10:00:05,在闹铃中断中每秒切换一次蜂鸣器状态闹铃,直到按KEY1关闭闹钟;
- 配置开发板上四个按键中断,按下实现:
-
- KEY0 —— 将时间设置为 2022年11月06日 10:00:00
- KEY1 —— 将关闭闹钟
- KEY2 —— 打开蜂鸣器
- KEYUP —— 关闭蜂鸣器
- 每次操作时,使用串口打印提示信息
二、硬件工作原理和原理图
RTC是个独立的定时器。RTC模块拥有一个连续计数的计数器,在相应的软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。一般配备有电池。
三、实验记录
1.完成CubeMx初始化配置
1.1 利用CubeMX完成HAL库工程模板和初始化:
通过选择芯片型号创建CubeMX工程
在弹出的对话框中输入开发板上的芯片型号,STM32F103RB
在右侧筛选栏中选择Tx型,即开发板上芯片所用的LQFP64型封装,双击建立工程
1.2 RCC模块引脚的配置
在弹出的工程配置对话框中的第一个引脚配置选项卡下,先完成RCC时钟模块引脚配置:
选择启用外部的高速和低速时钟源,HSE和LSE,配置为晶振连接;
配置完成后,对应时钟引脚变绿,同时旁边出现其将要配置模式的文字说明;
1.3 配置时钟
我们前面启用了RCC时钟模块的外部时钟引脚,这里我们需要将外部时钟源配置为实际使用的频率;
1.4 RTC配置
1.在侧边栏的计时器中选择RTC
2.勾选Activate Clock Source 激活时钟源
Activate calendar 激活日历
3.配置时间日期
1.5 串口配置
- 在侧边栏的通信外设中选择USART1
- 在串口下拉框出选择异步(Asynchronous),成功后可以看到对应的串口引脚RX(接收引脚),TX(发送引脚)变绿。
- 选择下方的Parameter Settings选项卡确认串口参数。设置波特率为115200,传输数据长度为8 Bit,无奇偶校验位,1个停止位,数据方向(Data Direction)为接收和发送(Receive and Transmit)
1.6 配置按键外部中断
参看EX3_1配置四个按键的外部中断,注意不同按键的上/下拉和边沿检测;
1.7 配置NVIC,使能中断并设置优先级
1.8 创建生成工程
略
2.使用的RTC的HAL库函数带读
2.1 RTC初始化
1) 配置RTC的秒时钟
2) 配置初始化时间日期
2.2 HAL_RTC_MspInit()解析
2.3 RTC相关接口函数
1)日期设置函数:
/*函数功能:设置RTC当前日期
/入口参数:hrtc:指向RTC_HandleTypeDef结构的指针sDate:指向日期结构体指针Format:输入格式(RTC_FORMAT_BIN:二进制格式,RTC_FORMAT_BCD:BCD数据格式)
/返回值:HAL_OK表示设置成功,HAL_ERROR表示设置失败*/
HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)//RTC日期结构体定义
typedef struct
{uint8_t WeekDay; /*!< Specifies the RTC Date WeekDay (not necessary for HAL_RTC_SetDate).This parameter can be a value of @ref RTC_WeekDay_Definitions */uint8_t Month; /*!< Specifies the RTC Date Month (in BCD format).This parameter can be a value of @ref RTC_Month_Date_Definitions */uint8_t Date; /*!< Specifies the RTC Date.This parameter must be a number between Min_Data = 1 and Max_Data = 31 */uint8_t Year; /*!< Specifies the RTC Date Year.This parameter must be a number between Min_Data = 0 and Max_Data = 99 */} RTC_DateTypeDef;
2)时间设置函数:
/*函数功能:设置RTC当前时间
/入口参数:hrtc:指向RTC_HandleTypeDef结构的指针sTime:指向时间结构体指针Format:输入格式(RTC_FORMAT_BIN:二进制格式,RTC_FORMAT_BCD:BCD数据格式)
/返回值:HAL_OK表示设置成功,HAL_ERROR表示设置失败*/
HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)//RTC时间结构体定义
typedef struct
{uint8_t Hours; /*!< Specifies the RTC Time Hour.This parameter must be a number between Min_Data = 0 and Max_Data = 23 */uint8_t Minutes; /*!< Specifies the RTC Time Minutes.This parameter must be a number between Min_Data = 0 and Max_Data = 59 */uint8_t Seconds; /*!< Specifies the RTC Time Seconds.This parameter must be a number between Min_Data = 0 and Max_Data = 59 */} RTC_TimeTypeDef;
3)闹钟设置函数:
/*函数功能:设置指定的RTC报警与中断
/入口参数:hrtc:指向RTC_HandleTypeDef结构的指针sAlarm:指向报警结构体指针Format:输入格式(RTC_FORMAT_BIN:二进制格式,RTC_FORMAT_BCD:BCD数据格式)
/返回值:HAL_OK表示设置成功,HAL_ERROR表示设置失败
/注:再使用这个函数设计前必须调用HAL_RTC_SetTime()*/
HAL_StatusTypeDef HAL_RTC_SetAlarm_IT(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format)//RTC闹钟结构体定义
typedef struct
{RTC_TimeTypeDef AlarmTime; /*!< Specifies the RTC Alarm Time members */uint32_t Alarm; /*!< Specifies the alarm ID (only 1 alarm ID for STM32F1).This parameter can be a value of @ref RTC_Alarms_Definitions */
} RTC_AlarmTypeDef;
4)报警函数:
/*该函数处理告警中断请求,当RTC到我们所设置的时间时,会进入该中断,随后进入报警回调函数*/
void HAL_RTC_AlarmIRQHandler(RTC_HandleTypeDef *hrtc)/*报警回调函数,其是一个弱定义的占位空函数,使用需要我们自己重写一个同名的函数,来完成中断的响应内容*/
__weak void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
5)RTC中断
/*处理RTC全局中断*/
void RTC_IRQHandler(void)
{/* USER CODE BEGIN RTC_IRQn 0 *//* USER CODE END RTC_IRQn 0 */HAL_RTCEx_RTCIRQHandler(&hrtc);//秒中断/* USER CODE BEGIN RTC_IRQn 1 *//* USER CODE END RTC_IRQn 1 */
}/*秒中断回调函数,每秒进入一次*/
__weak void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc)
3.程序编写
3.1 修改 rtc.h 和 rtc.c 实现基础功能
1)根据设计效果要求,rtc模块须实现三个功能函数,依此修改rtc.h 文件:
2)在rtc.c 中实现三个功能函数
① void RTC_TimeAndDate_Show(void) 串口打印时间和日期
/*** @brief 串口打印时间和日期* @param 无* @retval 无*/
void RTC_TimeAndDate_Show(void)
{RTC_TimeTypeDef RTC_TimeStructure;RTC_DateTypeDef RTC_DateStructure;// 获取日历HAL_RTC_GetTime(&hrtc, &RTC_TimeStructure, RTC_FORMAT_BIN);HAL_RTC_GetDate(&hrtc, &RTC_DateStructure, RTC_FORMAT_BIN); // 打印日期printf("日期: 20%0.2d年%0.2d月%0.2d日 - 星期%d\r\n", RTC_DateStructure.Year,RTC_DateStructure.Month, RTC_DateStructure.Date,RTC_DateStructure.WeekDay);// 打印时间printf("时间: %0.2d:%0.2d:%0.2d \r\n\r\n", RTC_TimeStructure.Hours, RTC_TimeStructure.Minutes, RTC_TimeStructure.Seconds);
}
②void RTC_StartAlarm(void) 启动 10:00:05 闹钟
/*** @brief 要使能 RTC 闹钟中断,需按照以下顺序操作:1. 配置 NVIC 中的 RTC_Alarm IRQ 通道并将其使能。2. 配置 RTC 以生成 RTC 闹钟(闹钟 A 或闹钟 B)。* @param 无* @retval 无*/
void RTC_StartAlarm(void)
{RTC_AlarmTypeDef RTC_AlarmStructure;/* RTC 闹钟中断配置 */HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 9, 0);/* 使能RTC闹钟中断 */HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);/* 设置闹钟源 */RTC_AlarmStructure.Alarm = RTC_ALARM_A;/* 设置闹钟时间 */RTC_AlarmStructure.AlarmTime.Hours = 0x10;RTC_AlarmStructure.AlarmTime.Minutes = 0x00;RTC_AlarmStructure.AlarmTime.Seconds = 0x5;/* 启动闹钟中断10:00:05 */ HAL_RTC_SetAlarm_IT(&hrtc,&RTC_AlarmStructure, RTC_FORMAT_BCD); printf("启动闹钟! 10:00:05闹铃!\r\n\r\n");
}
③void RTC_SetTime(void) 设置当前日期时间
/*** @brief 设置当前日期时间* @param 无* @retval 无*/
void RTC_SetTime(void)
{RTC_TimeTypeDef sTime = {0};RTC_DateTypeDef DateToUpdate = {0};sTime.Hours = 0x10;sTime.Minutes = 0x0;sTime.Seconds = 0x0;HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD);DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;DateToUpdate.Month = RTC_MONTH_NOVEMBER;DateToUpdate.Date = 0x7;DateToUpdate.Year = 0x22;HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD);
}
3.2 在 usart.c 中,重定义printf
前面有文章教学。
3.3 移植BEEP的BSP驱动到到新工程
1)拷贝BSP驱动到工程目录
2)添加源文件到工程
3)在main.c 中添加BSP驱动头文件
这里添加时使用了绝对路径,故可不必在编译器中添加头文件的 include path
3.4 在main.c中实现设计效果
1)定义一个全局变量,作为闹钟状态标志
2)用户层代码初始化
3)RTC秒中断实现时间打印和闹铃效果
3)编写报警回调函数
4)套用之前的按键外部中断程序,实现设计效果
4. 编译烧录
结果显示: