PWM采集方法介绍
GaoSheng Lv4

本介绍两种常用的PWM采集方法
1.TIM的PWM输入捕获
2.IO中断+定时器

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

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;//IC1 产生上升沿时发生捕获动作
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);

//选择通道2的滤波后信号作为触发源,即CH的上升沿
/* Select the TIM3 Input Trigger: TI2FP2 */
TIM_Trigger_Source_Select(TIM3, TIM_TRIG_SEL_TI2FP2);

//上升沿复位计数器,便于直接测量周期 TIM3->CNT复位为0
/* Select the slave Mode: Reset Mode */
TIM_Slave_Mode_Select(TIM3, TIM_SLAVE_MODE_RESET);

/* Enable the Master/Slave Mode */
TIM_Master_Slave_Mode_Set(TIM3, TIM_MASTER_SLAVE_MODE_ENABLE);


/* TIM enable counter */
TIM_On(TIM3);

//使能CC2中断,捕获上升沿完成时触发
/* Enable the CC2 Interrupt Request */
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)
{

/* Clear TIM3 Capture compare interrupt pending bit */
TIM_Interrupt_Status_Clear(TIM3, TIM_INT_CC2);

/* Get the Input Capture value */
IC2Value = TIM_Compare_Capture2_Get(TIM3);

if (IC2Value != 0)
{
/* Duty cycle computation */
DutyCycle = (TIM_Compare_Capture1_Get(TIM3) * 100) / IC2Value;

/* Frequency computation */
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
period = (0xFFFF - lastRiseTime) + currentTime;
}
lastRiseTime = currentTime;
} else {
// 下降沿:记录时间戳,计算高电平时间
if (currentTime >= riseTime) {
highTime = currentTime - riseTime;
} else {
// 发生一次溢出:highTime = (0xFFFF - riseTime) + currentTime
highTime = (0xFFFF - riseTime) + currentTime;
}
// 计算频率和占空比
if (period != 0) {
frequency = 1e6f / period; // 1MHz时钟,单位Hz
dutyCycle = ((float)highTime / period) * 100.0f;
}
}
EXTI_ClearITPendingBit(PWM_INPUT_EXTI); // 清除中断标志
}
}

需要特别注意的点:
如果要使用PWM_IN的话只能使用通道1和通道2
1742658755748
1742658876424

本站由 提供部署服务