You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

STM32F303如何生成时间戳?嵌入式编程新手求助

嘿,作为嵌入式新手,想实现时间戳功能来标记功能执行节点完全没问题!我来给你分享几种实用的实现方案,适配不同的嵌入式场景:

一、无RTOS的裸机环境:用硬件定时器实现基础时间戳

这是裸机项目里最常用的方案,利用MCU自带的定时器计数生成相对时间戳,足够满足大多数功能执行节点标记、耗时统计的需求:

实现步骤:

  • 初始化一个定时器,设置合适的预分频和自动重装值,让定时器以固定频率触发中断(比如每1ms触发一次)
  • 在定时器中断回调里维护一个全局计数变量,每次中断触发就自增
  • 当需要标记某个功能的执行时间点时,直接读取这个全局变量即可

代码示例(以STM32为例):

#include "stm32f1xx_hal.h"

// 全局时间戳变量,记录系统启动后的毫秒数
uint32_t timestamp_ms = 0;

// 定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == TIM2)
  {
    timestamp_ms++; // 每1ms自增一次
  }
}

// TIM2初始化配置(72MHz系统时钟下,生成1ms中断)
void TIM2_Timestamp_Init(void)
{
  TIM_HandleTypeDef htim2;
  __HAL_RCC_TIM2_CLK_ENABLE();

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 71;       // 72MHz分频后为1MHz
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 999;         // 计数到999触发中断,刚好1ms
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  
  HAL_TIM_Base_Init(&htim2);
  HAL_TIM_Base_Start_IT(&htim2);   // 启动定时器中断
}

// 使用示例:统计某功能的执行耗时
void sample_function(void)
{
  uint32_t start_time = timestamp_ms;
  // --- 这里写你要执行的功能代码 ---
  for(int i=0; i<10000; i++);
  // -------------------------------
  uint32_t end_time = timestamp_ms;
  uint32_t execute_duration = end_time - start_time;
  
  // 打印耗时(如果有串口的话)
  printf("Function took %lu ms to execute\n", execute_duration);
}

注意点:如果用的是16位定时器,要额外加一个溢出计数变量来处理溢出问题;32位定时器的话,timestamp_ms大概能连续跑49天才会溢出,大部分场景下不用额外处理。

二、使用外部RTC模块生成绝对时间戳

如果需要真实的年月日时分秒作为时间戳(比如记录事件发生的实际时间),可以搭配外部RTC模块(比如DS3231,精度高还带备用电池):

实现步骤:

  • 通过I2C接口连接RTC模块和MCU
  • 初始化RTC并设置当前时间(可以通过串口指令或者上位机配置)
  • 需要时间戳时,读取RTC的时间数据,转换成Unix时间戳(从1970年1月1日到当前的秒数)或者自定义的时间字符串

代码示例(简化版):

#include "ds3231.h"

// 日期转Unix时间戳的工具函数(网上有成熟实现,直接用就行)
uint32_t date_to_unix(uint16_t year, uint8_t month, uint8_t day, 
                      uint8_t hour, uint8_t minute, uint8_t second);

// 获取当前Unix时间戳
uint32_t get_absolute_timestamp(void)
{
  DS3231_Time current_time;
  ds3231_read_time(&current_time); // 读取RTC的年、月、日、时、分、秒
  
  return date_to_unix(current_time.year, current_time.month, current_time.day,
                      current_time.hour, current_time.minute, current_time.second);
}

// 使用示例:记录功能执行的绝对时间
void log_execution_event(void)
{
  uint32_t event_timestamp = get_absolute_timestamp();
  printf("Function executed at Unix timestamp: %lu\n", event_timestamp);
}

注意点:RTC模块自带备用电池,断电后也能保持时间,适合需要长期记录事件真实时间的场景。

三、带RTOS的嵌入式系统:利用系统时钟API

如果你的项目用了RTOS(比如FreeRTOS、RT-Thread),系统本身就提供了时间相关的API,直接调用更稳定:

FreeRTOS示例:

#include "FreeRTOS.h"
#include "task.h"

void sample_rtos_task(void *pvParameters)
{
  while(1)
  {
    // 获取系统启动后的tick数(tick时长由configTICK_RATE_HZ定义)
    TickType_t start_tick = xTaskGetTickCount();
    
    // --- 执行你的功能代码 ---
    vTaskDelay(pdMS_TO_TICKS(500));
    // -----------------------
    
    TickType_t duration_tick = xTaskGetTickCount() - start_tick;
    // 转换为毫秒时长
    uint32_t duration_ms = duration_tick * portTICK_PERIOD_MS;
    
    printf("Task execution took %lu ms\n", duration_ms);
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

注意点:RTOS的tick计数是相对时间,如果需要绝对时间,还是得结合RTC模块来实现。

总的来说,优先根据你的需求选方案:只是统计功能耗时、标记执行节点,用硬件定时器就够;需要真实时间关联,就上RTC;用RTOS的话直接用系统API更省心。

内容的提问来源于stack exchange,提问作者ballack

火山引擎 最新活动