本介绍两种常用的PWM采集方法
1.TIM的PWM输入捕获
2.IO中断+定时器
方法一:
定时器的通道的IO存在映射关系,可以把两个通道的信号(TI1,TI2)映射到同一个端口。
通过TIM的TI1通道采集PWM的上升沿,TI2来采集PWM的下降沿。这样就实现了对同一信号的双沿采集.
配置从模式中的复位模式,选择IC1捕获的上升沿有效信号为触发信号,并在上升沿触发时将记数值归零。这样在中断中CC1的值就为外部PWM的频率,CC2的值即为PWM的占空比

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| TIM_Input_Struct_Initialize(&TIM_ICInitStructure); TIM_ICInitStructure.Channel = TIM_CH_2; TIM_ICInitStructure.IcPolarity = TIM_IC_POLARITY_RISING; TIM_ICInitStructure.IcSelection = TIM_IC_SELECTION_DIRECTTI; TIM_ICInitStructure.IcPrescaler = TIM_IC_PSC_DIV1; TIM_ICInitStructure.IcFilter = 0x0; TIM_PWM_Input_Channel_Config(TIM3, &TIM_ICInitStructure);
TIM_Trigger_Source_Select(TIM3, TIM_TRIG_SEL_TI2FP2);
TIM_Slave_Mode_Select(TIM3, TIM_SLAVE_MODE_RESET);
TIM_Master_Slave_Mode_Set(TIM3, TIM_MASTER_SLAVE_MODE_ENABLE);
TIM_On(TIM3);
TIM_Interrupt_Enable(TIM3,TIM_INT_CC2);
|
下面是中断函数,可以说是非常简洁了,需要注意的点是:当上升沿触发时,输入捕获操作会先将当前的TIM3->CNT值锁存到CCR2寄存器,然后计数器TIM3->CNT才被复位为0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| void TIM3_IRQHandler(void) {
TIM_Interrupt_Status_Clear(TIM3, TIM_INT_CC2);
IC2Value = TIM_Compare_Capture2_Get(TIM3);
if (IC2Value != 0) { DutyCycle = (TIM_Compare_Capture1_Get(TIM3) * 100) / IC2Value;
Frequency = SystemCoreClockFrequency / IC2Value; } else { DutyCycle = 0; Frequency = 0; } }
|
这种方法只有IC1和IC2可以作为捕获通道,配置其中一个就行,另一个会被硬件自动配置相反极性。
方法二:
用IO口外部中断两次进入上升沿的时间差来计算频率(如果需要计算占空比需要将IO配置成双边沿触发),这种方法简单粗暴,对IO口也什么要求,不需要是TIM的CH1或者CH2,但是使用中需要考虑这种频率进中断会不会对系统代码造成影响,并且这种方法能够采集的PWM频率上限相较方法一会低很多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| void EXTI0_IRQHandler(void) { static uint16_t lastRiseTime = 0; uint16_t currentTime = TIM2->CNT;
if (EXTI_GetITStatus(PWM_INPUT_EXTI) { if (GPIO_ReadInputDataBit(PWM_INPUT_PORT, PWM_INPUT_PIN) == Bit_SET) { if (currentTime >= lastRiseTime) { period = currentTime - lastRiseTime; } else { period = (0xFFFF - lastRiseTime) + currentTime; } lastRiseTime = currentTime; } else { if (currentTime >= riseTime) { highTime = currentTime - riseTime; } else { highTime = (0xFFFF - riseTime) + currentTime; } if (period != 0) { frequency = 1e6f / period; dutyCycle = ((float)highTime / period) * 100.0f; } } EXTI_ClearITPendingBit(PWM_INPUT_EXTI); } }
|
需要特别注意的点:
如果要使用PWM_IN的话只能使用通道1和通道2

