之前有写过怎么使用定时器生成PWM波,以及怎么修改频率与占空比,具体大家可以看下面这篇
stm32f4 生成PWM波_居安士的博客-CSDN博客_stm32产生pwm波
STM32每一个定时器都有4路通道,但是通常一个TIM输出的频率是固定了,使用一个定时器通常只能输出同频率不同占空比的PWM波。
但是由于IO口的选择,如果不使用同一个TIM,就需要启用高级定时器(TIM1和TIM8),最后我们尝试先用同一个TIM生成多个不同频率和占空比的PWM波,几经波折,找到了解决方法!
下面我使用的是TIM3的3通道和4通道,对应着PB0和PB1,大家对照着自己的IO口和TIM修改下面我注释的地方:
#include "sys.h"
#include "osa.h"
//OSA clk : PB0 TIM3_CH3
//OSA Reset£ºPB1 TIM3_CH4
uint16_t CCR3_Val1 = 200;//修改
uint16_t CCR3_Val2 = 200;
uint16_t CCR4_Val1 = 800;//修改
uint16_t CCR4_Val2 = 1600;
void OSA_clk_init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
修改
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource0,GPIO_AF_TIM3); //修改
GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM3); //修改
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //修改
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler =1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* Output Compare Toggle Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR3_Val1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable);
/* Output Compare Toggle Mode configuration: Channel3 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR4_Val1;
TIM_OC4Init(TIM3, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Disable);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* TIM enable counter */
/* TIM IT enable */
TIM_ITConfig(TIM3,TIM_IT_CC3| TIM_IT_CC4, ENABLE);//修改
/* Enable the TIM3 global Interrupt */
TIM_Cmd(TIM3, ENABLE);
}
_Bool CH3_Flag = 0;
_Bool CH4_Flag = 0;
void TIM3_IRQHandler(void)
{
uint16_t capture1 = 0;
uint16_t capture2 = 0;
/* TIM3_CH2 toggling with frequency = 732.4 Hz */
if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);
capture1 = TIM_GetCapture3(TIM3);
if(CH3_Flag == 0)
{
TIM_SetCompare3(TIM3, capture1 + (uint16_t)CCR3_Val2);
CH3_Flag = 1;
}
else
{
TIM_SetCompare3(TIM3, capture1 + (uint16_t)CCR3_Val1);
CH3_Flag = 0;
}
}
/* TIM3_CH3 toggling with frequency = 1464.8 Hz */
if (TIM_GetITStatus(TIM3, TIM_IT_CC4) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);
capture2 = TIM_GetCapture4(TIM3);
if(CH4_Flag == 0)
{
TIM_SetCompare4(TIM3, capture2 + (uint16_t)CCR4_Val2);
CH4_Flag = 1;
}
else
{
TIM_SetCompare4(TIM3, capture2 + (uint16_t)CCR4_Val1);
CH4_Flag = 0;
}
}
}
修改完IO口和TIM,我们只需要动下面这个地方,即修改CCR的值
最终,频率=主频/分频/(CCR1+CCR2)
占空比=CCR1/(CCR1_CCR2)
我们可以按照自己的需要,设置CCR1和CCR2的值
普通定时器主频/分频=84;高级定时器主频/分频=168
举个例子:普通定时器CCR1=CCR2=84,那么频率就是 84/(84+84)=0.5M,占空比=0.5
但是在实验的时候,我们发现,这个代码只能输出低于0.1M频率的PWM波(或许还不够完善?),如果大家需要生成高于这个频率的PWM波,只能选择使用高级定时器(TIM1和TIM8),很不幸,我的项目需要频率高于0.1M,也需要使用高级定时器。。。但是也不算白弄,分享给可以使用的朋友!