大家好,欢迎来到 DSP28335 的核心精讲系列。我们已经掌握了如何通过外部中断来响应“外部事件”,但系统内部同样需要一个精准的节拍器来处理“内部周期性任务”。单纯依靠 DELAY_US() 这样的软件延时,不仅精度差,而且会在延时期间霸占整个CPU,导致系统无法响应其他任何事情,这是专业开发中无法接受的。
今天,我们将学习嵌入式系统的“心脏”——CPU 定时器 (CPU Timer),并利用它来产生精确的定时器中断。掌握它,你就能创建一个非阻塞的、可以同时执行多个任务的、真正意义上的多任务雏形系统。
一、硬件原理:一个会自动重装的“数字沙漏”
F28335 内置了三个 32 位的 CPU 定时器 (Timer0, Timer1, Timer2)。要理解它们如何工作,我们首先要看懂其内部的硬件逻辑。
[图1: CPU 定时器硬件逻辑图]
这个看似复杂的图,其核心工作原理就像一个可以精确计时的“数字沙漏”:
时钟源 (Clock Source): 定时器的动力来自系统时钟 SYSCLKOUT。这就是“沙漏”中“沙子”下落的速度基准。
预分频器 (Prescaler):
PSCH:PSC (16位) 是一个预分-频计数器。
TDDHR:TDDR (16位) 是一个定时器分频器。
它们组合起来,可以对输入的 SYSCLKOUT 进行分频。例如,如果 SYSCLKOUT 是 150MHz,我们可以设置一个 N 分频,让最终进入主计数器的时钟频率变为 150MHz / N。这允许我们实现更长时间的定时。
计数器 (Counter): TIMH:TIM 是一个 32 位的递减计数器。这是“沙漏”的上半部分。它在每个分频后的时钟脉冲到来时,数值减一。
周期寄存器 (Period Register): PRDH:PRD 是一个 32 位的周期寄存器。这是“沙漏”的下半部分,用来设定总的“沙子”量。
工作流程:
启动: 当我们启动定时器时,PRD 的值被加载到 TIM 计数器中。
递减: TIM 寄存器开始以分频后的时钟速度向下计数。
中断: 当 TIM 减到 0 时,它会产生一个中断信号 (INT) 给 PIE 模块。
重载: 与此同时,TIM 会自动将 PRD 的值重新加载进来,然后开始新一轮的递减计数。
这个“递减->归零->中断->重载”的过程周而复始,就为我们提供了一个稳定、精确的周期性中断信号,成为了系统的“心跳”。
二、控制枢纽:关键寄存器解析
要指挥定时器工作,我们必须学会操作它的控制寄存器。
[图2 & 图3: Timer0/1/2 寄存器地址映射]
每个定时器都有一组独立的寄存器。其中,最重要的就是控制寄存器 (TCR - Timer Control Register)。
[图4 & 图5: TCR 寄存器位功能描述]
让我们来认识一下TCR中最重要的几个“开关”:
bit 15 (TIF): 中断标志位 (Timer Interrupt Flag)
当计数器减到 0 时,硬件会自动将该位置 1。
我们必须在中断服务函数中手动向该位写 1 来清除它,否则中断会不停地产生。
bit 14 (TIE): 中断使能位 (Timer Interrupt Enable)
只有将该位置 1,当计数器减到 0 时,才会向 PIE 发出中断请求。
bit 5 (TRB): 重载控制位 (Timer Reload Bit)
必须将该位置 1。当它为 1 时,每当定时器启动或计数器归零时,PRD 的值都会被重新加载到 TIM。这是实现周期性定时的关键。
bit 4 (TSS): 启动/停止位 (Timer Start/Stop)
写 1 停止 定时器。
写 0 启动 或 重新启动 定时器。
三、软件配置:五步点燃“心跳引擎”
TI 官方在 DSP2833x_CpuTimers.c 文件中为我们提供了一系列标准函数,极大地简化了定时器的配置。结合这些库函数,我们的配置流程非常清晰。
Step 1: 使能定时器外设时钟
任何外设工作的前提都是有时钟。
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // 开启 Timer 0 的时钟
EDIS;
Step 2: 初始化定时器参数 (使用库函数)
TI 提供了一个强大的函数 ConfigCpuTimer(),它能自动根据我们设定的 CPU 频率和想要的定时周期(微秒),计算出正确的 PRD 周期值并写入寄存器。
// 使用示例:
// 假设 Freq=150 (MHz), Period=500000 (us)
ConfigCpuTimer(&CpuTimer0, Freq, Period);```
Step 3: 关联中断向量与 ISR
//在 PIE 中断向量表中,将 TINT0 (定时器0中断) 指向我们自己的中断服务函数 `TIM0_IRQn`。
EALLOW;
PieVectTable.TINT0 = &TIM0_IRQn;
EDIS;```
Step 4: 开启中断通路并启动定时器
// PIE 级:TINT0 属于第1组第7个中断
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
// CPU 级
IER |= M_INT1;
// 全局
EINT;
// 启动定时器!
CpuTimer0Regs.TCR.bit.TSS = 0;
Step 5: 编写中断服务函数 (ISR)
这是中断发生时执行的代码。记得在函数末尾进行中断应答。
interrupt void TIM0_IRQn(void)
{// ... 用户功能代码 ...// PIE 中断应答PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
四、代码实战:双灯齐“闪”,各司其职
下面的代码将实现:
D2 指示灯:由 Timer0 中断精确控制,每 500ms 翻转一次。
D1 指示灯:在主函数 while(1) 循环中闪烁,证明 CPU 在没有中断时并未闲置。
time.h
#ifndef TIME_H_
#define TIME_H_#include "DSP2833x_Device.h" // DSP2833x 头文件
#include "DSP2833x_Examples.h" // DSP2833x 例子相关头文件// 声明初始化函数和中断服务函数
void TIM0_Init(float Freq, float Period);
interrupt void TIM0_IRQn(void);#endif /* TIME_H_ */
time.c
#include "time.h"
#include "leds.h"void TIM0_Init(float Freq, float Period)
{// Step 1: 使能时钟EALLOW;SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1;EDIS;// Step 3: 关联中断向量EALLOW;PieVectTable.TINT0 = &TIM0_IRQn;EDIS;// 手动进行一些基础配置CpuTimer0.RegsAddr = &CpuTimer0Regs;CpuTimer0Regs.PRD.all = 0xFFFFFFFF; // 先设为最大值CpuTimer0Regs.TCR.bit.TSS = 1; // 确保停止CpuTimer0Regs.TCR.bit.TRB = 1; // 使能重载CpuTimer0.InterruptCount = 0;// Step 2: 使用库函数计算并配置周期ConfigCpuTimer(&CpuTimer0, Freq, Period);// Step 4: 开启中断通路并启动定时器IER |= M_INT1;PieCtrlRegs.PIEIER1.bit.INTx7 = 1;CpuTimer0Regs.TCR.bit.TSS = 0; // 启动!EINT;ERTM;
}// Step 5: 编写 ISR
interrupt void TIM0_IRQn(void)
{EALLOW;LED2_TOGGLE; // 精确的周期性任务PieCtrlRegs.PIEACK.bit.ACK1 = 1; // 中断应答EDIS;
}
main.c
#include "leds.h"
#include "time.h"void main()
{int i=0;InitSysCtrl();InitPieCtrl();IER = 0x0000;IFR = 0x0000;InitPieVectTable();LED_Init();// 初始化定时器0,CPU频率150MHz,定时周期500000us (0.5s)TIM0_Init(150, 500000);while(1){i++;if(i%2000==0){LED1_TOGGLE; // 主循环任务}DELAY_US(100);}
}
现象: 程序运行后,你会看到 D2 指示灯以非常精准的 1Hz 频率在闪烁,而 D1 指示灯则以 `while` 循环的速度在闪烁。D2 的闪烁完全不受主循环中 `DELAY_US` 的影响,反之亦然。这完美地展示了前台任务(中断)和后台任务(主循环)并行工作的场景。
### 总结
CPU 定时器中断是嵌入式开发从“入门”走向“专业”的分水岭。通过本次学习,你已经掌握了:
1. 定时器的**硬件工作原理**:基于递减计数器和周期寄存器实现周期性中断。
2. **关键寄存器 TCR** 的配置方法,尤其是启动、停止和重载位。
3. 利用 TI 库函数进行**标准化配置的完整流程**。
4. 如何编写中断服务函数来执行**精确的周期性任务**。
定时器是操作系统的“时钟节拍”、PWM生成的“基准”、任务调度的“指挥官”。精通了它,你就拥有了构建复杂、实时、高效嵌入式系统的核心能力。