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%。
具体步骤:
1、为了实现PWM输入捕获,TIM2占用了2个通道。第2通道的电平变化会被第一通道和第二通道引脚检测到,其中第一通道被设置为从机模式(如何快速判别主从机模式,规则如下:如果设置的是第二通道作为PWM输入捕获,则剩余的第一通道都为从机,反之亦然)。
2、假设输入的PWM从低电平开始跳变,在第一个上升沿到来时,1,2通道同时检测到上升沿。而从机设置为复位模式,所以将TIM2的计数值复位至0,此时不会产生一个中断请求。
3、下一个到来的电平是下降沿,此时通道1发生捕获事件,将计数值存入通道1的CCR1里。
然后是第二个上升沿到来后,此时通道2发生捕获事件,将此时的计数值存入通道2的CCR2里。复位模式此时又将TIM2计数值复位至0,等待第二个下降沿到来。
4、一次捕获过程完成,则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通道,计数器的值不可能在接受到信号上升沿时候,有复位这个动作。
|