STM32F1基于标准库工程RTC秒钟断+定时闹钟功能示例

2023-10-10 21:10

本文主要是介绍STM32F1基于标准库工程RTC秒钟断+定时闹钟功能示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

STM32F1基于标准库工程RTC秒钟断+定时闹钟功能示例


  • 🔖使用正点原子标准库工程模板创建。

  • 📍参考:https://mp.weixin.qq.com/s/0oLpg9Kjlfo4Z9q0s6lZuQ

  • 📋串口调试打印信息:
    在这里插入图片描述

  • 🚩本文仅针对STM32F1系列标准库函数使用。不适用于其他型号!!!

📗工程功能介绍

📜基于STM32F103,使用的是标准库,套用正点原子工程模板,使用STM32的RTC时钟系统中的秒中断和RTC 闹钟报警中断来执行相对应的代码。这里仅演示各中断功能响应执行的代码。可以参考此功能模块自行移植。

📓RTC秒中断和闹钟驱动

  • 📝RTC.C
#include "rtc.h"_calendar_obj calendar;    //时钟结构体
const u8 mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};static void RTC_Alarm_EXIT(void)
{EXTI_InitTypeDef EXTI_InitStructure;EXTI_ClearITPendingBit(EXTI_Line17);EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Line = EXTI_Line17;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);}
/*** @brief  Configure the RTC peripheral by selecting the clock source.* @param  None* @retval None*/
void RTC_Config(void)
{NVIC_InitTypeDef NVIC_InitStructure;/* 使能PWR和BKP时钟 *//* Enable PWR and BKP clocks */RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);/* 使能对后备寄存器的访问 *//* Allow access to BKP Domain */PWR_BackupAccessCmd(ENABLE);/* 复位BKP寄存器 *//* Reset Backup Domain */BKP_DeInit();/* 将 RTC时钟设置为LSE这个32.768KHZ的晶振*//* Enable LSE */RCC_LSEConfig(RCC_LSE_ON);/* Wait till LSE is ready */while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}/* Select LSE as RTC Clock Source */RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);/* 使能RTC Clock *//* Enable RTC Clock */RCC_RTCCLKCmd(ENABLE);/* 等待同步 *//* Wait for RTC registers synchronization */RTC_WaitForSynchro();/* 等待对RTC寄存器最后的写操作完成*//* Wait until last write operation on RTC registers has finished */RTC_WaitForLastTask();/* 使能RTC秒中断 *//* Enable the RTC Second */RTC_ITConfig(RTC_IT_SEC, ENABLE);//使能秒钟断和闹钟中断RTC_ITConfig(RTC_IT_ALR, ENABLE);//使能秒钟断和闹钟中断/* 等待对RTC寄存器最后的写操作完成*//* Wait until last write operation on RTC registers has finished */RTC_WaitForLastTask();/* 配置了预分频值: 设置RTC时钟周期为1s *//* Set RTC prescaler: set RTC period to 1sec */RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) *//* 等待对RTC寄存器最后的写操作完成*//* Wait until last write operation on RTC registers has finished */RTC_WaitForLastTask();/* Enable the RTC Alarm Interrupt */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_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn; //闹钟中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =  1; //比RTC全局中断的优先级高NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);RTC_Alarm_EXIT();}u8 Is_Leap_Year(u16 pyear)
{if(pyear % 4 == 0) //首先需能被4整除{if(pyear % 100 == 0){if(pyear % 400 == 0)    return 1; //如果以00结尾,还要能被400整除else    return 0;}elsereturn 1;}elsereturn 0;
}
/*
得到当前的时间
成功返回0,错误返回其它
*/
u8 RTC_Get(void)
{static u16 dayCount = 0;u32 secCount = 0;volatile u32 tmp = 0;u16 tmp1 = 0;secCount = RTC_GetCounter();tmp = secCount / 86400; //得到天数if(dayCount != tmp) //超过一天{dayCount = tmp;tmp1 = 1970; //从1970年开始while(tmp >= 365){if(Is_Leap_Year(tmp1))//是闰年{if(tmp >= 366)tmp -= 366; //减掉闰年的天数else{//    tmp1++;break;}}elsetmp -= 365; //平年tmp1++;}calendar.w_year = tmp1; //得到年份tmp1 = 0;while(tmp >= 28) //超过一个月{if(Is_Leap_Year(calendar.w_year) && tmp1 == 1) //当年是闰年且轮循到2月{if(tmp >= 29)tmp -= 29;elsebreak;}else{if(tmp >= mon_table[tmp1]) //平年tmp -= mon_table[tmp1];elsebreak;}tmp1++;}calendar.w_month = tmp1 + 1; //得到月份,tmp1=0表示1月,所以要加1calendar.w_date = tmp + 1; //得到日期,因为这一天还没过完,所以tmp只到其前一天,但是显示的时候要显示正常日期}tmp = secCount % 86400; //得到秒钟数calendar.hour = tmp / 3600; //小时calendar.min = (tmp % 3600) / 60; //分钟calendar.sec = (tmp % 3600) % 60; //秒return 0;
}
/*
*设置时钟
*把输入的时钟转换为秒钟
*以1970年1月1日为基准
*1970~2099年为合法年份
返回值:0,成功;其它:错误
*/
u8 RTC_Set(u16 year, u8 mon, u8 day, u8 hour, u8 min, u8 sec)
{u16 t;u32 secCount = 0;if(year < 1970 || year > 2099)return 1;//for(t = 1970; t < year; t++) //把所有年份的秒钟相加{if(Is_Leap_Year(t))//闰年secCount += 31622400; //闰年的秒钟数elsesecCount += 31536000;}mon -= 1; //先减掉一个月再算秒数(如现在是5月10日,则只需要算前4个月的天数,再加上10天,然后计算秒数)for(t = 0; t < mon; t++){secCount += (u32)mon_table[t] * 86400; //月份秒钟数相加if(Is_Leap_Year(year) && t == 1)secCount += 86400; //闰年,2月份增加一天的秒钟数}secCount += (u32)(day - 1) * 86400; //把前面日期的秒钟数相加(这一天还没过完,所以-1)secCount += (u32)hour * 3600; //小时秒钟数secCount += (u32)min * 60; //分钟秒钟数secCount += sec;
//    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR    | RCC_APB1Periph_BKP,ENABLE);
//    PWR_BackupAccessCmd(ENABLE);RTC_SetCounter(secCount);//设置RTC计数器的值RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成RTC_Get();//更新时间return 0;
}
  • 📝RTC.H
#ifndef __RTC_H
#define __RTC_H
#include "stm32f10x.h"//时间结构体
typedef struct 
{vu8 hour;vu8 min;vu8 sec;            //公历年月日周vu16 w_year;vu8  w_month;vu8  w_date;vu8  week;     
}_calendar_obj;  extern _calendar_obj calendar;void RTC_Config(void);
void RTC_Init(void);
u8 RTC_Set(u16 year,u8 mon,u8 day,u8 hour,u8 min,u8 sec);
u8 RTC_Get(void);
#endif

📑main主程序

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "rtc.h"
#include <stdio.h>volatile unsigned char RTC_IT_SEC_flag = 0;
/* Private function prototypes -----------------------------------------------*/
void LEDInit(void);/* Private functions ---------------------------------------------------------*/
/*** @brief  Configures LED GPIO.* @retval None*/
void LEDInit(void)
{GPIO_InitTypeDef  GPIO_InitStructure;/* Enable the GPIO Clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);/* Configure the GPIO pin */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOE, &GPIO_InitStructure);
}int main(void)
{volatile u8 t = 0;delay_init();	    	 //延时函数初始化/* Configure RTC */RTC_Config();RTC_Set(2023, 6, 14, 12, 27, 5); //RTC_EnterConfigMode();RTC_SetAlarm(6 + RTC_GetCounter());//配置下次闹钟RTC_WaitForLastTask();RTC_ExitConfigMode();NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级uart_init(115200);	 //串口初始化为115200LEDInit();while(1){/* Show Time */if(t != calendar.sec)
//        if(RTC_IT_SEC_flag){t = calendar.sec;printf("NowTime:%d 年 %d 月 %d 日 %d 时 %d 分 %d 秒 \r\n ", \calendar.w_year, calendar.w_month, calendar.w_date, calendar.hour, calendar.min, calendar.sec);
//            RTC_IT_SEC_flag = 0;}}
}
/*** @brief  This function handles RTC global interrupt request.* @param  None* @retval None*/
void RTC_IRQHandler(void)
{if(RTC_GetITStatus(RTC_IT_SEC) != RESET) //秒钟中断{/* Clear the RTC Second interrupt */RTC_ClearITPendingBit(RTC_IT_SEC);RTC_Get();//更新时间
//        RTC_IT_SEC_flag = 1;/* Toggle LED */GPIOE->ODR ^= GPIO_Pin_5;printf("RTC_IT_SEC!\r\n");/* Wait until last write operation on RTC registers has finished */RTC_WaitForLastTask();}
}void RTCAlarm_IRQHandler(void)
{if(RTC_GetITStatus(RTC_IT_ALR) != RESET) //ALR中断{EXTI_ClearITPendingBit(EXTI_Line17);RTC_WaitForLastTask();printf("Alarm clock!\r\n");/* Clear the RTC ALR interrupt */RTC_ClearITPendingBit(RTC_IT_ALR);PWR_BackupAccessCmd(ENABLE);RTC_EnterConfigMode();RTC_SetAlarm(6 + RTC_GetCounter());//配置下次闹钟/* Wait until last write operation on RTC registers has finished */RTC_WaitForLastTask();RTC_ExitConfigMode();PWR_BackupAccessCmd(DISABLE);}RTC_ClearITPendingBit(RTC_IT_OW);/* Wait until last write operation on RTC registers has finished */RTC_WaitForLastTask();}

📚工程源码

链接:https://pan.baidu.com/s/1Zl6vd0h_uHkYnrfIYxtmMQ 
提取码:2xk3

这篇关于STM32F1基于标准库工程RTC秒钟断+定时闹钟功能示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/183119

相关文章

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java高效实现PowerPoint转PDF的示例详解

《Java高效实现PowerPoint转PDF的示例详解》在日常开发或办公场景中,经常需要将PowerPoint演示文稿(PPT/PPTX)转换为PDF,本文将介绍从基础转换到高级设置的多种用法,大家... 目录为什么要将 PowerPoint 转换为 PDF安装 Spire.Presentation fo

使用EasyPoi快速导出Word文档功能的实现步骤

《使用EasyPoi快速导出Word文档功能的实现步骤》EasyPoi是一个基于ApachePOI的开源Java工具库,旨在简化Excel和Word文档的操作,本文将详细介绍如何使用EasyPoi快速... 目录一、准备工作1、引入依赖二、准备好一个word模版文件三、编写导出方法的工具类四、在Export

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数

python中的高阶函数示例详解

《python中的高阶函数示例详解》在Python中,高阶函数是指接受函数作为参数或返回函数作为结果的函数,下面:本文主要介绍python中高阶函数的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录1.定义2.map函数3.filter函数4.reduce函数5.sorted函数6.自定义高阶函数

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

Vue实现路由守卫的示例代码

《Vue实现路由守卫的示例代码》Vue路由守卫是控制页面导航的钩子函数,主要用于鉴权、数据预加载等场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、概念二、类型三、实战一、概念路由守卫(Navigation Guards)本质上就是 在路

JAVA实现Token自动续期机制的示例代码

《JAVA实现Token自动续期机制的示例代码》本文主要介绍了JAVA实现Token自动续期机制的示例代码,通过动态调整会话生命周期平衡安全性与用户体验,解决固定有效期Token带来的风险与不便,感兴... 目录1. 固定有效期Token的内在局限性2. 自动续期机制:兼顾安全与体验的解决方案3. 总结PS

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

Python屏幕抓取和录制的详细代码示例

《Python屏幕抓取和录制的详细代码示例》随着现代计算机性能的提高和网络速度的加快,越来越多的用户需要对他们的屏幕进行录制,:本文主要介绍Python屏幕抓取和录制的相关资料,需要的朋友可以参考... 目录一、常用 python 屏幕抓取库二、pyautogui 截屏示例三、mss 高性能截图四、Pill