温馨提示:本文不会重复之前提到的内容,如需查看,请参考附录
目录
重点提炼:
找到RTC闹钟的中断服务函数:RTC_Alarm_IRQHandler(void)
重点提炼:
一、需求分析
我们将设计一个示例项目RTC_Alarm_Demo,使用闹钟A、闹钟B和周期唤醒功能,它具有如下功能。
- 使用32.768kHz的LSE时钟作为RTC的时钟源。
- 系统复位时初始化RTC日期为2023-3-19,时间为9:15:10。
- 每秒唤醒一次,在周期唤醒中断里读取当前日期和时间,并在LCD上显示。
- 闹钟A设置为在时间xx:15:15触发,其中xx表示任意数字,即在每个小时的15分15秒时刻触发闹钟A。
- 对闹钟A中断次数计数,并在LCD上显示。
- 闹钟B设置为在时间xx:xx:20触发,即在每分钟的20秒时刻触发闹钟B。对闹钟B中断次数计数,并 在LCD上显示。
1、需要的外设资源分析:
- RTC的两个内部时钟,RTC唤醒中断输出引脚PC13用于控制LED;
- LCD、锁存器控制引脚PD2(见附录);
2、外设具体分析:
查看原理图,和手册。
CubeMX配置中,我们需要改动的参数:
1、RTC基本参数设置:
- Hour Format,小时格式,可以选择12 小时制或24小时制。
- Output Polarity,输出极性。闹钟A、闹钟B、周期唤醒中断事件信号有效时的输出极性,可设置为高电平或低电平。
Calendar Time 和 Calendar Data 分组里有用于设置日历的时间参数和初始化数据的如下参数:
- Data Format,数据格式,可选择二进制格式或BCD格式,这里选择Binary data forms
- 初始化时间数据,包括时、分、秒的数据。
- 初始化日期数据,包括年、月、日的数据。
2、Alarm 闹钟设置:
- 设置闹钟时间数据,包括时、分、秒的数据。
- Mask项:设置为Enable表示屏蔽某时间值的影响。
3、周期唤醒设置
- Wake Up Clock 可以设置为各种分频信号,一般设置为1Hz,即每秒一次。
- Wake Up Counter,周期唤醒重载值,与秒数有差一性,设置为零表示一秒。
4、中断设置
- RTC的中断唤醒和闹钟的中断的中断优先级都设置为1
二、软件配置
参考附录的内容,建立名为“RTC_Alarm_Demo”的项目。
按照分析配置:
选中RTC,打开两个闹钟,均使用内部闹钟功能;设置WakeUp模式为内部唤醒如图:
切换到时钟配置,选择LSI作为RTC的时钟,这样可以让RTC生成比较标准的1s/Hz,如图:
然后配置 Parameter Settings :
按照前文的分析与介绍,这里的设置如图所示:
打开并设置中断优先级:
生成项目文件后,打开MDK;
导入LCD驱动程序文件。
三、程序功能实现
用到的函数:
中断服务函数名称:
RTC_WKUP_IRQHandler(void);
HAL_RTC_AlarmAEventCallback(hrtc);//对应Alarm A
HAL_RTCEx_AlarmBEventCallback(hrtc);//对应Alarm B
RTC函数名称:
注意:这两个函数必须一起使用,不管你用不用的着,因为必须取出全部结果才可以重新写入。
HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN);//获取当前时间
HAL_RTC_GetDate(&hrtc,&sData,RTC_FORMAT_BIN);//获取当前日期
在MDK中编写代码:
在main.h中 :
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include <stdio.h>
/* USER CODE END Includes */
在main函数中初始化LCD,并设置背景色和画笔颜色,清屏:
在 stm32g4xx_it.c 中,定义两个全局变量,用于计数:
找到RTC唤醒的中断服务函数:RTC_WKUP_IRQHandler(void) 大约在204行
在如下代码段编写程序:
代码如下:
/* USER CODE END RTC_WKUP_IRQn 0 */
HAL_RTCEx_WakeUpTimerIRQHandler(&hrtc);
/* USER CODE BEGIN RTC_WKUP_IRQn 1 */
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sData;
if(HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN) == HAL_OK)
{
HAL_RTC_GetDate(&hrtc,&sData,RTC_FORMAT_BIN);
char str[20];
sprintf(str,"Data:20%2d-%2d-%2d",sData.Year,sData.Month,sData.Date);
LCD_DisplayStringLine(Line3,str);
sprintf(str,"Time:%2d:%2d:%2d",sTime.Hours,sTime.Minutes,sTime.Seconds);
LCD_DisplayStringLine(Line5,str);
}
/* USER CODE END RTC_WKUP_IRQn 1 */
找到RTC闹钟的中断服务函数:
RTC_Alarm_IRQHandler(void)
由于要分别对Alarm A 和 Alarm B 计数,所以必须在对应的中断回调函数里实现;
右击 HAL_RTC_AlarmIRQHandler (&hrtc); 然后点击Go To Definition,如图:
自动跳转到这里:该函数判断了到底是哪个闹钟引起了中断,并调用了对应的中断回调函数。
HAL_RTC_AlarmAEventCallback(hrtc);对应Alarm A
HAL_RTCEx_AlarmBEventCallback(hrtc);对应Alarm B
同样的右击,然后点击Go To Definition,就可以找到这两个函数。
这两个函数是弱函数,需要用户重新实现。复制函数的定义,如:
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
粘贴到 stm32g4xx_it.c 中的如下位置:(最底下的用户代码段)
完成后如图:
之后在里面实现功能,代码如下:
/* USER CODE BEGIN 1 */
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
char str[20];
CntA++;
sprintf(str,"Alarm A count: %d",CntA);
LCD_DisplayStringLine (Line7,str);
}
void HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *hrtc)
{
char str[20];
CntB++;
sprintf(str,"Alarm B count: %d",CntB);
LCD_DisplayStringLine (Line9,str);
}
/* USER CODE END 1 */
四、运行测试
编译、下载(见附录)。
运行结果如下:
RTC_Alarm实验结果