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

相关文章

Python标准库datetime模块日期和时间数据类型解读

《Python标准库datetime模块日期和时间数据类型解读》文章介绍Python中datetime模块的date、time、datetime类,用于处理日期、时间及日期时间结合体,通过属性获取时间... 目录Datetime常用类日期date类型使用时间 time 类型使用日期和时间的结合体–日期时间(

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

MySQL常用字符串函数示例和场景介绍

《MySQL常用字符串函数示例和场景介绍》MySQL提供了丰富的字符串函数帮助我们高效地对字符串进行处理、转换和分析,本文我将全面且深入地介绍MySQL常用的字符串函数,并结合具体示例和场景,帮你熟练... 目录一、字符串函数概述1.1 字符串函数的作用1.2 字符串函数分类二、字符串长度与统计函数2.1

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

Oracle数据库定时备份脚本方式(Linux)

《Oracle数据库定时备份脚本方式(Linux)》文章介绍Oracle数据库自动备份方案,包含主机备份传输与备机解压导入流程,强调需提前全量删除原库数据避免报错,并需配置无密传输、定时任务及验证脚本... 目录说明主机脚本备机上自动导库脚本整个自动备份oracle数据库的过程(建议全程用root用户)总结

SQL Server 中的 WITH (NOLOCK) 示例详解

《SQLServer中的WITH(NOLOCK)示例详解》SQLServer中的WITH(NOLOCK)是一种表提示,等同于READUNCOMMITTED隔离级别,允许查询在不获取共享锁的情... 目录SQL Server 中的 WITH (NOLOCK) 详解一、WITH (NOLOCK) 的本质二、工作

MySQL CTE (Common Table Expressions)示例全解析

《MySQLCTE(CommonTableExpressions)示例全解析》MySQL8.0引入CTE,支持递归查询,可创建临时命名结果集,提升复杂查询的可读性与维护性,适用于层次结构数据处... 目录基本语法CTE 主要特点非递归 CTE简单 CTE 示例多 CTE 示例递归 CTE基本递归 CTE 结

Spring AI使用tool Calling和MCP的示例详解

《SpringAI使用toolCalling和MCP的示例详解》SpringAI1.0.0.M6引入ToolCalling与MCP协议,提升AI与工具交互的扩展性与标准化,支持信息检索、行动执行等... 目录深入探索 Spring AI聊天接口示例Function CallingMCPSTDIOSSE结束语