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;
        }
        else
            return 1;
    }
    else
        return 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;
                }
            }
            else
                tmp -= 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;
                else
                    break;
            }
            else
            {
                if(tmp >= mon_table[tmp1]) //平年
                    tmp -= mon_table[tmp1];
                else
                    break;
            }
            tmp1++;
        }
        calendar.w_month = tmp1 + 1; //得到月份,tmp1=0表示1月,所以要加1
        calendar.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; //闰年的秒钟数
        else
            secCount += 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);	 //串口初始化为115200
    LEDInit();
    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
  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值