stm32定时器pwm模式输入捕获
stm32中的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。这种模式通常用在对输入信号频率frequency、占空比duty、高低脉宽的计算中,具有很广泛的用途。
STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。
PWM模式捕获方法:利用TIM3_CH1作PWM输出,TIM2_CH2捕获上述PWM信号,并测出频率和占空比。设置PWM频率为1KHz,占空比50%。
具体步骤:
- 为了实现PWM输入捕获,TIM2占用了2个通道。第2通道的电平变化会被第一通道和第二通道引脚检测到,其中第一通道被设置为从机模式(如何快速判别主从机模式,规则如下:如果设置的是第二通道作为PWM输入捕获,则剩余的第一通道都为从机,反之亦然)。
- 假设输入的PWM从低电平开始跳变,在第一个上升沿到来时,1,2通道同时检测到上升沿。而从机设置为复位模式,所以将TIM2的计数值复位至0,此时不会产生一个中断请求。
- 下一个到来的电平是下降沿,此时通道1发生捕获事件,将计数值存入通道1的CCR1里。
- 然后是第二个上升沿到来后,此时通道2发生捕获事件,将此时的计数值存入通道2的CCR2里。复位模式此时又将TIM2计数值复位至0,等待第二个下降沿到来。
- 一次捕获过程完成,则PWM的频率f=72M/CCR2;占空比:duty=(CCR1/CCR2) X100%
注:
PWM输入模式时,用到两个通道(一般用TIMx_CH1或TIMx_CH2),只给其中一个通道分配gpio时钟即可,另一个在内部使用。给一个通道分配gpio时钟后,需要设置另一个为从机且复位模式。(例如使用ch2,ch1就得设置成从机模式)。当一个输入信号(TI1或TI2)来临时,主通道捕获上升沿,从机捕获下降沿。
在CH2通道中:
TI2FP1和TI2FP2都来自同一信号TI2 的边沿检测,信号相同,同一个TIx输入映射了两个ICx信号。
TI2FP1和TI2FP2可以分别由连接到的ICx (IC1或是IC2)相对应的控制寄存器设为上升沿或是下降沿触发,这两个ICx信号分别在相反的极性边沿有效。如果TI2FP2设置为上升沿触发,则TI2FP1设置为下降沿触发,二者极性相反。
CH1,3,4相同。
具体程序:
include “pbdata.h”
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void TIM2_Configuration(void);
void TIM3_Configuration(void);
void USART_Configuration(void);
int fputc(int ch,FILE *f)
{
USART_SendData(USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}
int main(void)
{
RCC_Configuration(); //配置时钟
GPIO_Configuration();//IO口配置
TIM3_Configuration();
TIM2_Configuration();
NVIC_Configuration();
USART_Configuration();
while(1)
{
if(flag==1)
{
flag=0;
printf(“the duty is %d/r/n”,duty);
printf(“the frequency is %.2fKHz /r/n”,freq);
}
}
}
void RCC_Configuration(void)
{
SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//LED
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//PWM,TIM3_CH1
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//TIM2_CH2
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//选择TIM2_CH2,选择输入端 IC2映射到TI2上
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TI2上
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//在捕获输入上每探测到一个边沿执行一次捕获
TIM_ICInitStructure.TIM_ICFilter=0;//滤波设置,经历几个周期跳变认定波形稳定。(采样高电平,只有连续采集到N个电平是高电平时才认为是有效的,否则低于N个时认为是无效的,N取0x0-0xF)
TIM_PWMIConfig(TIM2,&TIM_ICInitStructure);//以上是输入捕获配置
TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2);//选择滤波后的TI2FP2输入作为触发源,触发下面程序的复位
TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);//从模式控制器被设置为复位模式-选中的触发信号上升沿重新初始化计数器并产生一个更新信号(上升沿一到,TIM2->CNT被清零,每次上升沿来到,CNT都会被清零)
TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);//捕获中断打开
TIM_ClearFlag(TIM2,TIM_IT_CC2);//清除标志位
TIM_Cmd(TIM2,ENABLE);//使能定时器2
}
void TIM3_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseStruct.TIM_Period=72000;//计数初值
TIM_TimeBaseStruct.TIM_Prescaler=0;//分频系数
TIM_TimeBaseStruct.TIM_ClockDivision=0;//时钟分割
TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);
//TIM3_CH1作为pwm输出
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=36000;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OC1Init(TIM3,&TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3,ENABLE);
TIM_Cmd(TIM3,ENABLE);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate=115200;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE);
USART_ClearFlag(USART1,USART_FLAG_TC);
}
//中断程序
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==Bit_SET)
{
float IC2Value=0;
float DutyCycle=0;
float Frequency=0;
float pulse=0;
IC2Value=TIM_GetCapture2(TIM2);//获得CCR2的值
pulse=TIM_GetCapture1(TIM2);//获得CCR1的值
DutyCycle=pulse/IC2Value;
Frequency=72000000/IC2Value;
duty=(u32)(DutyCycle*100);
freq=(Frequency/1000);
flag=1;
TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);
}
}
duty和freq是定义的全局变量
extern u32 duty;
extern u16 freq;
u32 duty=0;
u16 freq=0;
经调试程序可用。频率和占空比都对。频率的设置不要太高,因为printf函数发数所需时间较多,两次捕获的时间间隔短的话可能使printf不能及时地送出数据,造成数据被刷新。更改方法,使用:USART_SendData();函数发数。
其他应用:
1.测量高电平时间:a,上文中的CCR1就是高电平时间;b,当使用一个通道CH1时,先将触发沿选为为上升沿,产生捕获中断,读取CCR1中的内容,再改变触发沿为下降沿,下降沿到来时捕获,再次读出CCR1的内容,两次相减为高电平时间。
2.测量脉冲个数:a,开启定时器1的捕获中断,捕获信号边沿(上升沿或下降沿)进中断,count++计数,再开启定时器2的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。b,开启外部中断,配置沿触发中断,count++计数,再开启定时器x的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。
3.计算一路信号的频率,可以选择定时器的CH1或CH2(不可同时计算两路频率,否则计算出的频率是后初始化的那个通道代表的信号频率。当然,要同时也可以,每次得到频率后切换通道,将数据通过DMA取走即可),使用PWM输入捕获模式,使用上升沿触发。而CH3和CH4通道则不行,如图2所示,只有红线所指的4个信号连在了从模式控制器上。所以,对于3和4通道,计数器的值不可能在接受到信号上升沿时候,有复位这个动作。