内容发布更新时间 : 2024/12/27 7:38:57星期一 下面是文章的全部内容请认真阅读。
PWM输入捕获频率学习笔记
陈宏敏 2013-5-25
1、 PWM:脉冲宽度调制,英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用
微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。
2、 STM32的定时器除了TIM6和TIM7。其他的定时器都可以用来产生PWM输出。其中
高级定时器TIM1和TIM8可以同时产生多达7路的PWM输出。而通用定时器也能同时产生多达4路的PWM输出,这样STM32最多可以同时产生30路PWM输出!等下我用TIM2的CH2产生一路PWM输出和PWM输入。 3、 要使STM32的通用定时器TIMx产生PWM输出,我们会用到3个寄存器,来控制PWM。
这三个寄存器分别是:捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。(注意,还有个TIMx的ARR寄存器是用来控制pwm的输出频率)。首先是捕获/比较模式寄存器(TIMx_CCMR1/2),该寄存器总共有2个,TIMx _CCMR1和TIMx _CCMR2。TIMx_CCMR1控制CH1和2,而TIMx_CCMR2控制CH3和CH4。其次是捕获/比较使能寄存器(TIMx_CCER),该寄存器控制着各个输入输出通道的开关。最后是捕获/比较寄存器(TIMx_CCR1~4),该寄存器总共有4个,对应4个输通道CH1~4。4个寄存器都差不多,说的简单一点,这个寄存器就是用来设置pwm的占空比。 4、 具体看STM芯片手册。
TIMx_ARR寄存器的值怎么样来确定PWM的频率?TIM_Period(即是TIMx_ARR寄存器的值)的大小实际上表示的是需要经过TIM_Period次计数后才会发生一次更新或中断。接下来需要设置时钟预分频数TIM_Prescaler,这里有个公式,我们举例来说明:例如系统频率是72MHz,TIM_Prescaler=71,那么PWM的时钟频率是72MHz/(71+1)=1MHz。接着就是TIM_Period,定时器周期怎么计算,TIM_Period=1999,那么1MHz/(1999+1)=500Hz。这里的意思通俗点说就是1MHz时间内计数多少次,才发生一次更新或中断。比如时钟周期是1999,就是1MHz时间内计数1999+1次后就会中断一次,每计数一次需要时间是2000/1MHz。
具体看程序:
1) PWM输出设置:
//分频 预分频(时钟分频)72M/143+1=500K TIM_TimeBaseStructure.TIM_Prescaler = 143; //计数模式 向上计数
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //周期 计数值 500K/(4999+1)=100 就是说向上加到5000就满了 TIM_TimeBaseStructure.TIM_Period = 4999;
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x00; //周期计数器值 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始TIM1 /**-----设置通道 在PWM2模式下的PWM---------*/ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //PWM功能使能 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//反向通道无效
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //置高 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
/*************************** 通道3********************************/ TIM_OCInitStructure.TIM_Pulse = 500; //写比较值(占空比 TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);
/****************************** 通道4 ******************************/ /* PWM1 Mode configuration: Channel2 */ TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC4Init(TIM2, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);
TIM_ARRPreloadConfig(TIM2, ENABLE); // /* TIM3 Main Output Enable */
TIM_CtrlPWMOutputs(TIM2,ENABLE);
TIM_Cmd(TIM2, ENABLE); //使能计数
2) PWM输入捕获设置:
void PWM_IC2Init(void) {
TIM_ICInitTypeDef TIM_ICInitStructure; TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Prescaler = 2879; //时钟分频 分频数为2879+1即2880分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式 TIM_TimeBaseStructure.TIM_Period = 65535; //周期0~FFFF TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//基本初始化 TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; 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(TIM2, &TIM_ICInitStructure); //根据参数配置TIM外设信息
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); //选择IC2为始终触发源
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);//TIM从模式:触发信号的上升沿重新初始化计数器和触发寄存器的更新事件
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable); //启动定时器的被
动触发
// TIM_ICInit(TIM2, &TIM_ICInitStructure);
// TIM_ClearFlag(TIM2,TIM_FLAG_Update|TIM_IT_CC2); /* TIM enable counter */ TIM_Cmd(TIM2, ENABLE); /* Enable the CC2 Interrupt Request */ TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE); }
void TIM2_IRQHandler(void) {
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET) { /* Clear TIM3 Capture compare interrupt pending bit */ TIM_ClearITPendingBit(TIM2, TIM_IT_CC2); /* Get the Input Capture value */ IC2ReadValue1 = TIM_GetCapture2(TIM2); TIM2Freq = 50000 / IC2ReadValue1; } }
这里的5000是根据前面的PWM_IC2初始化配置来得出的。72MHz/2880=25000Hz,定时器TIM2最高是36MHz所以是50000。
PWM有采样精度的要求,TIM_GetCapture2(TIM2)的最高次数是65535,采样精度即是50000Hz/65535=0.7Hz,实际采样的值是TIM_GetCapture2(TIM2),TIM_GetCapture2、TIM_Channel_2是通道2是依次对应IO口的。这里的采样时间一定要大于PWM输出时间。采样精度的设计主要取决于TIM_Prescaler和TIM_Period的设计。
频率捕获风速代码如下:
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET) { TIM_ClearITPendingBit(TIM2, TIM_IT_CC2); Glitter; IC2ReadValue = TIM_GetCapture2(TIM2); Freq[TIM2_counter++] = 25000 / IC2ReadValue; TIM2Freq += Freq[TIM2_counter-1]; Freq[TIM2_counter-1] =0; if(TIM2_counter>=100) { TIM2Freq = TIM2Freq/100; Windspeed = ((TIM2Freq*765)+3500)/1000; TIM2_counter = 0; TIM2Freq = 0; } }
这样的采样虽然是取100次的平均值,但是其中涉及到,AD采样的时间,所以这样做的缺点就是显示比实际的要晚,比如风的频率是1Hz,则采样到值需要1s时间,到显示就需要100s,风可能已经过了!你才动作,就会有危险。 所以频率采样,只能实时显示数据。