You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LPC17XX定时器配置异常排查:计数速率低于预期

LPC17XX定时器初始化与计数不准问题排查

我在实现LPC17XX定时器的初始化与运行功能,为验证定时器效果,设置了一个每1微秒递增的计数器,但实际运行后发现计数速率远低于预期——例如系统运行529000微秒时,计数器值仅为123832。请帮忙检查定时器配置。

相关寄存器说明:

  • MR0I、MR0R、MR0S:定时器匹配控制寄存器位
  • CE、CR:定时器控制寄存器位

原始代码

#define PRESCALER_3   2
#define MR0I     0x00000001
#define MR0R     0x00000002
#define MR0S     0x00000004
#define CE  0x00000001
#define CR  0x00000002
    void TI_InitTimer(uint8_t u8_NumTimer, uint32_t u32_TempsUs, uint8_t u8_AutoRestart)
    {
        uint32_t u32_Horloge;
        uint32_t u32_Frequence;

       u32_Horloge = SY_PeriphClock();           // 读取外设时钟频率
       u32_Frequence = 1000000 / u32_TempsUs;

       switch(u8_NumTimer)
       {
          case TIMER3:
          {
             PCONP |= PCTIM3;                     // 启用定时器3模块时钟
             T3PR = PRESCALER_3 - 1;              // 预分频值=1,时钟分频为2
             T3CTCR = 0;                          // 定时器模式(内部频率计数)
             T3MR0 = (u32_Horloge / PRESCALER_3) / u32_Frequence;
             T3MCR = 0;                           // 未使用比较器功能
             T3EMR = 0;                           // 未使用输出翻转功能
             T3MCR |= MR0R;                      
             T3MCR &= ~MR0S;                       
             T3MCR |= MR0I;                       
             T3TCR &= ~CE;
             T3TCR |= CR;                         
             T3TCR &= ~CR;
             T3TCR |= CE;                         
             IT_InitIrq(INT_TIMER3,PRIO_INT_TIMER3); 
             g_u8_CompteurTimer3 = 0;
             g_u8_AutoRestartTimer3 = u8_AutoRestart;
             break;
          }
          default: break;
       }
    }



    void TIMER3_IRQHandler(void)
    {
    uint8_t u8_Source;

       u8_Source = (uint8_t)T3IR;
       if((u8_Source & 0x01) != 0)                   // 是否为比较器0触发?
       {
           if(g_u8_AutoRestartTimer3 == OFF)
           {
              TI_ActiveTimer(TIMER3, OFF);
           }
           g_u8_CompteurTimer3++;
       }
       T3IR = u8_Source;
    }

问题分析与修复方案

1. 计数器类型溢出

g_u8_CompteurTimer3是uint8_t类型,最大值仅为255,计数超过后会自动归零,直接导致计数结果严重失真。

  • 修复:将计数器改为uint32_t类型,避免溢出。

2. 匹配值计算逻辑误差

原代码中u32_Frequence = 1000000 / u32_TempsUs,当u32_TempsUs=1时u32_Frequence=1000000,后续计算T3MR0 = (u32_Horloge / PRESCALER_3) / u32_Frequence,若外设时钟不是1000000的整数倍,整数除法会产生截断误差,导致匹配值偏小或偏大,影响定时精度。

  • 修复:直接计算微秒对应的定时器计数值:u32_TimerTicks = (u32_Horloge / 1000000) * u32_TempsUs,再除以预分频值得到T3MR0,逻辑更直观且误差更小。

3. 定时器启动流程冗余

原代码中先关闭定时器,再复位、取消复位,最后启动,步骤冗余且可能引入时序问题。

  • 修复:简化启动流程:先置位CR位复位定时器,再直接设置为CE位启动定时器,操作更简洁可靠。

4. 中断标志位清除错误

原代码中T3IR = u8_Source会将所有读取到的中断位都清除,若存在其他未处理的中断,会被误清除,导致后续中断异常。

  • 修复:仅清除MR0对应的中断标志位,即T3IR = 0x01。

5. 外设时钟配置确认

需要确保SY_PeriphClock()返回的是定时器3的实际工作时钟。LPC17XX中定时器外设时钟由PCLKSEL0/PCLKSEL1寄存器控制,若该寄存器设置了分频(比如4分频),会导致定时器实际工作时钟远低于预期,进而减慢计数速率。

  • 修复:检查并设置PCLKSEL0中TIMER3对应的位(通常是第24、25位),确保外设时钟分频符合预期(比如设置为00,即PCLK=CCLK/1)。

修改后的代码示例

#define PRESCALER_3   2
#define MR0I     0x00000001
#define MR0R     0x00000002
#define MR0S     0x00000004
#define CE  0x00000001
#define CR  0x00000002

// 更换为32位计数器,避免溢出
uint32_t g_u32_CompteurTimer3 = 0;
uint8_t g_u8_AutoRestartTimer3 = 0;

void TI_InitTimer(uint8_t u8_NumTimer, uint32_t u32_TempsUs, uint8_t u8_AutoRestart)
{
    uint32_t u32_Horloge;
    uint32_t u32_TimerTicks;

    u32_Horloge = SY_PeriphClock();           // 读取外设时钟频率
    // 直接计算目标微秒对应的定时器计数值
    u32_TimerTicks = (u32_Horloge / 1000000) * u32_TempsUs;

    switch(u8_NumTimer)
    {
        case TIMER3:
        {
            PCONP |= PCTIM3;                     // 启用定时器3模块时钟
            // 确认TIMER3的外设时钟分频,示例设置为PCLK=CCLK/1
            PCLKSEL0 &= ~(0x03 << 24);
            PCLKSEL0 |= (0x00 << 24);

            T3PR = PRESCALER_3 - 1;              // 预分频值=1,时钟分频为2
            T3CTCR = 0;                          // 定时器模式(内部频率计数)
            T3MR0 = u32_TimerTicks / PRESCALER_3; // 计算预分频后的匹配值
            T3MCR = MR0R | MR0I;                 // 合并设置匹配复位+中断
            T3EMR = 0;                           // 未使用输出翻转功能
            
            // 简化启动:先复位定时器,再启动
            T3TCR = CR;                          // 复位计数器
            T3TCR = CE;                          // 启动定时器
            
            IT_InitIrq(INT_TIMER3, PRIO_INT_TIMER3); 
            g_u32_CompteurTimer3 = 0;
            g_u8_AutoRestartTimer3 = u8_AutoRestart;
            break;
        }
        default: break;
    }
}

void TIMER3_IRQHandler(void)
{
    if(T3IR & 0x01)                   // 检查MR0中断标志
    {
        if(g_u8_AutoRestartTimer3 == OFF)
        {
            TI_ActiveTimer(TIMER3, OFF);
        }
        g_u32_CompteurTimer3++;
        T3IR = 0x01;                  // 仅清除MR0中断标志
    }
}

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 01:22:16