在嵌入式系统设计中,定时器模块是最基础也最核心的外设之一。ARM APB总线上的定时器模块采用双通道设计,每个通道包含完整的16位计数器及其控制逻辑。模块内部采用层次化设计,主要分为以下几个功能单元:
这种架构设计使得定时器模块既能在常规操作时保持高效,又能在测试阶段进行充分验证。APB总线时钟(PCLK)经过预分频处理后,驱动计数器工作,当计数值归零时触发中断信号,形成完整的定时功能链路。
这个16位可读写寄存器承担双重职责:
c复制// 寄存器映射示例
#define TIMER1_LOAD (*(volatile uint16_t *)0x40000000)
注意:实际写入时应先检查TimerXControl的Enable位,避免在运行中修改导致不可预测的行为
32位宽的控制寄存器实际只使用低8位,关键位域如下:
| 位域 | 名称 | 功能描述 | 典型值 |
|---|---|---|---|
| 0 | Enable | 1=启用定时器 0=禁用 | 0x1 |
| 1 | Mode | 0=自由运行 1=周期模式 | 0x1 |
| 3:2 | Prescale | 00=不分频 01=/16 10=/256 11=保留 | 0x01 |
| 7:4 | 保留 | 必须写0 | 0x0 |
预分频器通过如下公式计算实际定时周期:
code复制定时周期 = (TimerXLoad + 1) × (PCLK周期) × 分频系数
例如当PCLK=50MHz,Load=999,Prescale=01时:
code复制周期 = (999+1)×(1/50MHz)×16 = 320μs
这个只读寄存器反映了计数器的实时状态,读取时需注意:
测试寄存器是许多开发者容易忽视的重要部分,其2位宽设计支持两种测试模式:
计数器测试模式(bit0):
测试时钟选择(bit1):
定时器中断处理流程包含三个关键环节:
典型的中断服务程序(ISR)应遵循以下结构:
c复制void TIMER1_IRQHandler(void)
{
// 1. 清除中断源
TIMER1_CLEAR = 0x1; // 写入任意值
// 2. 执行定时任务
task_scheduler();
// 3. 必要时重载计数器(周期模式自动完成)
#ifdef FREE_RUNNING_MODE
TIMER1_LOAD = RELOAD_VALUE;
#endif
}
以下代码展示如何配置定时器1为周期模式,产生10ms中断:
c复制void timer1_init(void)
{
// 1. 禁用定时器
TIMER1_CTRL = 0x00;
// 2. 设置重载值 (PCLK=50MHz, 分频16)
uint32_t reload = (10000 * 50) / 16 - 1; // 10ms定时
TIMER1_LOAD = reload;
// 3. 配置控制寄存器
TIMER1_CTRL = (1 << 0) | // Enable=1
(1 << 1) | // Mode=1(周期模式)
(1 << 2); // Prescale=01(16分频)
// 4. 使能NVIC中断
NVIC_EnableIRQ(TIMER1_IRQn);
}
验证计数器逻辑时的测试配置:
c复制void enter_test_mode(void)
{
// 1. 禁用定时器
TIMER1_CTRL = 0x00;
// 2. 启用测试模式
TIMER1_TEST |= 0x1; // 设置Counter test mode
// 3. 观察4位计数器行为
while(1) {
uint16_t val = TIMER1_VALUE;
printf("Counter: 0x%04X\n", val);
delay(100);
}
}
定时不准:
中断不触发:
寄存器写入无效:
c复制void pwm_init(uint8_t duty_cycle)
{
TIMER1_LOAD = 1000; // 周期=1000个时钟
TIMER1_CTRL = 0x05; // 自由运行模式+中断使能
PWM_COMPARE = 1000 * duty_cycle / 100; // 占空比设置
}
低功耗优化:
时间戳采集:
c复制uint32_t get_timestamp(void)
{
static uint32_t overflow_count = 0;
uint16_t timer_val = TIMER1_VALUE;
if(timer_val > 0x8000 && !flag) {
overflow_count++;
flag = 1;
} else if(timer_val < 0x8000) {
flag = 0;
}
return (overflow_count << 16) | timer_val;
}
定时器模块的灵活运用需要结合具体应用场景,在实时操作系统(RTOS)中,它通常作为任务调度的时基;在电机控制中,用于PWM波形生成;在通信协议中,则可能承担超时检测的功能。理解寄存器级的操作原理,是进行高效嵌入式开发的基础。