问题描述
为了备赛蓝桥杯,开始更深入的接触PWM的各个模式(之前只使用过PWM1和PWM2的输出模式)。在比赛提供的官方固件库的基础上进行修改,暂且用了两块板子,板子A烧录的之前写的输出比较输出两路频率和占空比可变的PWM作为信号发生源供烧入捕获的板子B检测。 板子A一路是1Khz作为基频的频率可调,另一路是10Khz作为基频的占空比可调的PWM(只有四个按键,就一路一个功能了)。
官方例程基本不需要改动就可用,但是板子B检测到的的基频1Khz的PWM频率显示数值异常,但是频率加上去以后就正常。而且两路PWM占空比都和真实PWM存在1%误差,如图
问题代码
初次接触还是很有必要了解一下PWM输入捕获模式的(一种特殊的输入捕获),可以去B站看一下一下野火的视频(PWM部分分各种模式讲的,比较详细)或翻看一下资料,不再赘述。
V3.5库的"Project->STM32F10x_StdPeriph_Examples->TIM->PWM_input"文件夹下
占空比误差解决
看过野火视频就基本一目了然了,CNT计数值是0开始计数的,计数到N-1进入中断时捕获的是N-1,其实记录了N个数,所以需要在中断服务函数内进行
+1修改。(高频时不改影响不大)
解决方案
参考文章
https://www.firebbs.cn/thread-14334-1-1.html
低频错误解决
这个其实也简单,不过发现问题着实费了些功夫。之前过于依赖固件库也受其它帖子影响以为自己出了问题。
原因:固件库例程未对定时器预分频系数和周期做配置(主要是预分频系数)
解决方案:添加定时器预分频系数配置函数
需要注意你配置的定时器分频以后的频率要小于你的基频(可以理解成要求检测的最小频率)
举个栗子,1Khz是我要检测的基频,定时器频率f=72M(不分频)/(psc+1) /(period(周期)+1),如果我设置psc为71,period需要大于999。同时在中断服务函数计算频率时 需要用分频后的数值(72M/(psc+1))/寄存器+1的值。因为你的配置的定时器速度小于基频是会漏掉或检测不到你的跳变沿。
效果演示
代码
void PWMCP_Init()
{
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
TIM_Cmd(TIM3, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
}
__IO uint16_t IC2Value = 0;
__IO uint16_t DutyCycle = 0;
__IO uint32_t Frequency = 0;
void TIM3_IRQHandler(void)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
IC2Value = TIM_GetCapture1(TIM3);
if (IC2Value != 0)
{
DutyCycle = ((TIM_GetCapture2(TIM3)+1) * 100) / (IC2Value+1);
Frequency = SystemCoreClock / (72*(IC2Value+1));
}
else
{
DutyCycle = 0;
Frequency = 0;
}
}
欢迎批评指正,需要工程的可以留下邮箱!