当前位置: 首页 > article >正文

RTC:实时时钟

RTC:实时时钟

  • 1、实时时钟
  • 2、闹钟中断
  • 3、秒中断
  • 4、输出功能
  • 5、BKP的读写
  • 6、BKP的侵入事件

1、实时时钟

①RTC.c

#include "RTC.h"

/**
 * @brief:RTC初始化函数
 */
RCC_PeriphCLKInitTypeDef RTCPeriphClkInit;  //RTC时钟配置结构体
RTC_HandleTypeDef hrtc;                     //RTC配置结构体
void RTC_Init(void)
{
    /* 配置RTC的时钟源 */
    RTCPeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC; //需要配置的外设:RTC
    RTCPeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; //RTC时钟源:LSE(外部低速时钟)
    HAL_RCCEx_PeriphCLKConfig(&RTCPeriphClkInit);
    
    /* RTC的初始化配置 */
    __HAL_RCC_RTC_ENABLE();                     //使能RTC的时钟
    __HAL_RCC_PWR_CLK_ENABLE();                 //使能PWR的时钟
    __HAL_RCC_BKP_CLK_ENABLE();                 //使能BKP的时钟
    hrtc.Instance = RTC;                        //选择RTC
    hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND; //时钟源的分频值,1Hz
    hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;   //无输出
    HAL_RTC_Init(&hrtc);
}

/**
 * @brief:HAL_RTC_Init()调用函数
 */
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
    /* 其他的配置 */
}

/**
 * @brief:日期转换为时间戳秒函数
 */
void Time_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec)
{
    struct tm DayData;              //定义结构体变量DayData
    DayData.tm_year = Year - 1900;  //设置为2025年
    DayData.tm_mon = Mon;           //设置为1月
    DayData.tm_mday = Day;          //设置为2号
    DayData.tm_hour = Hour;         //设置为20时
    DayData.tm_min = Min;           //设置为04分
    DayData.tm_sec = Sec;           //设置为40秒
    
    time_t temp = mktime(&DayData);                     //将设置的日期转换为时间挫数据
    __HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc);           //关闭RTC写保护
    WRITE_REG(hrtc.Instance->CNTH,(temp >> 16));        //将转换好的时间挫写入RTC计数寄存器高16位
    WRITE_REG(hrtc.Instance->CNTL,temp & 0x0000FFFF);   //将转换好的时间挫写入RTC计数寄存器低16位
    __HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc);            //开启RTC写保护
}


/**
 * @brief:将RTC中的计数器寄存器值转换为日期
 */
struct tm* Time_Get(void)
{
    /* 读取数据寄存器的值 */
    time_t temp = (READ_REG(hrtc.Instance->CNTH) << 16) | READ_REG(hrtc.Instance->CNTL);

    /* 将计数器的值转换为日期 */
    return localtime(&temp);//将时间戳转换为本地的年月日时分秒
}

②RTC.h

#ifndef __RTC_H
#define __RTC_H

#include "stm32f1xx_hal.h"
#include <time.h>
extern RTC_HandleTypeDef hrtc;  //RTC配置结构体
void RTC_Init(void);
void Time_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec);
struct tm* Time_Get(void);

#endif

③main.c

#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "RTC.h"
#include "UART.h"

struct tm* Day; 
int main(void){
    
	HAL_Init();
	HSE_RCC_Init(); 
	UART1_Init(115200);
    RTC_Init();
    printf("代码测试\r\n");
    Time_Set(2025,1,2,21,8,30);//2025-01-02 20:55:30

	while(1){
       Day = Time_Get();
        printf("%d-%d-%d %d:%d:%d\r\n"
        ,Day->tm_year + 1900,Day->tm_mon,Day->tm_mday,Day->tm_hour,Day->tm_min,Day->tm_sec);
        HAL_Delay(1000);
	}	
}

在这里插入图片描述

2、闹钟中断

①RTC.c

#include "RTC.h"

/**
 * @brief:RTC初始化函数
 */
RCC_PeriphCLKInitTypeDef RTCPeriphClkInit;  //RTC时钟配置结构体
RTC_HandleTypeDef hrtc;                     //RTC配置结构体
void RTC_Init(void)
{
    /* 配置RTC的时钟源 */
    RTCPeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC; //需要配置的外设:RTC
    RTCPeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; //RTC时钟源:LSE(外部低速时钟)
    HAL_RCCEx_PeriphCLKConfig(&RTCPeriphClkInit);
    
    /* RTC的初始化配置 */
    __HAL_RCC_RTC_ENABLE();                     //使能RTC的时钟
    __HAL_RCC_PWR_CLK_ENABLE();                 //使能PWR的时钟
    __HAL_RCC_BKP_CLK_ENABLE();                 //使能BKP的时钟
    hrtc.Instance = RTC;                        //选择RTC
    hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND; //时钟源的分频值,1Hz
    hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;   //无输出
    HAL_RTC_Init(&hrtc);
    
    /* 开启闹钟中断 */
    __HAL_RTC_ALARM_CLEAR_FLAG(&hrtc, RTC_FLAG_ALRAF);  //清除闹钟标志
    __HAL_RTC_ALARM_ENABLE_IT(&hrtc, RTC_IT_ALRA);      //开启闹钟中断
    __HAL_RTC_ALARM_EXTI_ENABLE_IT();                   //开启闹钟外部中断线,EXTI17为闹钟事件
    __HAL_RTC_ALARM_EXTI_ENABLE_RISING_EDGE();          //上升沿触发
    HAL_NVIC_SetPriority(RTC_Alarm_IRQn,3,0);
    HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
}

/**
 * @brief:HAL_RTC_Init()调用函数
 */
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
    /* 其他的配置 */
}

/**
 * @brief:日期转换为时间挫函数
 */
void Time_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec)
{
    struct tm DayData;              //定义结构体变量DayData
    DayData.tm_year = Year - 1900;  //设置为2025年
    DayData.tm_mon = Mon;           //设置为1月
    DayData.tm_mday = Day;          //设置为2号
    DayData.tm_hour = Hour;         //设置为20时
    DayData.tm_min = Min;           //设置为04分
    DayData.tm_sec = Sec;           //设置为40秒
    
    time_t temp = mktime(&DayData);                     //将设置的日期转换为时间挫数据
    __HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc);           //关闭RTC写保护
    WRITE_REG(hrtc.Instance->CNTH,(temp >> 16));        //将转换好的时间挫写入RTC计数寄存器高16位
    WRITE_REG(hrtc.Instance->CNTL,temp & 0x0000FFFF);   //将转换好的时间挫写入RTC计数寄存器低16位
    __HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc);            //开启RTC写保护
    HAL_Delay(20);                                      //等待写保护成功,必须要有
}

/**
 * @brief:闹钟时间转换为时间挫函数
 */
void AlarmTime_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec)
{
    struct tm DayData;              //定义结构体变量DayData
    DayData.tm_year = Year - 1900;  //设置为2025年
    DayData.tm_mon = Mon;           //设置为1月
    DayData.tm_mday = Day;          //设置为2号
    DayData.tm_hour = Hour;         //设置为20时
    DayData.tm_min = Min;           //设置为04分
    DayData.tm_sec = Sec;           //设置为40秒
    
    time_t temp = mktime(&DayData);                     //将设置的日期转换为时间挫数据
    __HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc);           //关闭RTC写保护
    WRITE_REG(hrtc.Instance->ALRH,(temp >> 16));        //将转换好的时间挫写入RTC闹钟寄存器高16位
    WRITE_REG(hrtc.Instance->ALRL,temp & 0x0000FFFF);   //将转换好的时间挫写入RTC闹钟寄存器低16位
    __HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc);            //开启RTC写保护
    HAL_Delay(20);                                      //等待写保护成功,必须要有
}

/**
 * @brief:将RTC中的计数器寄存器值转换为日期
 */
struct tm* Time_Get(void)
{
    /* 读取数据寄存器的值 */
    time_t temp = (READ_REG(hrtc.Instance->CNTH) << 16) | READ_REG(hrtc.Instance->CNTL);

    /* 将计数器的值转换为日期 */
    return localtime(&temp);//将时间戳转换为本地的年月日时分秒
}

②RTC.h

#ifndef __RTC_H
#define __RTC_H

#include "stm32f1xx_hal.h"
#include <time.h>
extern RTC_HandleTypeDef hrtc;  //RTC配置结构体
void RTC_Init(void);
void Time_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec);
void AlarmTime_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec);
struct tm* Time_Get(void);

#endif

③main.c

#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "RTC.h"
#include "UART.h"

struct tm* Day; 
int main(void){
    
	HAL_Init();
	HSE_RCC_Init(); 
	UART1_Init(115200);
    RTC_Init();
    printf("代码测试\r\n");
    Time_Set(2025,1,2,21,8,30);         //2025-01-02 20:55:30
    AlarmTime_Set(2025,1,2,21,8,35);    //闹钟时钟为2025-01-02 20:55:35
	while(1){
       Day = Time_Get();
        printf("%d-%d-%d %d:%d:%d\r\n"
        ,Day->tm_year + 1900,Day->tm_mon,Day->tm_mday,Day->tm_hour,Day->tm_min,Day->tm_sec);
        HAL_Delay(1000);
	}	
}

④stm32f1xx_it.c

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "RTC.h" 
#include "UART.h"

/**
 * @brief:RTC闹钟中断服务函数
 */
void RTC_Alarm_IRQHandler(void)
{
    HAL_RTC_AlarmIRQHandler(&hrtc);
}
/******************* 下面的中断的回调函数 ***************************/
/**
 * @brief:RTC闹钟中断回调函数函数
 */
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    printf("起床啦!\r\n");
}

在这里插入图片描述

3、秒中断

①RTC.c

#include "RTC.h"

/**
 * @brief:RTC初始化函数
 */
RCC_PeriphCLKInitTypeDef RTCPeriphClkInit;  //RTC时钟配置结构体
RTC_HandleTypeDef hrtc;                     //RTC配置结构体
void RTC_Init(void)
{
    /* 配置RTC的时钟源 */
    RTCPeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC; //需要配置的外设:RTC
    RTCPeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; //RTC时钟源:LSE(外部低速时钟)
    HAL_RCCEx_PeriphCLKConfig(&RTCPeriphClkInit);
    
    /* RTC的初始化配置 */
    __HAL_RCC_RTC_ENABLE();                     //使能RTC的时钟
    __HAL_RCC_PWR_CLK_ENABLE();                 //使能PWR的时钟
    __HAL_RCC_BKP_CLK_ENABLE();                 //使能BKP的时钟
    hrtc.Instance = RTC;                        //选择RTC
    hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND; //时钟源的分频值,1Hz
    hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;   //无输出
    HAL_RTC_Init(&hrtc);
    
    /* 开启秒中断 */
    HAL_RTCEx_SetSecond_IT(&hrtc);              //开启秒中断
    HAL_NVIC_SetPriority(RTC_IRQn,3,0);
    HAL_NVIC_EnableIRQ(RTC_IRQn);
}

/**
 * @brief:HAL_RTC_Init()调用函数
 */
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
    /* 其他的配置 */
}

/**
 * @brief:日期转换为时间挫函数
 */
void Time_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec)
{
    struct tm DayData;              //定义结构体变量DayData
    DayData.tm_year = Year - 1900;  //设置为2025年
    DayData.tm_mon = Mon;           //设置为1月
    DayData.tm_mday = Day;          //设置为2号
    DayData.tm_hour = Hour;         //设置为20时
    DayData.tm_min = Min;           //设置为04分
    DayData.tm_sec = Sec;           //设置为40秒
    
    time_t temp = mktime(&DayData);                     //将设置的日期转换为时间挫数据
    __HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc);           //关闭RTC写保护
    WRITE_REG(hrtc.Instance->CNTH,(temp >> 16));        //将转换好的时间挫写入RTC计数寄存器高16位
    WRITE_REG(hrtc.Instance->CNTL,temp & 0x0000FFFF);   //将转换好的时间挫写入RTC计数寄存器低16位
    __HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc);            //开启RTC写保护
    HAL_Delay(20);                                      //等待写保护成功,必须要有
}

/**
 * @brief:闹钟时间转换为时间挫函数
 */
void AlarmTime_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec)
{
    struct tm DayData;              //定义结构体变量DayData
    DayData.tm_year = Year - 1900;  //设置为2025年
    DayData.tm_mon = Mon;           //设置为1月
    DayData.tm_mday = Day;          //设置为2号
    DayData.tm_hour = Hour;         //设置为20时
    DayData.tm_min = Min;           //设置为04分
    DayData.tm_sec = Sec;           //设置为40秒
    
    time_t temp = mktime(&DayData);                     //将设置的日期转换为时间挫数据
    __HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc);           //关闭RTC写保护
    WRITE_REG(hrtc.Instance->ALRH,(temp >> 16));        //将转换好的时间挫写入RTC闹钟寄存器高16位
    WRITE_REG(hrtc.Instance->ALRL,temp & 0x0000FFFF);   //将转换好的时间挫写入RTC闹钟寄存器低16位
    __HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc);            //开启RTC写保护
    HAL_Delay(20);                                      //等待写保护成功,必须要有
}

/**
 * @brief:将RTC中的计数器寄存器值转换为日期
 */
struct tm* Time_Get(void)
{
    /* 读取数据寄存器的值 */
    time_t temp = (READ_REG(hrtc.Instance->CNTH) << 16) | READ_REG(hrtc.Instance->CNTL);

    /* 将计数器的值转换为日期 */
    return localtime(&temp);//将时间戳转换为本地的年月日时分秒
}

②RTC.h

#ifndef __RTC_H
#define __RTC_H

#include "stm32f1xx_hal.h"
#include <time.h>
extern RTC_HandleTypeDef hrtc;  //RTC配置结构体
void RTC_Init(void);
void Time_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec);
void AlarmTime_Set(int Year,int Mon,int Day,int Hour,int Min,int Sec);
struct tm* Time_Get(void);

#endif

③main.c

#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "RTC.h"
#include "UART.h"
#include "LED.h"

struct tm* Day; 
int main(void){
    
	HAL_Init();
	HSE_RCC_Init(); 
	UART1_Init(115200);
    LED_GPIO_Init();
    RTC_Init();
    printf("代码测试\r\n");
    Time_Set(2025,1,2,21,8,30);         //2025-01-02 20:55:30
    
	while(1){
       Day = Time_Get();
        printf("%d-%d-%d %d:%d:%d\r\n"
        ,Day->tm_year + 1900,Day->tm_mon,Day->tm_mday,Day->tm_hour,Day->tm_min,Day->tm_sec);
        HAL_Delay(1000);
	}	
}

④stm32f1xx_it.c

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "RTC.h" 
#include "UART.h"
#include "LED.h"

/**
 * @brief:RTC秒中断服务函数
 */
void RTC_IRQHandler(void)
{
    HAL_RTCEx_RTCIRQHandler(&hrtc);
}

/******************* 下面的中断的回调函数 ***************************/
/**
 * @brief:RTC秒中断回调函数
 */
void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc)
{
    LED_Turn();
}

4、输出功能

①RTC.c文件需要修改的代码如下

hrtc.Init.OutPut = RTC_OUTPUTSOURCE_SECOND; //输出:秒脉冲
hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM ; //输出:闹钟脉冲
hrtc.Init.OutPut = RTC_OUTPUTSOURCE_CALIBCLOCK; //输出:32768Hz/64后的脉冲

输出引脚是PC13,但是不用配置它。其他的代码不用修改

5、BKP的读写

BKP的读写需要RTC的配置,但是不需要开启LSE的时钟源。只需要打开RTC时钟+配置RTC总控结构体
①RTC.c文件的代码如下

#include "RTC.h"

/**
 * @brief:RTC初始化函数
 */
RTC_HandleTypeDef hrtc;                     //RTC配置结构体
void RTC_Init(void)
{    
    /* RTC的初始化配置 */
    __HAL_RCC_RTC_ENABLE();                     //使能RTC的时钟
    __HAL_RCC_PWR_CLK_ENABLE();                 //使能PWR的时钟
    __HAL_RCC_BKP_CLK_ENABLE();                 //使能BKP的时钟
    hrtc.Instance = RTC;                        //选择RTC
    HAL_RTC_Init(&hrtc);
}

/**
 * @brief:HAL_RTC_Init()调用函数
 */
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
    /* 其他的配置 */
}

②main.c文件的代码如下

#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "RTC.h"
#include "UART.h"

uint16_t Data = 0x1234;
int main(void){
    
	HAL_Init();
	HSE_RCC_Init(); 
	UART1_Init(115200);
    RTC_Init();										//初始化BKP
    printf("代码测试\r\n");
   
    HAL_RTCEx_BKUPWrite(&hrtc, 1, Data);            //向BKP的第一个数据寄存器写入数据
    printf("%x\r\n",HAL_RTCEx_BKUPRead(&hrtc, 1));  //读取BKP的第一个数据寄存器的数据
    
	while(1){

	}	
}

在这里插入图片描述

6、BKP的侵入事件

若发生了侵入事件,会将BKP中的数据清除(主电源断电,侵入事件也有效)。侵入事件检测引脚为PC13且检测电平。但是我们不用配置PC13。
在这里插入图片描述当侵入事件产生后,应该先关闭侵入检测。需要侵入检测则重新调用API函数开启侵入检测。
①RTC.c文件的代码如下

#include "RTC.h"

/**
 * @brief:RTC初始化函数
 */
RTC_HandleTypeDef hrtc;                     //RTC配置结构体
RTC_TamperTypeDef Tamper;                   //侵入事件配置结构体
void RTC_Init(void)
{    
    /* RTC的初始化配置 */
    __HAL_RCC_RTC_ENABLE();                     //使能RTC的时钟
    __HAL_RCC_PWR_CLK_ENABLE();                 //使能PWR的时钟
    __HAL_RCC_BKP_CLK_ENABLE();                 //使能BKP的时钟
    hrtc.Instance = RTC;                        //选择RTC
    HAL_RTC_Init(&hrtc);
    
    /* 侵入事件配置 */
    Tamper.Tamper = RTC_TAMPER_1;                   //指定引脚:PC13
    Tamper.Trigger = RTC_TAMPERTRIGGER_HIGHLEVEL;   //高电平触发
    HAL_RTCEx_SetTamper_IT(&hrtc,&Tamper);          //配置侵入事件,开启中断
    HAL_NVIC_SetPriority(TAMPER_IRQn,3,0);
    HAL_NVIC_EnableIRQ(TAMPER_IRQn);
}

②main.c文件的代码如下

#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "RTC.h"
#include "UART.h"


uint16_t Data = 0x1234;
int main(void){
    
	HAL_Init();
	HSE_RCC_Init(); 
	UART1_Init(115200);
    RTC_Init();										//初始化BKP,初始化侵入事件
    printf("代码测试\r\n");
   
    HAL_RTCEx_BKUPWrite(&hrtc, 1, Data);            //向BKP的第一个数据寄存器写入数据
    printf("%x\r\n",HAL_RTCEx_BKUPRead(&hrtc, 1));  //读取BKP的第一个数据寄存器的数据
    
	while(1){

	}	
}

③stm32f1xx_it.c文件的代码如下

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "RTC.h" 
#include "UART.h"

/**
 * @brief:RTC侵入事件中断服务函数
 */
void TAMPER_IRQHandler(void)
{
    HAL_RTCEx_TamperIRQHandler(&hrtc);
}

/******************* 下面的中断的回调函数 ***************************/
/**
 * @brief:RTC侵入中断回调函数
 */
void HAL_RTCEx_Tamper1EventCallback(RTC_HandleTypeDef *hrtc)
{
    printf("发生侵入事件了\r\n");
    HAL_RTCEx_DeactivateTamper(hrtc, RTC_TAMPER_1);//关闭侵入事件
}

http://www.kler.cn/a/471700.html

相关文章:

  • [备忘.OFD]OFD是什么、OFD与PDF格式文件的互转换
  • java集成stable diffusion
  • JavaScript之JQuery
  • 【Logstash02】企业级日志分析系统ELK之Logstash 输入 Input 插件
  • 【数据结构-堆】力扣3275. 第 K 近障碍物查询
  • 湖南家居现代风,让生活充满舒适感
  • 深入理解 TCP 协议
  • conda安装及demo:SadTalker实现图片+音频生成高质量视频
  • 如何 cURL Elasticsearch:进入 Shell
  • 基于机器学习的京东手机商品评论数据可视化分析系统
  • 一、二极管(应用篇)
  • JimuReport 积木报表 v1.9.2 发布,免费可视化报表
  • Java-JVM详解
  • nginx运行之后显示的是上一个项目,如何解决
  • Linux 系统中 FTP 文件操作常用命令
  • uniapp 使用vue3写法,拿不到uni-popup的ref
  • 深入理解Java并发控制:AQS与ReentrantLock
  • pyarmor加密python脚本
  • 若依框架简介
  • ffmpeg将mp4等文件转mp3