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

相关文章

Java中StopWatch的使用示例详解

《Java中StopWatch的使用示例详解》stopWatch是org.springframework.util包下的一个工具类,使用它可直观的输出代码执行耗时,以及执行时间百分比,这篇文章主要介绍... 目录stopWatch 是org.springframework.util 包下的一个工具类,使用它

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

SpringIntegration消息路由之Router的条件路由与过滤功能

《SpringIntegration消息路由之Router的条件路由与过滤功能》本文详细介绍了Router的基础概念、条件路由实现、基于消息头的路由、动态路由与路由表、消息过滤与选择性路由以及错误处理... 目录引言一、Router基础概念二、条件路由实现三、基于消息头的路由四、动态路由与路由表五、消息过滤

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

基于SpringBoot实现文件秒传功能

《基于SpringBoot实现文件秒传功能》在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复... 目录前言文件秒传原理代码实现1. 创建项目基础结构2. 创建上传存储代码3. 创建Result类4.

springboot security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

一文详解SpringBoot响应压缩功能的配置与优化

《一文详解SpringBoot响应压缩功能的配置与优化》SpringBoot的响应压缩功能基于智能协商机制,需同时满足很多条件,本文主要为大家详细介绍了SpringBoot响应压缩功能的配置与优化,需... 目录一、核心工作机制1.1 自动协商触发条件1.2 压缩处理流程二、配置方案详解2.1 基础YAML

golang 日志log与logrus示例详解

《golang日志log与logrus示例详解》log是Go语言标准库中一个简单的日志库,本文给大家介绍golang日志log与logrus示例详解,感兴趣的朋友一起看看吧... 目录一、Go 标准库 log 详解1. 功能特点2. 常用函数3. 示例代码4. 优势和局限二、第三方库 logrus 详解1.

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.