问题现象

在嵌入式开发中使用FreeRTOS时,我设置了一个12小时(43,200,000毫秒)的定时器,如下

// app_timer_start是我封装后的定时器创建,不影响
app_timer_start(&app_esp8285_send_timer, 43200000, portMAX_DELAY, pdTRUE);

但实际运行时,定时器却在5分钟左右就提前触发,误差超过140倍!

关键代码

// FreeRTOS标准宏定义
#define pdMS_TO_TICKS(xTimeInMs) ((TickType_t)(((TickType_t)(xTimeInMs) * 
                               (TickType_t)configTICK_RATE_HZ) / 
                               (TickType_t)1000U))

// 实际配置
typedef uint32_t TickType_t;  // 32位计数器
#define configTICK_RATE_HZ 1000  // 系统时钟1kHz

崩溃的数学计算

问题出在毫秒到Ticks的转换过程:

  • ​计算原理​​:
    Ticks = (ms × configTICK_RATE_HZ) / 1000
  • ​预期计算​​:
    43,200,000 × 1,000 = 43,200,000,000
  • ​实际发生​​:
43,200,000,000 ÷ 4,294,967,296 = 10.05次整循环
余数 = 43,200,000,000 - (10 × 4,294,967,296) 
     = 43,200,000,000 - 42,949,672,960 
     = 250,327,040
  • 最终错误结果:Ticks = 250,327,040 ÷ 1000 = 250,327 Ticks

为什么是5分钟左右

250,327 Ticks × (1000ms/s ÷ 1000 ticks/s) = 250,327毫秒 ≈ 250秒 ≈ 4.17分钟

解决办法

// 在FreeRTOSConfig.h中,会覆盖默认的pdMS_TO_TICKS
#define pdMS_TO_TICKS(x) ((TickType_t)((uint64_t)(x) * \
                         configTICK_RATE_HZ / 1000U))