STM32CubeMX教程10 RTC 实时时钟 - 周期唤醒、闹钟A/B事件和备份寄存器

news2024/12/28 2:12:26

目录

1、准备材料

2、实验目标

3、实验流程

3.0、前提知识

3.1、CubeMX相关配置

3.1.1 、时钟树配置

3.1.2、外设参数配置

3.1.3 、外设中断配置

3.2、生成代码

3.2.1、外设初始化函数调用流程

3.2.2、外设中断函数调用流程

3.2.3、添加其他必要代码

4、常用函数

5、烧录验证

5.1、具体步骤

5.2、实现现象

6、注释详解

参考资料


1、准备材料

开发板(正点原子stm32f407探索者开发板V2.4)

STM32CubeMX软件(Version 6.10.0)

野火DAP仿真器

keil µVision5 IDE(MDK-Arm)

CH340G Windows系统驱动程序(CH341SER.EXE)

XCOM V2.6串口助手

2、实验目标

使用STM32CubeMX软件配置STM32F407开发板实现RTC周期唤醒、闹钟A/B事件功能,具体为在周期唤醒时利用串口输出当前RTC记录时间,当闹钟A/B事件发生时利用串口输出闹钟A/B事件发生提示

3、实验流程

3.0、前提知识

RTC的时钟可以由外部低速时钟LSE、外部高速时钟HSE经过2-31分频和内部RC振荡LSI三种时钟来源提供,但是一般我们都选择使用32.768kHz的LSE作为RTC的时钟源,因为32.768kHz的时钟频率可以经过128次分频,然后再经过256次分频得到一个较为精确的1Hz信号,此信号1s脉动一次,可以方便的用于更新日历,如下图所示(注释1)

另外RTC还有两个可编程的闹钟A/B,如果设置了闹钟A/B的时间,则闹钟A/B设定时间会和当前日历时间对比,如果时间相等,会产生ALRA/BF事件

周期唤醒可以使用RTC内部一个16位唤醒自动重载寄存器来实现,周期唤醒的时钟信号可以来自于更新日历的1Hz(ck_spre)信号,也可以使用RTC时钟的2/4/8/16分频后的时钟,设置该自动重载寄存器的值,根据时钟频率向上计数,当计数溢出时发生周期唤醒事件

闹钟A/B,周期唤醒产生的 ALRAF、 ALRBF和WUTF事件均可以输出到复用引脚RTC_AF1(PC13)

STM32F407的RTC还有20个32位的备份寄存器,其名字从RTC_BKP_DR0到RTC_BKP_DR19,定义在stm32f4xx_hal_rtc_ex.h文件中,RTC和备份寄存器均由单片机的备用电源VBAT提供,主电源VDD/VDDA断开不影响备份寄存器内容存储及RTC的正常运行

3.1、CubeMX相关配置

3.1.1 、时钟树配置

本文实验中RTC时钟信号源选择为外部32.768kHz的低速时钟LSE,与之前使用的STM32F407G-DISC1开发板在RCC及Clock Configuration页面中对LSE的设置不同,首先需要在Pinout & Configuration页面左边System Core/RCC中将原来Disable状态的Low Speed Clock(LSE)选择为Crystal/Ceramic Resonator,表示外部低速时钟LSE由32.768kHz的晶振提供,如下图所示

然后还是在这个页面,在Timers/RTC中单击Activate Clock Source,激活时钟源之后才可以对Clock Configuration页面的时钟修改,如下图所示

最后在Clock Configuration页面将输出到RTC时钟的时钟源选择为LSE,此时就已经配置好了RTC的输入时钟为32.768kHz的LSE,如下图所示

3.1.2、外设参数配置

单击Pinout & Configuration页面左边Timers/RTC

在该页面中间RTC Mode and Configuration中单击Activate Calendar激活日历,这里Alarm A、Alarm B和WakeUp均有Disable、Internal Alarm/WakeUp和Routed to AF1三个选项,分别表示不使用、单纯内部使用和输出到复用引脚AF1(PC13),注意由于AF1只有一个所以一旦某一个选择输出到了复用引脚AF1,其他便不可以设置

配置如下图所示

然后对启用的日历、Alarm A、Alarm B和WakeUp参数做不同的配置,这里比较通俗易懂,具体配置请看下图

3.1.3 、外设中断配置

在Pinout & Configuration页面左边System Core/NVIC中勾选闹钟A/B中断及周期唤醒中断,然后选择合适的中断优先级即可,另外串口中断可以不打开,本节实验输出采用阻塞传输数据的方式输出RTC时间

3.2、生成代码

请先阅读“STM32CubeMX STM32F4 HAL库 工程建立”实验3.4.3小节配置Project Manager

单击页面右上角GENERATE CODE生成工程

3.2.1、外设初始化函数调用流程

主函数中调用MX_RTC_Init()函数对RTC基本参数及日历时间、日历日期、闹钟A定时时间、闹钟B定时时间和周期唤醒等参数初始化/使能

在初始化RTC的函数HAL_RTC_Init()中调用了HAL_RTC_MspInit()函数完成了对RTC时钟使能,NVIC使能,NVIC优先级设置

如下图所示为上述的函数调用流程

3.2.2、外设中断函数调用流程

在stm32f4xx_it.c文件中新增了周期唤醒中断服务函数RTC_WKUP_IRQHandler()

在该RTC_WKUP_IRQHandler()函数中调用了HAL_RTCEx_WakeUpTimerIRQHandler()函数处理周期回调事件

最终调用了虚函数HAL_RTCEx_WakeUpTimerEventCallback(),该函数需要用户重新实现

如下图所示为周期唤醒中断函数调用流程

同时在stm32f4xx_it.c文件中新增了RTC闹钟A/B事件中断服务函数RTC_Alarm_IRQHandler()

在该RTC_Alarm_IRQHandler()函数中调用了HAL_RTC_AlarmIRQHandler()函数处理闹钟A/B事件

最后在该函数中调用了虚函数HAL_RTC_AlarmAEventCallback()处理闹钟A事件,调用虚函数HAL_RTCEx_AlarmBEventCallback()处理闹钟B事件

如下图所示为RTC闹钟A/B事件中断函数调用流程

3.2.3、添加其他必要代码

重新实现周期唤醒中断回调函数HAL_RTCEx_WakeUpTimerEventCallback()在rtc.c中,具体实现代码如下图所示

源代码如下

/*周期唤醒回调函数*/
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
    RTC_TimeTypeDef sTime;
    RTC_DateTypeDef sDate;
    if(HAL_RTC_GetTime(hrtc, &sTime, RTC_FORMAT_BIN) == HAL_OK)
    {
        HAL_RTC_GetDate(hrtc, &sDate,  RTC_FORMAT_BIN);
        char str[22];
        sprintf(str,"RTC Time= %2d:%2d:%2d\r\n",sTime.Hours,sTime.Minutes,sTime.Seconds);
        printf("%s", str);
    }
    HAL_GPIO_TogglePin(RED_LED_GPIO_Port,RED_LED_Pin);
}

重新实现闹钟A/B事件中断回调函数HAL_RTC_AlarmAEventCallback()和HAL_RTCEx_AlarmBEventCallback()在rtc.c中,具体代码如下所示

源代码如下

/*闹钟A事件回调函数*/
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    char infoA[]="Alarm A(xx:xx:15) trigger: \r\n";
    printf("%s", infoA);
    HAL_GPIO_TogglePin(GREEN_LED_GPIO_Port,GREEN_LED_Pin);
}

/*闹钟B事件回调函数*/
void HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *hrtc)
{
    char infoB[]="Alarm B(xx:0:30) trigger: \r\n";
    printf("%s", infoB);
    HAL_GPIO_TogglePin(GREEN_LED_GPIO_Port,GREEN_LED_Pin);
}

此时的代码可以正常运行,但存在一个问题,复位后重新执行RTC初始化函数会对RTC时间强制初始化为0:0:0,日期也会强制初始化,而我们想要设定的是当我们需要其初始化时就初始化,当一次初始化完毕之后,我不希望每次单片机复位时重新初始化

因此我们可以通过上述介绍的备份寄存器实现此功能,我们在RTC通用初始化结束之后,RTC日期和时间初始化之前处,添加判断RTC备份寄存器是否已被写入1来决定是否需要初始化时间和日期,如果已被写入1,则表示之前已完成日期和时间初始化,不需要再次重新初始化,因此启动周期唤醒后直接退出函数,如下图代码所示

源代码如下

//读取备份寄存R0
uint32_t iniRTC=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0);	
//非零
if((iniRTC & 0x01))  
{
    //使能周期唤醒
    if(HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0, RTC_WAKEUPCLOCK_CK_SPRE_16BITS) != HAL_OK)
        Error_Handler();

    //提前退出函数,不初始化时间和日期
    return;  
}

何时改变/写入RTC备份寄存器中的值呢?

这里笔者使用按键来控制,当按下WK_UP按键时,就翻转备份寄存器RTC_BKP_DR0中存储的值,也就是说按下一次WK_UP按键,备份寄存器RTC_BKP_DR0中的值会在0/1之间改变,如下图所示为主循环中的按键扫描程序

源代码如下

uint32_t iniRTC = HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR0);
iniRTC = !iniRTC;

if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin) == 1)
{
    HAL_Delay(50);
    if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin) == 1)
    {
        HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0, iniRTC);
        printf("Write RTC_BKP_DR0 %d\r\n", iniRTC);
        while(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin));
    }
}

4、常用函数

/*RTC周期回调中断服务函数*/
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)

/*RTC闹钟A中断服务函数*/
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)

/*RTC闹钟B中断服务函数*/
void HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *hrtc)

/*查询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备份寄存器的值*/
uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister)

/*写RTC备份寄存器的值*/
void HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data)

5、烧录验证

5.1、具体步骤

“RCC中启用LSE -> RTC中激活时钟源 -> Clock Configuration配置RTC时钟来源为LSE -> RTC中激活日历 -> 选择闹钟A/B、唤醒模式 -> 配置RTC、闹钟A/B和周期唤醒参数 -> NVIC中启动RTC闹钟A/B、周期唤醒中断 -> rtc.c中重新实现周期唤醒回调函数HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) -> 重新实现闹钟A事件回调函数HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) -> 重新实现闹钟B事件回调函数HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *hrtc) -> 在三个回调函数中利用串口编程实现输出信息提示”

5.2、实现现象

烧录程序,通过串口助手观察串口输出信息,每隔1秒,串口助手收到开发板传来的RTC时间信息,并且红色LED每一秒状态翻转一次,当时间到达0:0:15时,闹钟A触发,此时绿色LED灯状态翻转被点亮,随着时间继续流逝,当时间到达0:0:30时,闹钟B触发,此时此时绿色LED灯状态翻转被熄灭,此后每分钟的第15秒闹钟A会触发一次,每小时的0分30秒闹钟B会触发一次

按下WK_UP按键可以翻转备份寄存器RTC_BKP_DR0内存储的值,当备份寄存器RTC_BKP_DR0的值为1时,复位之后RTC的时间不会重置为0;

而当备份寄存器RTC_BKP_DR0的值为0时,复位之后RTC的时间会被重新初始化为0:0:0,串口输出信息如下图所示

细心的小伙伴可能发现0:0:15时刻的闹钟A没有响应,这是因为备份寄存器RTC_BKP_DR0的值为1时,我们在MX_RTC_Init初始化函数中初始化完毕RTC之后直接启动了周期唤醒然后整个函数就退出了,并没有对RTC的闹钟A/B进行初始化,如果你想兼顾两者功能,也可以编写程序不直接退出,而是绕过RTC时间和日期赋初值的代码,然后执行RTC的闹钟A/B的初始化

6、注释详解

注释1:图片来源STM32F4xx中文参考手册 RM0090

参考资料

STM32Cube高效开发教程(基础篇)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1343567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

听GPT 讲Rust源代码--src/tools(34)

File: rust/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs 文件"collection_is_never_read.rs"位于Rust源代码中的clippy_lints工具中,其作用是检查在集合类型(如Vec、HashMap等)的实例上执行的操作是否被忽略了…

[Angular] 笔记 19:路由参数

油管视频 Route Parameters 路由参数是跟在 url 后面的数字,字符串,或者 数字字符串,例如如下 url 中的 123,此类参数会传给后端: www.facebook.com/profile/123 首先将 pokemon-template-form 组件移到 pokeman-ba…

【开源】基于Vue+SpringBoot的房屋出售出租系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 房屋销售模块2.2 房屋出租模块2.3 预定意向模块2.4 交易订单模块 三、系统展示四、核心代码4.1 查询房屋求租单4.2 查询卖家的房屋求购单4.3 出租意向预定4.4 出租单支付4.5 查询买家房屋销售交易单 五、免责说明 一、摘…

Matlab:BP神经网络算法,二叉决策树

1、BP神经网络算法 (1)步骤 1.准备训练数据和目标值 2.创建并配置BP神经网络模型 3.训练BP神经网络模型 4.用BP神经网络模型预测数据 例:某企业第一年度营业额为132468,第二年度为158948,第三年度为183737,预测第四年度的营…

相位相关匹配法的opencv C++实现

前言:一个图像拼接的小项目,用途场景,显微图像的拼接,或者只包含x,y平移的图像拼接。本来是显微镜拼接工具,MIST的核心拼接代码,matlab版的,已经开源。下面是地址, GitH…

AI面板识别 - 华为OD统一考试

OD统一考试 (B卷) 分值: 100分 题解: Java / Python / C++ 题目描述 AI识别到面板上有N(1 ≤ N ≤ 100)个指示灯,灯大小一样,任意两个之间无重叠。 由于AI识别误差,每次别到的指示灯位置可能有差异,以4个坐标值描述AI识别的指示灯的大小和位置(左上角x1,y1,右下角x2…

Android NDK打包armeabi平台架包

NDK打包armeabi 1.降低NDK版本和Cmake版本 sdk.dirE\:\\Android\\sdk //指定ndk版本,不指定默认使用最新的NDK ndk.dirE\:\\Android\\sdk\\ndk\\16.1.4479499修改builde.gradle(app) android{defaultConfig{...//配置 AS 工程的 C/C 源文件编译参数externalNativ…

帆软FineBi V6版本经验总结

帆软FineBi V6版本经验总结 BI分析出现背景 ​ 现在是一个大数据的时代,每时每刻都有海量的明细数据出现。这时大数据时代用户思维是:1、数据的爆炸式增长,人们比起明细数据,更在意样本的整体特征、相互关系。2、基于明细的“小…

香橙派 ubuntu实现打通内网,外网双网络,有线和无线双网卡

当香橙派 ubuntu 连了有线,和无线时,默认请求外网时,只走一个网卡,如走了内网网卡,就只能访问内访问,访问不了外网;走了外网网卡就只能访问外网,访问不了内网; 实现双网…

如何使用Docker将.Net6项目部署到Linux服务器(三)

目录 四 安装nginx 4.1 官网下载nginx 4.2 下载解压安装nginx 4.3 进行configure 4.4 执行make 4.5 查看nginx是否安装成功 4.6 nginx的一些常用命令 4.6.1 启动nginx 4.6.2 通过命令查看nginx是否启动成功 4.6.3 关闭Nginx 4.6.5 重启Nginx 4.6.6 杀掉所有Nginx进程 4.…

嵌入式SOC之通用图像处理之OSD文字信息叠加的相关实践记录

机缘巧合 机缘巧合下, 在爱芯元智的xx开发板下进行sdk的开发.由于开发板目前我拿到是当前最新的一版(估计是样品),暂不公开开发板具体型号信息.以下简称板子 .很多优秀的芯片厂商,都会提供与开发板配套的完善的软件以及完善的技术支持(FAE),突然觉得爱芯…

C/C++转WebAssembly及微信小程序调用

上一篇文章讲了C/C如何转WebAssembly,并测试了在Web端调用。本篇内容和上篇一样,介绍C/C包转的.wasm包如何在小程序中调用。 说明 本篇是在上一篇步骤1-4的基础上,再做修改,供微信小程序端调用的方法和步骤。 本篇操作手册可以…

burpsuite模块介绍之repeater

导语 repeater是一个用于手动操作和发送个别HTTP请求的简单工具,它可以帮助您分析应用程序的响应。您可以使用repeater从Burp Suite的任何位置发送内部请求,然后修改请求并发送。通过这种方式,您可以测试和调试应用程序,并对请求…

思福迪运维安全管理系统 任意文件读取漏洞

产品简介 思福迪运维安全管理系统是思福迪开发的一款运维安全管理堡垒机 漏洞概述 由于思福迪运维安全管理系统 GetCaCert路由存在任意文件读取漏洞,攻击者可通过该漏洞在服务器端读取任意文件敏感内容,可能导致攻击者后续获取到相关的服务器权限 资…

nginx设置跨域访问

目录 一&#xff1a;前端请求 二&#xff1a;后端设置 网站架构前端使用jquery请求&#xff0c;后端使用nginxphp-fpm 一&#xff1a;前端请求 <script> $.getJSON(http://nngzh.youjoy.com/cc.php, { openid: sd, }, function(res) { alert(res); if(res.code 0) …

提升Windows系统安全性的一些有效的策略

假设一个杀猪的机器人感染了病毒&#xff0c;把人识别成了猪&#xff0c;&#xff0c;&#xff0c;&#xff0c;&#xff0c; 1&#xff1a;我偶然发现的&#xff1a;把所有向外的UDP都禁止&#xff0c;但是要开放53号端口&#xff0c;因为这是DNS通讯端口&#xff0c;没有这个…

关于log4j的那些坑

背景&#xff1a;工程中同时存在log4j.xml&log4j2.xml maven依赖如下&#xff1a; 此时工程实际使用的日志文件为log4j.xml 1、当同时设置log4j和log4j2的桥接依赖时 maven依赖如下&#xff1a; 此时启动会有警告日志&#xff1a; 点击告警日志链接&#xff1a;https://…

LTPI协议的理解——2、LTPI实现的底层架构

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 LTPI协议的理解——2、LTPI实现的底层架构 前言一、体系结构三、实现细节四、物理接口信号传输方法总结 前言 前面讲了LTPI的定义和大概结构&#xff0c;接下来继续理解LTPI…

rancher 手册

官方 https://www.rancher.com/https://github.com/rancher/rancherhttps://docs.rke2.io/ rancher kubernetesl yaml deploy rancher serverHelm Deploy Online Rancher DemoHelm & Kubernetes Offline Deploy Rancher v2.7.5 Demohelm upgrade rancher server from v2…

Visual Studio 配置DLL

我们在用Visual Studio进行开发时&#xff0c;如果没有正确配置DLL&#xff0c;就会出现类似“丢失***.dll”的错误。DLL配置有哪些方法&#xff1f; 1、手动复制 将dll文件拷贝到生成的.exe所在的文件夹里 2、配置环境 在右键属性->配置属性->调试->环境&#xf…