在 DSP28335 的开发中,CPU 定时器是实现定时中断、周期任务调度的核心外设之一。本文将从基础概念 、硬件结构 、代码解析 、周期计算 到实战应用,全面拆解 28335 的 CPU 定时器,帮你彻底搞懂它的使用方法!
一、定时器核心概念扫盲
1. 三个定时器的分工与使用场景
DSP28335 内置 3 个 32 位 CPU 定时器(Timer0/Timer1/Timer2),分工明确:
- Timer2 :预留给操作系统(如 TI-RTOS、FreeRTOS),作为系统滴答定时器(SysTick),为任务调度提供时间基准(如 1ms 中断),保障任务轮转和延时函数精准执行。
- Timer0/Timer1 :开放给用户自定义,典型场景:
- 周期性采样触发(ADC 定时采样);
- 通信协议定时(UART 超时检测、SPI 同步);
- 运动控制(电机 PWM 斩波、位置环周期);
- 故障检测(过流保护延时、看门狗备用)。
2. 32bit 定时器的含义
32bit 定时器指 ** 计数寄存器(TIM)和 周期寄存器(PRD)** 为 32 位宽度,计数范围0~2³²-1(0~4294967295)。相比 16 位定时器(仅 0~65535),无需多级分频即可实现更长定时周期(如 150MHz 系统时钟下,无分频最大定时约 28.6 秒,16 位仅 0.437ms)。
3. 计数部分与预分频部分的分工
- 计数部分 :由 32 位周期寄存器
PRDH:PRD和计数寄存器TIMH:TIM组成,采用递减计数:TIM 从 PRD 值递减至 0 时触发中断,自动重载 PRD 重新计数。 - 预分频部分 :由预订标寄存器
TPRH:TPR和预订标计数器PSC组成,对定时器时钟(TIMCLK)分频:PSC 从 TPR 值递减至 0 时,TIM 才减 1,进一步延长定时周期。 
4. XH:X 如何表示 32bit?
XH是高 16 位寄存器 ,X是低 16 位寄存器,拼接为完整 32 位数据:
TPRH:TPR:32 位预分频值;TIMH:TIM:32 位计数值;PRDH:PRD:32 位周期值。示例:TPRH=0x0001、TPR=0x0000,则 32 位预分频值为0x00010000(65536)。
二、定时器硬件结构与寄存器定义
1. 寄存器集合结构体CPUTIMER_REGS
该结构体直接映射硬件寄存器,定义定时器的核心配置:
cpp
// CPU定时器寄存器集合(硬件映射)
struct CPUTIMER_REGS {
union TIM_GROUP TIM; // 32位计数寄存器(TIMH:TIM):存储当前计数值,递减计数
union PRD_GROUP PRD; // 32位周期寄存器(PRDH:PRD):计数重载值
union TCR_REG TCR; // 控制寄存器:配置启停、中断使能、重载等
Uint16 rsvd1; // 保留位:硬件对齐/预留
union TPR_REG TPR; // 预分频低位寄存器(低16位)
union TPRH_REG TPRH; // 预分频高位寄存器(高16位,TPRH:TPR组成32位预分频值)
};
2. 辅助变量结构体CPUTIMER_VARS
封装定时器配置与状态,便于上层调用
cpp
// 定时器辅助变量(配置/状态封装)
struct CPUTIMER_VARS {
volatile struct CPUTIMER_REGS *RegsAddr; // 指向定时器寄存器基地址
Uint32 InterruptCount; // 中断计数:统计触发次数
float CPUFreqInMHz; // 系统时钟频率(MHz):用于周期计算
float PeriodInUSec; // 目标定时周期(微秒)
};
三、定时器初始化代码逐行解析
1. 通用初始化函数InitCpuTimers
该函数将定时器初始化为 "最长周期 + 停止状态",避免上电误触发:
cpp
void InitCpuTimers(void)
{
// ------------------- Timer0初始化(用户自定义) -------------------
CpuTimer0.RegsAddr = &CpuTimer0Regs; // 绑定Timer0寄存器地址
CpuTimer0Regs.PRD.all = 0xFFFFFFFF; // 周期设为最大值(最长定时)
CpuTimer0Regs.TPR.all = 0; // 预分频低16位=0
CpuTimer0Regs.TPRH.all = 0; // 预分频高16位=0(无预分频)
CpuTimer0Regs.TCR.bit.TSS = 1; // 停止定时器(TSS=1)
CpuTimer0Regs.TCR.bit.TRB = 1; // 重载计数寄存器(PRD→TIM)
CpuTimer0.InterruptCount = 0; // 重置中断计数
// ------------------- Timer1/2初始化(预留RTOS) -------------------
// 注:Timer1/2预留给DSP-BIOS/RTOS,勿随意修改
CpuTimer1.RegsAddr = &CpuTimer1Regs;
CpuTimer2.RegsAddr = &CpuTimer2Regs;
CpuTimer1Regs.PRD.all = 0xFFFFFFFF;
CpuTimer2Regs.PRD.all = 0xFFFFFFFF;
CpuTimer1Regs.TPR.all = 0;
CpuTimer1Regs.TPRH.all = 0;
CpuTimer2Regs.TPR.all = 0;
CpuTimer2Regs.TPRH.all = 0;
CpuTimer1Regs.TCR.bit.TSS = 1;
CpuTimer2Regs.TCR.bit.TSS = 1;
CpuTimer1Regs.TCR.bit.TRB = 1;
CpuTimer2Regs.TCR.bit.TRB = 1;
CpuTimer1.InterruptCount = 0;
CpuTimer2.InterruptCount = 0;
}
2. Timer0 专属初始化函数TIM0_Init
该函数完成 Timer0 的时钟使能、中断配置、参数初始化:
cpp
// Timer0初始化:Freq=系统时钟(MHz),Period=定时周期(us)
void TIM0_Init(float Freq, float Period)
{
EALLOW; // 允许访问受保护寄存器
SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // 使能Timer0外设时钟
EDIS; // 禁止访问受保护寄存器
// 配置中断向量:Timer0中断服务函数→TINT0向量
EALLOW;
PieVectTable.TINT0 = &TIM0_IRQn;
EDIS;
// 基础配置(同InitCpuTimers)
CpuTimer0.RegsAddr = &CpuTimer0Regs;
CpuTimer0Regs.PRD.all = 0xFFFFFFFF;
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
CpuTimer0Regs.TCR.bit.TSS = 1;
CpuTimer0Regs.TCR.bit.TRB = 1;
CpuTimer0.InterruptCount = 0;
ConfigCpuTimer(&CpuTimer0, Freq, Period); // 计算并设置实际周期值
CpuTimer0Regs.TCR.bit.TSS = 0; // 启动定时器(TSS=0)
// 中断使能配置
IER |= M_INT1; // 使能CPU第1组中断
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; // 使能PIE第1组第7个中断(Timer0)
EINT; // 使能全局中断
ERTM; // 使能实时调试中断
}
四、定时周期计算原理与公式

1. 核心公式定义
| 符号 | 含义 | 单位 |
|---|---|---|
| X | 系统时钟频率 | MHz |
| TDDRH:TDDR | 32 位预分频配置值 | 无(数值) |
| PRDH:PRD | 32 位周期配置值 | 无(数值) |
公式 1(预分频后计数时钟周期):计算 "TIM 减 1" 对应的时间(最小定时单位):

公式 2(总定时周期):计算定时器从计数到中断的总时间:

2. 关键逻辑说明
- 预分频系数 / 计数次数需
+1:定时器从配置值递减至 0 触发动作,实际次数比配置值多 1; ×10⁻⁶:将 MHz 对应的 "微秒级周期" 转换为秒。
五、实战应用:多定时器配置与主循环
电路图如下

1. main 函数中的定时器使用
cpp
void main()
{
int i = 0;
InitSysCtrl(); // 初始化系统控制(时钟/PLL等)
InitPieCtrl(); // 初始化PIE中断控制器
IER = 0x0000; // 禁用所有CPU中断
IFR = 0x0000; // 清除中断标志
InitPieVectTable();// 初始化PIE向量表
LED_Init(); // 初始化LED硬件
// 配置三个定时器:不同周期
TIM0_Init(150, 500000); // Timer0:500ms中断
TIM1_Init(150, 1000000); // Timer1:1s中断
TIM2_Init(150, 1500000); // Timer2:1.5s中断
// 主循环
while(1)
{
i++;
if(i % 2000 == 0)
{
LED14_TOGGLE; // 每2000次循环切换LED14(约200ms)
}
DELAY_US(100); // 软件延时100us
}
}
2. 逻辑说明
- 三个定时器分别以 500ms、1s、1.5s 周期触发中断,可在各自中断服务函数中实现不同任务(如 LED 翻转、数据采样);
- 主循环通过
DELAY_US(100)和计数器实现 LED 的 200ms 周期翻转,与定时器中断形成 "软件延时 + 硬件定时" 的双层任务调度。
六、总结与拓展
DSP28335 的 CPU 定时器凭借 32 位宽和灵活的预分频设计,能满足从微秒级到秒级的定时需求。核心要点:
- 明确定时器分工:Timer0/1 用户自定义,Timer2 预留 RTOS;
- 掌握 32 位寄存器拼接逻辑(XH:X);
- 熟练运用定时周期公式,根据系统时钟和目标周期反推寄存器配置;
- 中断配置需注意 PIE 向量表映射和中断使能层级(CPU 级→PIE 级)。