3. 定时器中断实现精确延时

定时器中断实现精确延时 学习卡片

任务定义

在TI C2000系列DSP(以TMS320F28335为例)上,利用CPU定时器0(CPU-Timer 0)产生周期中断,在中断服务函数中翻转GPIO34电平,实现精确的1ms定时中断与500ms周期方波输出。通过示波器或逻辑分析仪测量GPIO34波形周期,验证定时精度。

硬件连接

TMS320F28335 CPU-Timer 0 INT1.7 (TINT0) GPIO34 示波器 CH1: GPIO34 GND: 公共地 CPU Timer 0 周期中断 → 翻转GPIO34 中断周期1ms,翻转周期2ms → 方波周期4ms(250Hz)

实现原理

CPU定时器0是C2000内核自带的32位递减计数器。定时器时钟源为系统时钟SYSCLKOUT(本案例配置为150MHz),经过预定标器分频后驱动计数器递减。当计数器递减到0时,产生TINT0中断请求,并自动重装载PRD寄存器中的周期值。在中断服务函数中翻转GPIO34电平,即可获得精确的定时方波输出。

代码实现

// main.c - TMS320F28335 CPU-Timer0 精确延时中断示例
#include "DSP2833x_Device.h"
#include "DSP2833x_Examples.h"

// 中断周期定义:1ms @ 150MHz SYSCLKOUT
#define TIMER0_PERIOD  150000L   // 150MHz × 1ms = 150,000个时钟周期

// GPIO34翻转标志
volatile Uint32 g_toggleCount = 0;

// 中断服务函数原型
interrupt void cpu_timer0_isr(void);

void InitGpio34(void)
{
    EALLOW;
    GpioCtrlRegs.GPAMUX2.bit.GPIO34 = 0;   // 配置为GPIO功能
    GpioCtrlRegs.GPADIR.bit.GPIO34 = 1;    // 配置为输出
    GpioDataRegs.GPASET.bit.GPIO34 = 1;    // 初始输出高电平
    EDIS;
}

void InitCpuTimer0(void)
{
    // 定时器时钟 = SYSCLKOUT / (预定标器+1)
    // 此处预定标器设为0,即不分频,定时器时钟 = 150MHz
    CpuTimer0.RegsAddr = &CpuTimer0Regs;
    
    // 设置周期寄存器
    CpuTimer0Regs.PRD.all  = TIMER0_PERIOD - 1;  // 周期值(递减到0产生中断)
    CpuTimer0Regs.TPR.all  = 0;                   // 预定标器 = 0
    CpuTimer0Regs.TPRH.all = 0;
    
    // 初始化计数器值
    CpuTimer0Regs.TIM.all  = TIMER0_PERIOD - 1;
    
    // 中断控制
    CpuTimer0Regs.TCR.bit.TSS = 1;      // 停止定时器
    CpuTimer0Regs.TCR.bit.TRB = 1;      // 重装载
    CpuTimer0Regs.TCR.bit.FREE = 0;     // 仿真暂停时定时器也暂停
    CpuTimer0Regs.TCR.bit.SOFT = 0;
    
    // 使能定时器中断
    CpuTimer0Regs.TCR.bit.TIE = 1;      // 使能定时器中断
    
    // 中断向量表映射
    EALLOW;
    PieVectTable.TINT0 = &cpu_timer0_isr;
    EDIS;
}

interrupt void cpu_timer0_isr(void)
{
    // 翻转GPIO34
    GpioDataRegs.GPADAT.bit.GPIO34 ^= 1;
    g_toggleCount++;
    
    // 清除中断标志
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

void main(void)
{
    // 系统初始化(时钟150MHz,PLL配置等)
    InitSysCtrl();
    
    // 禁止全局中断
    DINT;
    
    // 初始化PIE控制寄存器
    InitPieCtrl();
    
    // 清除PIE中断标志并禁用
    IER = 0x0000;
    IFR = 0x0000;
    
    // 初始化PIE向量表
    InitPieVectTable();
    
    // 初始化GPIO34
    InitGpio34();
    
    // 初始化CPU定时器0
    InitCpuTimer0();
    
    // 使能CPU中断INT1(定时器0中断挂在INT1.7)
    IER |= M_INT1;
    
    // 使能PIE中断组1的第7通道
    PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
    
    // 启动定时器0
    CpuTimer0Regs.TCR.bit.TSS = 0;
    
    // 使能全局中断
    EINT;
    ERTM;
    
    // 主循环:空转,所有工作由中断完成
    for(;;)
    {
        // 可在此添加低优先级任务
    }
}

关键配置说明

参数值说明
SYSCLKOUT150 MHz系统时钟(由InitSysCtrl配置)
定时器预定标器0不分频,定时器时钟=150MHz
PRD周期值149,999150,000个时钟周期 = 1ms
中断周期1 ms每1ms进入一次ISR
GPIO34翻转频率500 Hz每1ms翻转一次,方波周期2ms

工程文件与编译

本案例基于TI官方例程框架,需要以下文件:

  • DSP2833x_GlobalVariableDefs.c — 定义CpuTimer0Regs等全局寄存器结构体
  • DSP2833x_PieCtrl.c — PIE控制器初始化
  • DSP2833x_PieVect.c — PIE向量表初始化
  • DSP2833x_SysCtrl.c — 系统时钟与外设时钟使能
  • DSP2833x_CpuTimers.c — 定时器配置辅助函数(可选)

在CCS工程中添加上述源文件,包含头文件路径后编译。系统时钟配置为150MHz(PLLCR=10, DIVSEL=0)。

验证方法

测试步骤:

  1. 将GPIO34引脚连接示波器探头,示波器地线接开发板GND;
  2. 编译下载程序,运行后观察GPIO34输出波形;
  3. 测量方波周期,预期为2.000ms(频率500Hz);
  4. 连续测量10个周期,记录最大偏差。

判定标准:

  • 波形为占空比50%的方波,无毛刺抖动;
  • 实测周期在1.998ms~2.002ms范围内(误差±0.1%);
  • 长时间运行(>1小时)周期稳定,无累积漂移。

预期输出:GPIO34输出周期2.000ms、频率500.0Hz的方波(由1ms中断周期翻转得到,该结果由定时器配置直接决定)。

注意事项

  • 定时器中断服务函数应保持精简,避免在ISR中执行耗时操作导致定时溢出;
  • 若系统时钟不是150MHz,需按实际频率重新计算TIMER0_PERIOD值;
  • PIEACK_GROUP1必须在ISR末尾清除,否则后续中断无法响应;
  • GPIO34在F28335上属于GPIOA组,操作寄存器为GPADAT/GPASET/GPACLEAR。