PIT定时器(Periodic Interrupt Timer),也叫做周期性中断定时器(反正我是这么翻译的),是一个32位递减计数器,每个时钟周期减1。与普通的定时器相比,它只能递减计数,而不能向上计数,普通的定时器,相对高级一点的能向上或者向下计数,甚至再高级一点的可以产生pwm等等。而它就只能周期计数。但是不要小看它,它最大的作用就是为其它外设提供周期信号。这听起来像废话,普通定时器不行吗?当然行,但是普通定时器需要重启计数器才能改变计数周期,而PIT定时器可以不需要重新启动(其实就是重新初始化)就可以改变计数周期。典型的应用就是PIT+ADC,ADC周期性采集255(或者更大)的信号数据,通过FFT(快速傅里叶变换)处理,得到一段新的信号,这是很常见的,特别是做混合信号处理的时候。
描述一下特性吧:
由图可知,PIT定时器的时钟来源于外部,至于外部选择哪个时钟源,这个得看自己配置需求了。而我选择的是osc_clk提供的时钟源。
步入正题,用SDK配置PIT:
首先初始化pit,记得添加对应的.c和.h文件,代码如下:
void Pit_init(uint8_t PIT_CHn,uint32_t reload)
{
pit_config_t config;
pit_chnl_t channel;
if(PIT_CHn==0) channel = kPIT_Chnl_0;
else if(PIT_CHn==1) channel = kPIT_Chnl_1;
else if(PIT_CHn==2) channel = kPIT_Chnl_2;
else if(PIT_CHn==3) channel = kPIT_Chnl_3;
/* PIT时钟配置 */
CLOCK_SetMux(kCLOCK_PerclkMux,1U);
CLOCK_SetDiv(kCLOCK_PerclkDiv,0U);
PIT_GetDefaultConfig(&config);
config.enableRunInDebug = true;
PIT_Init(PIT, &config);
/* 设置PIT定时器通道0自动重装载值 */
PIT_SetTimerPeriod(PIT,channel,USEC_TO_COUNT(reload, PIT_SOURCE_CLOCK));
/* 清除通道0的中断标志位 */
PIT_ClearStatusFlags(PIT,channel,kPIT_TimerFlag);
/* 使能通道0的计时完成中断 */
PIT_EnableInterrupts(PIT, channel, kPIT_TimerInterruptEnable);
//Set_NVIC_PriorityGroup(Group_4);
//Set_IRQn_Priority(PIT_IRQn,Group4_PreemptPriority_6, Group4_SubPriority_0);
PIT_NVIC_Config();
/* 使能中断 */
EnableIRQ(PIT_IRQn);
if(PIT_CHn==0) PIT_StartTimer(PIT,kPIT_Chnl_0);
else if(PIT_CHn==1) PIT_StartTimer(PIT,kPIT_Chnl_1);
else if(PIT_CHn==2) PIT_StartTimer(PIT,kPIT_Chnl_2);
else if(PIT_CHn==3) PIT_StartTimer(PIT,kPIT_Chnl_3);
}
为了方便,写成通用型的了。
初始化之前,需要写好中断配置:
static void PIT_NVIC_Config(void)
{
uint32_t Priority_Encode = 0;
NVIC_SetPriorityGrouping(0x04);
Priority_Encode = NVIC_EncodePriority (0x04, 0x06, 0x00);//得到中断优先级编码
NVIC_SetPriority(PIT_IRQn,Priority_Encode);
}
然后编写对应的中断服务函数:
void PIT_IRQHandler(void)
{
if(PIT_GetStatusFlags(PIT, kPIT_Chnl_0))
{
/* 清除中断标志位 */
PIT_ClearStatusFlags(PIT, kPIT_Chnl_0, kPIT_TimerFlag);
PRINTF("进入PIT_CH0\n");
}
else if(PIT_GetStatusFlags(PIT, kPIT_Chnl_1))
{
/* 清除中断标志位 */
PIT_ClearStatusFlags(PIT, kPIT_Chnl_1, kPIT_TimerFlag);
PRINTF("进入PIT_CH1\n");
}
}
我这里只用了两个通道的PIT定时器,所以在中断中只做了两次判断。
最后得到的效果是这样的,没做啥,就验证是否进入了中断。