TMS320F28377D学习日志:day3定时器中断的应用


前言

TMS320F28377D有3个32位的定时器,分别为定时器0(timer0)、定时器1(timer1)和定时器2(timer2).这次利用28377的三个定时器,分别实现中断,在各自的中断程序中翻转GPIO的输出电平,实现板上LED1、2、3以不同周期闪烁。


一、TMS320F28377D的定时器介绍

1.1 28377定时器工作原理

TMS320F28377D有3个32位的定时器,分别为定时器0(timer0)、定时器1(timer1)和定时器2(timer2)。由2837xD的数据手册可以看到,定时器的工作原理为下图:
在这里插入图片描述
定时器的工作原理为

  1. 32位的计数器寄存器TIMH:TIM装载了周期寄存器PRDH:PRD的值
  2. 当TDDRH:TDDR作为定时分频器,计数器TIMH:TIM每SYSCLKOUT周期减1,SYSCLKOUT周期为TPR[TDDRH:TDDR]+1
  3. 当计数器TIMH:TIM为0时,输出中断信号。

也就是说,每来个时钟信号,PSCH:PSC都会减1,当PSCH:PSC减到0时,就会使减TIMH:TIM减1,并重载TDDRH:TDDR 的值。当TIMH:TIM减到0时,输出中断信号,并重新装载。

1.2 定时器中断原理

三个定时器的中断信号分别为下图
在这里插入图片描述
其中可以看到定时器0是经过PIE,将中断信号传入CPU中;而定时器1和定时器2是直接将中断信号传入CPU中。查看PIE通道图,可以看到定时器0为第1组第7个通道中断:
在这里插入图片描述

所以在启用定时器0中断时需要对PIE第1组第7个小中断进行使能;定时器1和定时器2则不需要。使能程序如下

PieCtrlRegs.PIEIER1.bit.INTx7 = 1;  //使能PIE第1组中断的第7个通道中断,即定时器0中断

另外,DSP的中断管理分为3个层次:外设级,PIE级,CPU级。其中,外设级中断管理负责具体外设中断源的允许与禁止,PIE级中断管理负责对外设级中断分组并按照优先级管理,CPU内核级中断管理则负责处理直接向CPU申请的中断请求。

二、程序介绍

2.1 GPIO引脚宏定义

这次程序是在上次day2程序的基础上进行修改得到,沿用了上次程序的GPIO口设置。由于要在中断中翻转GPIO引脚输出电平,为了方便编写,采用宏定义简化。宏定义如下

#define LED1_TOGGLE GpioDataRegs.GPCTOGGLE.bit.GPIO89 = 1    //GPIO89切换电平
#define LED2_TOGGLE GpioDataRegs.GPCTOGGLE.bit.GPIO91 = 1
#define LED3_TOGGLE GpioDataRegs.GPCTOGGLE.bit.GPIO93 = 1

寄存器GPCTOGGLE用于翻转引脚的输出电平,从而起到改变LED亮灭的作用。

2.2 中断函数地址存放

这里将中断函数地址赋值给PieVectTable中,PieVectTable就是中断向量表,它是一个存放ISR(中断服务程序,interrupt service routine)地址的结构体。因为它是受保护的,所以需要加上EALLOWEDIS语句。EALLOW,EDIS 一般是成对使用的,有些寄存器是受到保护的,不能任意写,EALLOW 相当于去掉保护,对写保护的寄存器进行操作后,EDIS 是重新把这个寄存器保护起来的意思。

 EALLOW;  //写保护
 PieVectTable.TIMER0_INT = &cpu_timer0_isr;  //将cpu_timer0_isr的地址赋给TIMER0_INT
 PieVectTable.TIMER1_INT = &cpu_timer1_isr;
 PieVectTable.TIMER2_INT = &cpu_timer2_isr;
 EDIS;   //关闭保护

2.3 初始化定时器和设置周期、频率

InitCpuTimers为定时器初始化程序。ConfigCpuTimer用于设置定时器的周期和频率,其中频率单位为MHz,时间单位为us(1e-6s)。因为28377D的主频为200Mhz,所以设置为频率设置为200.

 InitCpuTimers();  //初始化CPU定时器

 ConfigCpuTimer(&CpuTimer0, 200, 500000);  //设置定时器的频率和周期,这里设置为CPU0、200MHz、500000us(0.5s)
 ConfigCpuTimer(&CpuTimer1, 200, 1000000);  //1s
 ConfigCpuTimer(&CpuTimer2, 200, 2000000);  //2s

点击ConfigCpuTimer函数,可以看到参数Freq和Period,对于中断时间,可以采用如下的公式计算:
T=Freq*Period/(200e6)
其中200e6为28377的CPU频率200MHz

void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period)
{
...
}

2.3 对中断标志进行设置

CpuTimer0Regs.TCR.all = 0x4000;  //对定时器0的寄存器进行设置,使能定时器0中断
CpuTimer1Regs.TCR.all = 0x4000;
CpuTimer2Regs.TCR.all = 0x4000;

IER |= M_INT1;  //使能第1组中断
IER |= M_INT13;
IER |= M_INT14;

如下图TCR为定时器控制寄存器(Timer Control Register),其中第14位为控制中断使能功能,使该位为1,使能定时器中断。
在这里插入图片描述

2.3 定时器中断函数

//定时器0中断程序
__interrupt void cpu_timer0_isr(void)
{
    CpuTimer0.InterruptCount++;  //记录中断次数

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;  //中断响应标志位

    LED1_TOGGLE;  //LED1切换
}

其中PIEACK为中断应答寄存器,用来说明该中断组已经被锁存。

三、附录-程序

#include "F28x_Project.h"
#include "F2837xD_Ipc_drivers.h"

void GPIO_Setup(void);
__interrupt void cpu_timer0_isr(void);
__interrupt void cpu_timer1_isr(void);
__interrupt void cpu_timer2_isr(void);

#define LED1_TOGGLE GpioDataRegs.GPCTOGGLE.bit.GPIO89 = 1    //GPIO89切换电平
#define LED2_TOGGLE GpioDataRegs.GPCTOGGLE.bit.GPIO91 = 1
#define LED3_TOGGLE GpioDataRegs.GPCTOGGLE.bit.GPIO93 = 1

void main(void)
{
   InitSysCtrl();

#ifdef _STANDALONE
#ifdef _FLASH
// CPU2运行程序
IPCBootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_FLASH);
#else
// CPU2运行程序
IPCBootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_RAM);
#endif
#endif

// FALSH烧写配置
#ifdef _FLASH
   InitFlash();
#endif

    InitGpio();
    GPIO_Setup();
    DINT;
    InitPieCtrl();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();

    //EALLOW,EDIS 一般是成对使用的,有些寄存器是受到保护的,不能任意写
    //EALLOW 相当于去掉保护,对写保护的寄存器进行操作后
    //EDIS 是重新把这个寄存器保护起来的意思
    EALLOW;  //写保护
    PieVectTable.TIMER0_INT = &cpu_timer0_isr;  //将cpu_timer0_isr的地址赋给TIMER0_INT
    PieVectTable.TIMER1_INT = &cpu_timer1_isr;
    PieVectTable.TIMER2_INT = &cpu_timer2_isr;
    EDIS;   //关闭保护

    InitCpuTimers();  //初始化CPU定时器

    ConfigCpuTimer(&CpuTimer0, 200, 500000);  //设置定时器的频率和周期,这里设置为CPU0、200MHz、500000us(0.5s)
    ConfigCpuTimer(&CpuTimer1, 200, 1000000);  //1s
    ConfigCpuTimer(&CpuTimer2, 200, 2000000);  //2s

    CpuTimer0Regs.TCR.all = 0x4000;  //对定时器0的寄存器进行设置,使能定时器0中断
    CpuTimer1Regs.TCR.all = 0x4000;
    CpuTimer2Regs.TCR.all = 0x4000;

    IER |= M_INT1;  //使能第1组中断
    IER |= M_INT13;
    IER |= M_INT14;

    PieCtrlRegs.PIEIER1.bit.INTx7 = 1;  //使能第1组中断的第7个通道中断,即定时器0中断

    EINT;  //使能全局中断
    ERTM;  // 使能全局中断实时调试

    while(1)
    {

    }
}

void GPIO_Setup() //配置GPIO的功能
{
    GPIO_SetupPinMux(89, GPIO_MUX_CPU1, 0);//对引脚89设置;选择CPU1为内核,选择外设功能0
    GPIO_SetupPinOptions(89, GPIO_OUTPUT, GPIO_PUSHPULL);//GPIO89,作为输出,上拉
    GPIO_SetupPinMux(91, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(91, GPIO_OUTPUT, GPIO_PUSHPULL);
    GPIO_SetupPinMux(93, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(93, GPIO_OUTPUT, GPIO_PUSHPULL);
}

//定时器0中断程序
__interrupt void cpu_timer0_isr(void)
{
    CpuTimer0.InterruptCount++;       //记录中断次数

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;  //中断响应标志位

    LED1_TOGGLE;    //LED1切换
}

//定时器1中断程序
__interrupt void cpu_timer1_isr(void)
{
    CpuTimer1.InterruptCount++;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    LED2_TOGGLE;
}

__interrupt void cpu_timer2_isr(void)
{
    CpuTimer2.InterruptCount++;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    LED3_TOGGLE;
}















  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值