我们常常使用定时器的输入捕获功能来测量脉冲信号的宽度,最新的KSDK 2.0虽然非常好用(抽象层级更低,更易于理解,也更灵活了),但TPM模块却只有唯一一个PWM的example,正好最近需要使用TPM模块的输入捕获功能,就利用KSDK 2.0实现了。
为了简化实验的硬件,我直接使用了FRDM-KL27Z开发板上的按键作为输入信号,因为开发板的按键PTC1正好连接到了TPM0_CH0通道,并且按键未按下时还有上拉电阻进行上拉。因此,硬件上无需做任何改动。按键未按下时PTC1被拉高,按键按下则为低电平,所以只需要检测低电平的脉宽,就可以知道按键按下的时长啦。
配置引脚,打开引脚、模块时钟是必须的。这里只关注TPM的配置和中断函数部分:
%20TPM_GetDefaultConfig(&tpmInfo);
tpmInfo.prescale%20=%20kTPM_Prescale_Divide_32;
tpmInfo.triggerSource%20=%20kTPM_TriggerSource_Internal;
%20/*%20Initialize%20TPM%20module%20*/
TPM_Init(TPM0,%20&tpmInfo);
%20TPM_SetupInputCapture(TPM0,kTPM_Chnl_0,kTPM_RiseAndFallEdge);
%20NVIC_EnableIRQ(TPM0_IRQn);
%20TPM_EnableInterrupts(TPM0,kTPM_Chnl0InterruptEnable);
%20TPM_EnableInterrupts(TPM0,kTPM_TimeOverflowInterruptEnable);
%20TPM_StartTimer(TPM0,%20kTPM_SystemClock);
这里选用了内部48MHz时钟,并进行了32分频,因此实际TPM模块的工作时钟为1.5MHz。在输入捕获模式下,我们需要同时捕获上升沿和下降沿,通过判断下降沿和上升沿之间定时器改变的计数值,我们就可以知道脉宽是多少啦。最后,记得打开中断并启动定时器,这里需要注意打开中断,需要同时打开ch0的通道中断和溢出中断,因为定时器的计数值位数是有限的,因此我们需要记录定时器溢出的次数,并在换算时累加上溢出的这一部分计数值,否则将导致错误的计算结果。
下面是中断函数内进行处理的代码:
void%20TPM0_IRQHandler(void)
{
static%20int%20OverCnt=0;
static%20unsigned%20int%20FE_CnV%20=%200;
if(TPM_GetStatusFlags(TPM0)%20&%20kTPM_Chnl0Flag)
{
TPM_ClearStatusFlags(TPM0,%20kTPM_Chnl0Flag);
if(GPIO_ReadPinInput(GPIOC,1))
{
PRINTF("Rising%20Edge!%20%d%20msrn",(TPM0->CONTROLS[kTPM_Chnl_0].CnV-FE_CnV+OverCnt*65536)/1500);
}
else
{
FE_CnV%20=%20TPM0->CONTROLS[kTPM_Chnl_0].CnV;
OverCnt%20=%200;
PRINTF("Falling%20Edge!");
}
}
else%20if(TPM_GetStatusFlags(TPM0)%20&%20kTPM_TimeOverflowFlag)
{
TPM_ClearStatusFlags(TPM0,%20kTPM_TimeOverflowFlag);
OverCnt++;
}
}
在中断函数内定义了两个静态变量OverCnt和FE_CnV,OverCnt用来记录定时器溢出的次数,FE_CnV则用来记录下降沿时定时器的当前计数值。由于在按键释放时,打印的是按键按下的ms值,因此在对计数值进行换算时是除以1500,而不是1500000。这样就通过TPM模块的输入捕获功能实现了打印按键按下的ms数的简单Demo啦!
需要注意的是,在使用TPM模块的输入捕获模式时,写入CnV寄存器将被忽略,因此不要尝试在输入捕获模式下去清零CnV寄存器哦~