6.DSP学习记录之定时器
基于 TI 28335
- 一、28335定时器介绍
- 1.定时原理
- (1)寄存器简介
- (2)对主频脉冲计数
- (3)对TIMCLK计数
- 2.定时器寄存器介绍
- (1)定时器控制寄存器TIMERxTCR
- (2)定时器预定标寄存器PSC
- (3)定时器计数器TIM
- (4)定时器周期寄存器TRD
- 二、定时器中断软件实现
- 1.定时器中断配置步骤
- 2.定时器中断实验
如何用16位存储器表示32位?
用两个16位存储器,举例:XH:X(XH表示高16位,X表示低16位)
一、28335定时器介绍
定时器就是计数器
1.定时原理
(1)寄存器简介
28335的定时器在总体上和STM32定时器类似,但是28335相当于两个对脉冲计数的串联,首先TIMCLK组对设定 主频的脉冲计数,到计数值后输出一个TIMCLK,然后串联的计数器对TIMCLK进行计数
如上图,28335的定时器由四个寄存器组成:按照我的理解,按计数原理分为两组,一组为TIMCLK计数,也就是小脉冲计数(我自己理解),包括定时器分频寄存器TDDRH:TDDR(TDDRH为TDDR的高16位,下面三个类推),预定标计数器PSCH:PSC;另一组为周期寄存器 PRDH:PRD和计数器TIMH:TIM
什么是TIMCLK??
TIMCLK是一个对主频脉冲的计数值
(2)对主频脉冲计数
TIMCLK由定时器分频器TDDRH:TDDR 和定时器预定标器PSCH:PSC来控制的。
先给定时器分频器 TDDRH:TDDR 赋值,然后装载入预定标器PSCH:PSC中,每隔一个SYSCLKOUT脉冲,PSCH:PSC中的值减1,当PSCH:PSC中的值为0时,就会输出一个TIMCLK从而使TIMH:TIM减1。在下一个定时器输入时钟周期开始时,TDDRH:TDDR中的值重新装载入PSCH:PSC中,周而复始地循环下去。因此,TIMCLK就等于(TDDRH:TDDR+1)个系统时钟的时间。
假设主频为X Mhz而TIMCLK的计算为:
TIMCLK = (TDDRH:TDDR + 1)/ X * 0.000001
(3)对TIMCLK计数
在CPU定时器工作前,先要根据实际的需求,计算好CPU定时器周期寄存器的值,然后给周期寄存器PRDH:PRD赋值。当启动定时器开始计数时,周期寄存器PRDH:PRD里面的值装载进定时器计数寄存器TIMH:TIM中。
计数器寄存器TIMH:TIM里面的值每隔一个TIMCLK就减小1,直到计数到0,完成一个周期的计数,而CPU定时器这时候就会产生一个中断信号,完成一个周期的计数后,在下一个定时器输入时钟周期开始时,周期寄存器PRDH:PRD里面的值重新装载入计数器寄存器TIMH:TIM中,周而复始地循环下去。于是,一个CPU定时器周期所经历的时间就等于:
(PRDH:PRD+1)×TIMCLK
结合以上计数原理,最终定时器的定时时间T计算式为:
T = (PRDH:PRD+1) × (TDDRH:TDDR + 1)/ X * 0.000001
而实际应用时,通常是确定了要定时的时间T和CPU的系统时钟X,来确定周期寄存器PRDH:PRD的值。TDDRH:TDDR通常可以取为0,如果取0的时候,PRDH:PRD的值超过了32位寄存器的范围,那么TDDRH:TDDR可以取其他值,使得PRDH:PRD的值小一些,从而能放到32位寄存器中。
此处注意:
在实际的定时使用中,通常不直接写入PRD和TDDR,而是通过调用库函数ConfigCpuTimer,定义:
voidConfigCpuTimer(structCPUTIMER_VARS*Timer,floatFreq,floatPeriod){Uint32 temp;//Initializetimerperiod:Timer->CPUFreqInMHz=Freq;Timer->PeriodInUSec=Period;temp=(long)(Freq*Period);Timer->RegsAddr->PRD.all=temp;//Setpre-scalecountertodivideby1(SYSCLKOUT):Timer->RegsAddr->TPR.all =0;Timer->RegsAddr->TPRH.all =0;//Initializetimercontrolregister:Timer->RegsAddr->TCR.bit.TSS = 1; // 1 = Stop timer, 0 =Start/RestartTimerTimer->RegsAddr->TCR.bit.TRB=1; //1=reloadtimerTimer->RegsAddr->TCR.bit.SOFT=0;Timer->RegsAddr->TCR.bit.FREE=0; //TimerFreeRunDisabledTimer->RegsAddr->TCR.bit.TIE=1; //0=Disable/1=EnableTimerInterrupt//Resetinterruptcounter:Timer->InterruptCount=0;}
可以看到: Timer->RegsAddr->PRD.all=temp;
而 temp=(long)(FreqPeriod);;即PRD为该函数第二第三参数乘积,而 Timer->RegsAddr->TPR.all =0;说明将TDDR取为0,则根据定时公式:
T = (PRDH:PRD+1) × (TDDRH:TDDR + 1)/ X * 0.000001
T = FreqPeriod / X * 0.000001,若Freq为主频,单位为MHz,则:
T = Period * 0.000001
即 参数Period 为定时周期乘以0.000001
而 T 的单位是秒S,则Period 单位为微秒us
2.定时器寄存器介绍
定时器配置和控制的寄存器如下:
(1)定时器控制寄存器TIMERxTCR
(2)定时器预定标寄存器PSC
(3)定时器计数器TIM
(4)定时器周期寄存器TRD
二、定时器中断软件实现
1.定时器中断配置步骤
(1)使能定时器时钟
EALLOW;SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK=1;//CPUTimer0EDIS;
(2)初始化定时器参数
包括制定定时器寄存器地址、周期寄存器值、预定标计数器值等。
要使用F28335的CPU定时器,还需要对其内部相关寄存器的设置,具体设置代码如下:
//指向定时器0的寄存器地址
CpuTimer0.RegsAddr=&CpuTimer0Regs;//设置定时器0的周期寄存器值
CpuTimer0Regs.PRD.all =0xFFFFFFFF;//设置定时器预定标计数器值为0CpuTimer0Regs.TPR.all =0;CpuTimer0Regs.TPRH.all=0;//确保定时器0为停止状态
CpuTimer0Regs.TCR.bit.TSS=1;//重载使能
CpuTimer0Regs.TCR.bit.TRB=1;//Resetinterruptcounters:CpuTimer0.InterruptCount=0;
(3)定时器的设置
要使用定时器还需要设置它的定时周期以及设置定时器的控制寄存器等.这一步通过TI封装好的函数直接配置。
voidConfigCpuTimer(structCPUTIMER_VARS*Timer,floatFreq,float Period)
该函数有3个参数,第1个表示哪个定时器,第2个表示定时器频率,第3个表示定时器周期值。
(4)设置定时器0的中断入口地址
//设置定时器0的中断入口地址为中断向量表的INT0EALLOW;PieVectTable.TINT0=&TIM0_IRQn;//中断服务函数名EDIS;
(5)开启定时器中断功能,并使能定时器
CpuTimer0Regs.TCR.bit.TSS=0; //开始定时器功能PieCtrlRegs.PIEIER1.bit.INTx7=1;//PIE级中断使能,第一组中断的第7个小中断,即定时器0//使能CPU总中断
IER|=M_INT1;
EINT;
ERTM;
(6)编写定时器中断服务函数
中断服务函数用于产生中断后的操作,注意要在编写中断服务函数时需要在函数名前面加上一个关键字“interrupt”
interruptvoidTIM0_IRQn(void){......功能程序
}
2.定时器中断实验
效果:用定时器0控制LED1灯按照一秒翻转电平闪烁
代码:
中断代码:
#include "Interrupt.h"
#include "led.h"interrupt void TIM0_IRQn(void)
{EALLOW;GpioDataRegs.GPCTOGGLE.bit.GPIO68=1;PieCtrlRegs.PIEACK.bit.ACK1=1;EDIS;
}void Tim0_Init(float Freq, float Period)
{//1.时钟初始化EALLOW;SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1;EDIS;//2.初始化定时器参数CpuTimer0.RegsAddr=&CpuTimer0Regs;//指向定时器0的寄存器地址CpuTimer0Regs.PRD.all =0xFFFFFFFF; //设置定时器0的周期寄存器值CpuTimer0Regs.TPR.all =0;//设置定时器预定标计数器值为0CpuTimer0Regs.TPRH.all=0;CpuTimer0Regs.TCR.bit.TSS=1; //确保定时器0为停止状态CpuTimer0Regs.TCR.bit.TRB=1; //重载使能CpuTimer0.InterruptCount=0; //Resetinterruptcounters://3.定时器定时周期以及设置定时器的控制寄存器等ConfigCpuTimer(&CpuTimer0,Freq,Period);//4.设置定时器0的中断入口地址为中断向量表的INT0EALLOW;PieVectTable.TINT0=&TIM0_IRQn;EDIS;//5.开启定时器中断功能,并使能定时器CpuTimer0Regs.TCR.bit.TSS=0; //开始定时器功能PieCtrlRegs.PIEIER1.bit.INTx7=1;//PIE级中断使能,第一组中断的第7个小中断,即定时器0//使能CPU总中断IER|=M_INT1;EINT;ERTM;
}
主函数:
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP2833x Examples Include File
#include "beep.h"
#include "Key.h"
#include "led.h"
#include "Interrupt.h"void main()
{InitSysCtrl();InitPieCtrl();IER=0x0000;IFR=0x0000;InitPieVectTable();Led_Init();Tim0_Init(150,100000);while(1){GpioDataRegs.GPCCLEAR.bit.GPIO64=1;}
}