PWM输入捕获是输入捕获的一个特例,他要捕获PWM的周期和脉宽.一个定时器刚好链接两个IC输入.
那么PWM捕获输入的原理,也就从这里打通经脉.
高深的不说,那是各种什么原理,没必要了解,我们最重要是目的.看看实际逻辑.
IC2就是占空比,IC1就是周期长度,这样PWM就捕获了,如果频率太高,估计还要DMA,但是至少不用进入后然后更换边沿再捕捉.配置方法也说了.
看这么多,晕了,其实就是说明,Cube里面这么配置,就OK了.记得改Period(ARR)是0xFFFF哦.
生成的定时器初始化代码如下(最后5行是后自己打上的):
void TIM21_PWMInput(void){ LL_TIM_InitTypeDef TIM_InitStruct; LL_GPIO_InitTypeDef GPIO_InitStruct; /* Peripheral clock enable */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM21); /**TIM21 GPIO Configuration PA3 ------> TIM21_CH2 */ GPIO_InitStruct.Pin = LL_GPIO_PIN_3; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; GPIO_InitStruct.Alternate = LL_GPIO_AF_0; LL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* TIM21 interrupt Init */ NVIC_SetPriority(TIM21_IRQn, 0); NVIC_EnableIRQ(TIM21_IRQn); TIM_InitStruct.Prescaler = 0; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.Autoreload = 0xFFFF; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; LL_TIM_Init(TIM21, &TIM_InitStruct); LL_TIM_SetClockSource(TIM21, LL_TIM_CLOCKSOURCE_INTERNAL); LL_TIM_SetTriggerInput(TIM21, LL_TIM_TS_TI2FP2); LL_TIM_SetSlaveMode(TIM21, LL_TIM_SLAVEMODE_RESET); LL_TIM_CC_DisableChannel(TIM21, LL_TIM_CHANNEL_CH2); LL_TIM_IC_SetFilter(TIM21, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); LL_TIM_IC_SetPolarity(TIM21, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING); LL_TIM_DisableIT_TRIG(TIM21); LL_TIM_DisableDMAReq_TRIG(TIM21); LL_TIM_SetTriggerOutput(TIM21, LL_TIM_TRGO_RESET); LL_TIM_DisableMasterSlaveMode(TIM21); LL_TIM_IC_SetActiveInput(TIM21, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_INDIRECTTI); LL_TIM_IC_SetPrescaler(TIM21, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); LL_TIM_IC_SetFilter(TIM21, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); LL_TIM_IC_SetPolarity(TIM21, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING); LL_TIM_IC_SetActiveInput(TIM21, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI); LL_TIM_IC_SetPrescaler(TIM21, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); LL_TIM_EnableIT_CC1(TIM21); LL_TIM_EnableIT_CC2(TIM21); LL_TIM_CC_EnableChannel(TIM21,LL_TIM_CHANNEL_CH1); LL_TIM_CC_EnableChannel(TIM21,LL_TIM_CHANNEL_CH2); LL_TIM_EnableCounter(TIM21); }
注意,最后5行是自己打的,特缩进来大家看看,这就是开启时钟和CC捕获.然后数值计算的中断.
void TIM21_IRQHandler(void) { if(LL_TIM_IsActiveFlag_CC1(TIM21)){ LL_TIM_ClearFlag_CC1(TIM21); } if(LL_TIM_IsActiveFlag_CC2(TIM21)){ LL_TIM_ClearFlag_CC2(TIM21); } uwIC2Value = LL_TIM_OC_GetCompareCH2(TIM21); if (uwIC2Value != 0) { uwDutyCycle = ((LL_TIM_OC_GetCompareCH1(TIM21)) * 50) / uwIC2Value; uwFrequency = 16000000 / uwIC2Value; } else { uwDutyCycle = 0; uwFrequency = 0; } }
我主频32MHz,定时器频率也是32MHz,设置公式写16MHz,而占空比部分放大了100倍才能观察,不然是float型的,所以乘以100除以2,反正什么都折半算就对了.但是官方也有PWM Input参考代码不用折半,但是我发现结果不对,后来折半后结果就对了.看效果.用的555生成点波形.看,这是25%占空比,245Hz.(此处25%指的是高电平的范围)
验证:
深入思考:
这个频率计,可以捕获的频率范围是多少呢?
答->可测得最小频率是 TIM时钟频率/65535
精度又是多少呢?
答->精度就是 1/TIM时钟频率
怎么做一个自适应精度宽频率的测频计呢?
答->当频率过低的时候,增加TIM的分频系数,当频率过高时候,减少TIM的分频系数.
STM32L011K4-PWMInput