HAL库RTC时间戳和日期之间的相互转化

 1.RTC初始化 (为了兼容有无外部晶振程序都可正常运行,增加和更改了初始化相关函数)

void hal_rtc_init(void)
{
    uint32_t tickstart = 0;
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    HAL_PWR_EnableBkUpAccess();   //使能后备域访问
    __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);////设置外部低速晶振驱动能力
        
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;    
    __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct.LSEState);  ///打开外部低速晶振
    
    tickstart = HAL_GetTick();
    while (READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) == 0U)  /*读取LSE晶振准备状态*/
    {
      lse_check_flag = 1;
      if ((HAL_GetTick() - tickstart) > LSE_CHECK_TIME)  ///当准备时间大于LSE_CHECK_TIME时间   那么外部低速晶振检测失败 rtc使用内部低速晶振
      {
            lse_check_flag = 0;  
            break;
      }
    }
    if(lse_check_flag)  ///检测成功
    {
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)  ///设置外部晶振
        {
            Error_Handler();
        }
    }
    MX_RTC_Init();  /////初始化rtc
}

2.lse_check_flag主要用在下面函数中进行RTC的时钟配置,

void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{

  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(rtcHandle->Instance==RTC)
  {
  /* USER CODE BEGIN RTC_MspInit 0 */
    if(lse_check_flag == 0) ///外部低速时钟检测失败    那么将内部低速时钟作为RTC时钟源
    {
      PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
      PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;

      if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
      {
        Error_Handler();
      }

      /* RTC clock enable */
      __HAL_RCC_RTC_ENABLE();
      __HAL_RCC_RTCAPB_CLK_ENABLE();
    }
    else  ///检测成功  那么将外部低速时钟作为时钟源
    {

  /* USER CODE END RTC_MspInit 0 */

  /** Initializes the peripherals clocks
  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
    PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;

    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

    /* RTC clock enable */
    __HAL_RCC_RTC_ENABLE();
    __HAL_RCC_RTCAPB_CLK_ENABLE();
  /* USER CODE BEGIN RTC_MspInit 1 */
    }
  /* USER CODE END RTC_MspInit 1 */
  }
}

3.时间戳和日期之间的相互转换

时间戳计算调用了头文件"time.h"函数,刚开始调用了gmtime这个函数,但是返回指针一直是NULL,后来参考在Keil MDK中无法使用gmtime函数进行时间戳转换_keil 5 时间戳-优快云博客文章浏览阅读2.3k次,点赞4次,收藏11次。硬件平台STM32,软件平台Keil MDK 5.18由于项目中需要用到UNIX时间戳和日历的来回转换,于是想到C库函数里面有现成的函数可以使用。于直接使用mktime和gmtime两个函数进行时间戳转换,前者把日历转为时间戳,后者把时间戳转为日历。但是程序运行起来发现,gmtime得到的日历数据为乱码!!!经过调试才发现,这个函数返回值是NULL啊!!!查看反汇编代码,简直惊呆,这是什么鬼操作?汇编代码没有函数跳转,取而代之的是MOVS R0, #0_keil 5 时间戳https://blog.youkuaiyun.com/qq446252221/article/details/111625957,调用了localtime这个函数,gmtime和localtime的区别就是,gmtime返回的是GMT标准时间,而localtime返回的是本地时间。

何为本地时间?那就是带时区转换的时间,比如北京时间是东8区,与GMT时间相差8小时。

然而MDK库函数并没有直接设置时区的函数,因此locatime返回的仍然是GMT时间。

所以在使时localtime的时候,要先把时间戳加上28800秒(8小时)再进行转换,就能得到北京时间。

1)时间戳转换为日期:

/**
* @brief timestamp_set_clock 将时间戳转化为时间
* @param timestamp 需要转化的时间戳
* @param t 指向获取时间变量的指针
* @retval null
*/
static void timestamp_to_data(uint32_t timestamp,ts_rtc *t)
{
    struct tm *timeinfo = NULL;
    time_t t_stamp = 0;

    t_stamp = (time_t)(timestamp + 28800);   
    timeinfo = localtime(&t_stamp);    
    t->Year = timeinfo->tm_year + 1900 - 2000;   ////timeinfo得到的年份是从1900年开始   t.Year是从2000年开始
    t->Month = timeinfo->tm_mon + 1;   ///timeinfo的月份是从0开始  所以加一
    t->Date = timeinfo->tm_mday;
    t->Hours = timeinfo->tm_hour;
    t->Minutes = timeinfo->tm_min;
    t->Seconds = timeinfo->tm_sec;
}

timestamp + 28800,时间戳在原有的基础上加了28800也就是8小时,因为北京时间比标准时间快了8小时,

2)日期转换为时间戳:

/**
* @brief get_timestamp_value 将当前时间转化为时间戳
* @param timestamp 指向获取时间戳变量指针
* @retval null
*/
static void get_timestamp_value(uint32_t *timestamp)
{
    ts_rtc date = {0};  
    time_t times;
    struct tm tms;
    hal_get_DateTime(&date);  ////获取当前时间
    tms.tm_year = date.Year + 2000 - 1900; //C库函数的年份是从1900开始计算 date.Year是从2000年开始的,所以加上2000-1900
    tms.tm_mon  = date.Month - 1;   //C库函数的月份是用0表示1月
    tms.tm_mday = date.Date;
    tms.tm_hour = date.Hours;
    tms.tm_min  = date.Minutes;
    tms.tm_sec  = date.Seconds;
    times = mktime(&tms);
    *timestamp = times - 28800;    //北京时间:东8区偏移值
}


 

### STM32 HAL RTC 输出配置及使用方法 #### 配置RTC输出引脚 为了使能RTC的校准输出或唤醒功能,需通过CubeMX工具设置RTC输出至特定引脚。通常情况下,此引脚为PC13,在某些系列中也可以选择其他引脚作为RTC输出端口[^1]。 #### 初始化RTC模块 初始化过程中涉及到开启RTC外设时钟、配置低功耗模式以及设定初始时间日期等操作。这部分工作可以通过调用`HAL_RTC_Init()`完成,该函数会依据之前定义好的RTC_HandleTypeDef句柄参数来执行必要的硬件初始化动作[^4]。 ```c // 定义RTC处理实例 RTC_HandleTypeDef hrtc; void MX_RTC_Init(void){ /* ... */ if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } } ``` #### 设置RTC时间与日期 一旦完成了RTC的基础配置之后,就可以利用如下两个API接口分别用于写入当前的时间戳日历信息: - `HAL_RTC_SetTime()`: 更新指定RTC设备内的小时、分钟、秒钟数值。 - `HAL_RTC_SetDate()`: 修改年份、月份、星期几及具体某一天的数据记录。 这些修改均是以二进制格式(`RTC_FORMAT_BIN`)传递给目标寄存器存储起来。 ```c RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef DateToUpdate = {0}; sTime.Hours = 9; sTime.Minutes = 30; sTime.Seconds = 0; if(HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN)!= HAL_OK){ // 错误处理... } DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY; DateToUpdate.Month = RTC_MONTH_SEPTEMBER; DateToUpdate.Date = 7; DateToUpdate.Year = 23; if(HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN)!= HAL_OK){ // 错误处理... } ``` #### 获取RTC时间与日期 当应用程序需要读取实时更新后的时分秒或是完整的公历年月周日数据时,则可借助下面一对函数实现查询目的: - `HAL_RTC_GetTime()`: 返回由内部定时器计算得出的具体时刻详情; - `HAL_RTC_GetDate()`: 提供有关当天确切位置的信息描述。 同样地,这里也采用了同样的二进制编码方式表示返回的结果集。 ```c RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; if(HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN)!= HAL_OK){ // 错误处理... } if(HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN)!= HAL_OK){ // 错误处理... } ``` #### 使用RTC中断服务例程 对于希望基于预设条件触发事件的应用场景而言,比如每过一个小时就点亮LED灯一次这样的需求,那么就需要注册并编写对应的回调服务程序以便响应来自RTC产生的各类异常信号(如闹钟报警)。这一步骤涉及到了对`HAL_RTC_AlarmAEventCallback()`这类钩子函数重载的操作[^3]。 ```c void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc){ // 当前时间为整点时触发的动作逻辑 GPIO_PinState pin_state = GPIO_PIN_SET; HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, pin_state); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值