MCU微课堂
CKS32F107xx TIM(三)
第四十八期 2024.11.08
PWM输入捕获
上节课我们介绍了高级定时器互补PWM输出的配置方法,这节课我们将向大家介绍高级定时器的另一个常见应用——PWM输入模式。在本节课中,我们将先围绕输入捕获模式展开,并重点描述PWM输入模式和涉及的寄存器,最后通过一个实验例程去介绍PWM输入模式的配置方法。
输入捕获模式简介
1、普通输入模式
除基本定时器外,其余定时器的部分通道都可以对输入信号的上升沿、下降沿或者双边沿进行捕获,并且计数器CNT的值会被锁存到捕获/比较寄存器CCR中。当我们需要同时捕获PWM波的频率和占空比时,仅需要测出一个周期中高电平和低电平持续的时间即可。我们可尝试如下步骤:首先将定时器的某一通道初始设置为上升沿捕获,当发生第一次捕获到上升沿的中断,以此中断时刻作为一个起点,读取CCR中值为Value1,此时将捕获模式设置为下降沿捕获,在发生第二次中断的时候,捕获到了下降沿,读取CCR中值为Value2,那么Value2和Value1之间的差值,就是一个周期中高电平持续的时间,然后我们在中断中又将捕获的方式设置为上升沿捕获,那么在第三次产生中断的时候,读取CCR中值为Value3,那么Value3和Value2之间的差值就是一个周期中低电平的时间。至此,PWM波的频率可由Value3和Value1之间的差值计算出,正占空比则可通过高电平占整个周期的比值获得。如下图1所示:
图1 普通输入捕获概览图
2、PWM输入模式
PWM输入模式是普通输入模式的一种特例,以输入通道TI1为例,PWM信号进入该通道后,信号被分成TI1FP1和TI1FP2两路,最终分别映射到了IC1和IC2捕获通道,其中一个捕获上升沿,另一个捕获下降沿。这样用户可以在中断中去读上升沿和下降沿对应寄存器中的计数,从而得出周期和占空比。并且用户在设计之初,需要先选定哪一路为触发信号以及触发极性,一旦选定某一路为触发信号则对应的即为周期,另一路则对应为占空比,两路捕获极性也是相反的,并且因为是PWM输入捕获的缘故,当其中一路配置完成,另一路由硬件自动配置,无需软件来配置。图2为PWM输入模式时序图。
图2 PWM输入模式时序图
其中,IC1捕获通道计算两次都是上升沿的时间,即周期T;而IC2通道则计算一次下降沿和之前上升沿之差,这样得到高电平时长,从而可以求得周期T和占空比。需要注意的是,PWM输入模式需要占用两个捕获寄存器,且只有TI1FP1和TI2FP2连接到了从模式控制器(使用PWM输入捕获时,需要配置从模式控制器为复位模式),所以只能使用定时器的通道1或通道2。
寄存器和输入捕获结构体概述
1、捕获/比较寄存器CCMR
关于CCMR寄存器,上节课我们介绍了输出比较模式,这节课我们来介绍下输入捕获模式,该寄存器的各位描述图如下:
图3 CCMR1寄存器各位描述图
该16位寄存器CCMR的下层对应输入捕获(上层对应输出比较),其中CCMR1用于捕获通道1和2的控制,CCMR2用于捕获通道3和4的控制。下图为低8位详细描述图,用于捕获通道1。
图4 CCMR1寄存器低7位描述图
参数CC1S,用于输入捕获/输出比较通道的引脚选择,若我们设置CCIS[1:0] = 01,表明CC1通道(对应定时器的通道1)被配置为输入,IC1映射在TI1上。
参数IC1PSC,配置为00时,表明每1个边沿触发1次捕获。
参数IC1F,用来设置TI1输入采样频率和数字滤波器长度,本课中我们不做滤波处理。
2、捕获/比较使能寄存器CCER
在本课中我们仅用到低2位CC1E和CC1P,由于我们需要在中断中处理捕获的数据,所以配置CC1E为1,CC1P配置为不反相,故设置为0。CCER低2位图如下描述。
图5 CCMR1寄存器低7位描述图
3、输入捕获结构体TIM_ICInitTypeDef
可配合TIM_PWMIConfig函数完成定时器输入通道各参数的初始化配置。输入捕获结构体的各参数定义如下:
typedef struct
{
uint16_t TIM_Channel;
uint16_t TIM_ICPolarity;
uint16_t TIM_ICSelection;
uint16_t TIM_ICPrescaler;
uint16_t TIM_ICFilter;
} TIM_ICInitTypeDef;
1)参数TIM_Channel:设定CCMRx寄存器CCxS位,用于捕获通道ICx选择。
2)参数TIM_ICPolarity:设定CCER寄存器CCxP位和CCxNP位,用于输入捕获边沿触发选择。
3)参数TIM_ICSelection:设定CCRMx寄存器的CCxS[1:0]位,用于输入通道选择,输入通道共有三个来源,分别为:TIM_ICSelection_DirectTI、TIM_ICSelection_IndirectTI或TIM_ICSelection_TRC。若为普通输入模式,4个通道均能使用;若为PWM输入模式,只能使用通道1和2。输入通道和捕获通道的映射关系详见下图。
图6 输入通道和捕获通道的映射关系
4)参数TIM_ ICPrescaler:设定CCMRx寄存器的ICxPSC[1:0]位的值,用来设置输入捕获分频系数,有1、2、4、8分频可选。这里我们需要捕获输入信号的每个有效边沿,故设置为1分频即可。
5)参数TIM_ ICFilter:设定CCMRx寄存器ICxF[3:0]位,用于设置输入捕获滤波器。
本课中我们配置的示例代码如下:
TIM_ICInitTypeDef TIM_ICInitStructure;
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(TIM1, &TIM_ICInitStructure);
上述代码中,我们设置定时器的通道1为上升沿捕获,且输入通道1(TI1)与捕获通道1(IC1)为直接映射,不分频,不使用滤波器。
PWM模式输入配置实验
本实验配置高级定时器的通道1,即PA8,用于捕获信号发生器输出PWM信号,最后通过串口调试助手打印捕获到的PWM的频率和占空比。主要的编程要点如下。
1、高级定时器引脚初始化
由于TIM1_CH1是连接在PA8上,这里需要开启GPIOA时钟,并配置引脚为浮空输入,我们配置的代码如下:
void TIM1_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
2、高级定时器中断优先级设置
之前的课程中让我们对中断优先级已经有了深入了解,这里因为我们只有一个捕获/比较中断源,所以优先级随便设置,我们配置的代码如下:
void TIM1_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
3、高级定时器PWM输入模式配置
我们主要对时基和输入捕获结构体初始化,配置代码如下:
void TIM1_Input_Capture_Mode_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
/* Time Base Configuration */
TIM_TimeBaseStructure.TIM_Period = 65535-1;
TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* PWM Input Capture Configuration */
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(TIM1, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable);
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
TIM_Cmd(TIM1, ENABLE);
}
从上述示例代码来看,我们首先将TIM1_CH1的捕获计数器设置为1us计数一次,重装载值为65535,所以可以捕获的时间精度为1us,最低可捕获的频率为15.3Hz。其次,我们选择TIM1的通道1(TI1)作为PWM信号输入,并选择TI1FP1为触发信号(输入的信号被分为TI1FP1和TI1FP2),因此IC1捕获PWM信号周期,IC2捕获PWM信号占空比。而且由于PWM输入模式下,当捕获开始时,需要将CNT复位,所以我们需要配置定时器以从模式工作在复位模式下,最后使能捕获中断和高级定时器。
4、高级定时器中断服务函数配置
在函数TIM1_CC_IRQHandler中,如果是第一个上升沿中断,计数器CNT会被复位,锁存到CCR1寄存器的值是0,CCR2寄存器的值也是0,无法计算频率和占空比。当第二次上升沿到来的时候,CCR1和CCR2捕获到的才是有效的值。其中CCR1对应的是周期,CCR2对应的是占空比。我们配置的代码如下:
void TIM1_CC_IRQHandler(void)
{
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
IC1Value = TIM_GetCapture1(TIM1);
IC2Value = TIM_GetCapture2(TIM1);
if (IC1Value != 0)
{
DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);
Frequency = (72000000/((72-1)+1))/(float)(IC1Value+1);
printf("占空比:%0.2f%% 频率:%0.2fHz ", DutyCycle, Frequency);
}
else
{
DutyCycle = 0;
Frequency = 0;
}
}
5、主函数配置
main函数就是对上述函数的调用,配置示例如下:
int main(void)
{
CKS_USART_Init();
printf("CKS Timer Input Capture Demo start running... ");
TIM1_GPIO_Configuration();
TIM1_NVIC_Configuration();
TIM1_Input_Capture_Mode_Configuration();
while(1){}
}
至此,我们配置已完成。
6、下载验证
我们将编译好的程序下载至CKS32F107xx开发板,信号发生器和PWM输入引脚PA8通过杜邦线连接,USB转TTL模块分别与UART1—PA9和电脑相连,然后打开串口调试助手,查看打印信息。
全部0条评论
快来发表一下你的评论吧 !