stm32通用定时器有多种输入模式,其中包括了pwm输入模式。
原理pwm输入模式是在输入捕获的基础上使用两组输入捕获通道对同一个TIM引脚进行捕获。
如下图所示:
TIMx_CH1引脚输入一个pwm信号,经过输入滤波和边沿检测之后一路(TI1FP1)给到了IC1,一路(TI1FP2)给到了IC2,从而实现两个捕获通道捕获同一个pwm信号。IC1负责测量pwm信号的周期,而IC2负责测量pwm信号的脉宽。
总的来说是基于输入捕获功能实现了对输入pwm信号的测量。
功能实现以STM32F103RC为例,我们选择PA6引脚,使用TIM3_CH1功能,如下图:
下面列出主要步骤:
第一步:打开TIM3和GPIO的时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA时钟
第二步:初始化GPIO引脚功能
//PA6引脚GPIO初始化,用于捕获输入的pwm信号,测量其周期
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
第三步:初始化定时器timebase
//定时器初始化
TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_TimeBaseInitTypeStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitTypeStruct.TIM_CounterMode = TIM_CounterMode_Up;//计数方式
TIM_TimeBaseInitTypeStruct.TIM_Period = arr;//自动装载值
TIM_TimeBaseInitTypeStruct.TIM_Prescaler = psc;//预分频系数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitTypeStruct);
第四步:初始化捕获参数
//channel1 设置捕获参数
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0xf; //采样频率设为0.56MHz,连续采8次,可以滤掉14微秒的干扰
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //捕获极性
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //每检测到一个有效边沿就捕获一次
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_PWMIConfig(TIM3, &TIM_ICInitStruct);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
第五步:配置定时器的中断
//使能定时器的中断,包括更新中断、CC1捕获中断
TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_CC1,ENABLE);
第六步:配置NVIC irq通道,初始化NVIC
//中断优先级分组
NVIC_InitTypeStruct.NVIC_IRQChannel = TIM3_IRQn;//中断通道
NVIC_InitTypeStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitTypeStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitTypeStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitTypeStruct);
第七步:使能定时器
TIM_Cmd(TIM3,ENABLE);
第八步:编写定时器中断服务函数
//中断服务函数
void TIM3_IRQHandler(void)
{
//判断是否为定时器3产生的中断
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
{
if(s_tim3_IC_edge == 1) //在一个pwm周期内计数器溢出要计数
{
s_tim3_exceed++;
}
//要手动的清理中断标志位
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
if(TIM_GetITStatus(TIM3,TIM_IT_CC1)==SET) //捕获CC1中断
{
//要手动的清理中断标志位
TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);
/* Get the Input Capture value */
s_tim3_IC_val = TIM_GetCapture1(TIM3);
if (s_tim3_IC_val != 0)
{
/* Duty cycle computation */
s_tim3_pwminput_dutycycle = (TIM_GetCapture2(TIM3) * 100) / s_tim3_IC_val;
/* Frequency computation */
s_tim3_pwminput_freq = TIM3_TIME_BASE / s_tim3_IC_val;
}
else
{
s_tim3_pwminput_dutycycle = 0;
s_tim3_pwminput_freq = 0;
}
}
}
主任务通过以下函数获取pwm的频率和占空比:
uint16_t timer_get_pwm_period(void)
{
return s_tim3_pwminput_freq;
}
uint16_t timer_get_pwm_dutycycle(void)
{
return s_tim3_pwminput_dutycycle;
}
目前没有开发板,无法进行硬件实验,后面有时间再慢慢补充相关知识点和可能遇到的问题。
注意事项1、输入滤波如何设置。
原理:
输入信号可以通过数字滤波器进行滤波,滤波器的时钟由定时器的时钟(CK_INT)分频得到;滤波原理是使用采样信号对输入信号进行采样,根据连续多次采样的结果来判定输入电平是否跳变,如果连续采集到的结果都是同一个新的电平状态,就判定输入电平发生了跳变,然后给到边沿检测电路进行边沿检测;否则,判定电平状态没有发生改变,实现对干扰信号的过滤。
设置:
首先在初始化timebase的时候要选择时钟分频因子TIM_ClockDivision,这个参数用来确定数字滤波器的时钟频率,寄存器描述如下:
然后在初始化捕获参数时配置TIM_ICFilter,寄存器描述如下: