【STM32】STM32F407互补PWM进阶-带相移的互补PWM

本文详细介绍了如何在STM32F4微控制器上实现带移相的两对PWM互补输出。通过利用定时器TIM1和TIM8,以及它们的主从模式,实现了精确的相位差控制。文章提供了完整的代码示例,展示了如何配置定时器以生成具有特定相位差的PWM信号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一次尝试了STM32F4的PWM互补输出,这次尝试带移相的两对PWM互补输出。

1.相位差的概念

       在这里,我把相位简单理解为延时,当然前提是两个信号彼此之间除了相位差,其他参数都一致。如下图,两信号在一个周期内,两波峰(或波谷)的时间差,就是相位差。而习惯上用弧度方式表示,如果两信号相位差位π/2,那么就是相差1/4个周期,这个很好理解,一圈为2π,π/2当然就是1/4了。

2.思路

         互补PWM使用高级定时器TIM1和TIM8产生,均使用CH1和CH1N通道,上一篇文章有提到,这里就不再赘述。这两个定时器相互之间是独立的,我把参数配置成一样的时候,可以发现他们几乎是相同的。所以大概的思路就是在TIM1产生PWM之后,延时一会再由TIM8产生PWM,当然直接使用delay_ms()肯定是有误差的,这两个波形有可能会越差越多。

        按照这个思路,继续往下走,通过查看《STM32F4xx中文参考手册》,我们发现定时器具有主从模式,即主机产生一个触发信号(TRGO)时,从机可以响应。在这里,我们可以想象成当TIM1输出PWM,时间达到1/4个周期,产生一个触发信号,使得TIM8的PWM输出被打开。可以通过寄存器配置内部触发,从TIM8到TIM1.下面两张图展示了这一段话。

       那么怎么判断达到1/4个周期呢?想到计数器和定时器其实是一样的,能不能再用一个定时器呢?大可不必,既然定时器有那么多通道,我们干脆拿出一个通道来计时不就好了吗。于是TIM1的CH2,我们用来计时。下面是OC2的配置代码。

  // TIM1_OC2配置
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Active; // TIM1_OC2REF的模式为高电平有效
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;  // 不需要输出
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;// 不输出
  TIM_OCInitStructure.TIM_Pulse = 12500/2;                // 比较值为25000,这里四分之一就是12500/2
  TIM_OC2Init(TIM1,&TIM_OCInitStructure);  // OC2初始化
  TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_OC2Ref);  // TRGO源配置为TIM1_CH2
  TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable);   // 配置自动重载

       上面的代码已经帮我们搞定了触发信号来源,什么时候触发的问题,接下来就是把这个触发信号与TIM8相连接,并产生相应的事件。上代码:TIM1的OC2计数满之后,产生高电平给从定时器TIM8,TIM8配置为复位模式,重新输出PWM

//内部触发配置
void TIM8_IN_Config(void)
{
  TIM_SelectSlaveMode(TIM8,TIM_SlaveMode_Reset);             //从模式 复位模式
  TIM_SelectInputTrigger (TIM8,TIM_TS_ITR0);                 //触发源 TIM_TS_ITR0,从TIM8到TIM1
}

3.结果及代码

    使用双通道示波器对TIM1_CH1和TIM2_CH2测量,结果如下图所示,占空比为50%,容易看出两信号相差1/4周期,我们的目标达到,通过修改通道2的比较值TIM_OCInitStructure.TIM_Pulse,可以实现不同相位差(适用于0-180°)

附上完整代码:

//TIM1-CH1  PA8
//TIM1-CHN  PA7
//TIM1-OC2   触发源
void TIM1_PWM_Init()
{		 					 
	// 结构体声明
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
    TIM_BDTRInitTypeDef TIM_BDTRStructure;
  
	// 时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);  	//TIM3时钟使能    
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 	//使能PORTC时钟	
	
  // IO复用
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1); //
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM1); //
	
  // IO配置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7 | GPIO_Pin_8;           //GPIOC6
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
	GPIO_Init(GPIOA,&GPIO_InitStructure);              //初始化PF9
	 
    GPIO_ResetBits(GPIOA,GPIO_Pin_6);        //拉低刹车
  // 定时器配置
	TIM_TimeBaseStructure.TIM_Prescaler=168-1;  //自动重装载值1M / 25000 =40Hz
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseStructure.TIM_Period=25000-1;   //定时器分频84M/84=1M
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);//初始化定时器1
    
   // 定时器比较输出通道配置
    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; 
    TIM_OCInitStructure.TIM_Pulse=0; 	//占空比:12500/25000*100%=50%
    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;  //输出极性高
    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; //输出使能
    TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Reset; // 输出空闲电平低

   // 互补输出配置
    TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Enable; //互补输出使能
    TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_High;	// 互补端输出极性高
    TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Reset; //互补输出空闲电平低
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);  // OC1
    TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);   //配置
  
  // OC2配置
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Active; //
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;  //
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//
	TIM_OCInitStructure.TIM_Pulse = 12500/2;                //相位差90度,既1/4周期
	TIM_OC2Init(TIM1,&TIM_OCInitStructure);
	TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_OC2Ref);  //TRGO输出
    TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable);   //配置
  
  // 刹车死区配置
    TIM_BDTRStructure.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable;// 自动输出功能使能
    TIM_BDTRStructure.TIM_Break=TIM_Break_Disable;//失能刹车输入
    TIM_BDTRStructure.TIM_BreakPolarity=TIM_BreakPolarity_High; //刹车输入管脚极性高 
    TIM_BDTRStructure.TIM_DeadTime=0x01; //输出打开和关闭状态之间的延时 84-1us  168-2us 
    TIM_BDTRStructure.TIM_LOCKLevel=TIM_LOCKLevel_OFF;// 锁电平参数: 不锁任何位
    TIM_BDTRStructure.TIM_OSSIState=TIM_OSSIState_Disable; //设置在运行模式下非工作状态选项
    TIM_BDTRStructure.TIM_OSSRState=TIM_OSSRState_Disable; //设置在运行模式下非工作状态选项
    TIM_BDTRConfig(TIM1,&TIM_BDTRStructure);
  

    TIM_ARRPreloadConfig(TIM1,ENABLE);//ARPE使能 
	
	TIM_Cmd(TIM1, ENABLE);  //使能TIM3
    TIM_CtrlPWMOutputs(TIM1, ENABLE); //开启OC和OCN输出										  
}  


// 定时器8
// PA5-CH1N
// PC6-CH1
void TIM8_PWM_Init()
{		 					 
	// 结构体声明
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
    TIM_BDTRInitTypeDef TIM_BDTRStructure;
  
	// 时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE);  	//TIM3时钟使能    
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 	//使能PORTC时钟	
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); 	//使能PORTC时钟	
	
  // IO复用
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM8); //
    GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM8); //
	
  // GPIOA
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;           //GPIOC6
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
	GPIO_Init(GPIOA,&GPIO_InitStructure);              //初始化PF9
  // GPIOC
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;           //GPIOC6
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
	GPIO_Init(GPIOC,&GPIO_InitStructure);              //初始化PF9
	 
   //GPIO_ResetBits(GPIOA,GPIO_Pin_6);        //拉低刹车
  // 定时器配置
	TIM_TimeBaseStructure.TIM_Prescaler=168-1;  //自动重装载值1M / 25000 =40Hz
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseStructure.TIM_Period=25000-1;   //定时器分频84M/84=1M
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	TIM_TimeBaseInit(TIM8,&TIM_TimeBaseStructure);//初始化定时器1
    
  // 定时器比较输出通道配置
    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; 
    TIM_OCInitStructure.TIM_Pulse=0; 	//占空比:12500/25000*100%=50%
    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;  //输出极性高
    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; //输出使能
    TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Reset; // 输出空闲电平低

  // 互补输出配置
    TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Enable; //互补输出使能
    TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_High;	// 互补端输出极性高
    TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Reset; //互补输出空闲电平低
  
    TIM_OC1Init(TIM8, &TIM_OCInitStructure);  // OC1
    TIM_OC1PreloadConfig(TIM8,TIM_OCPreload_Enable);   //配置

  // 刹车死区配置
    TIM_BDTRStructure.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable;// 自动输出功能使能
    TIM_BDTRStructure.TIM_Break=TIM_Break_Disable;//失能刹车输入
    TIM_BDTRStructure.TIM_BreakPolarity=TIM_BreakPolarity_High; //刹车输入管脚极性高 
    TIM_BDTRStructure.TIM_DeadTime=0x01; //输出打开和关闭状态之间的延时 84-1us  168-2us 
    TIM_BDTRStructure.TIM_LOCKLevel=TIM_LOCKLevel_OFF;// 锁电平参数: 不锁任何位
    TIM_BDTRStructure.TIM_OSSIState=TIM_OSSIState_Disable; //设置在运行模式下非工作状态选项
    TIM_BDTRStructure.TIM_OSSRState=TIM_OSSRState_Disable; //设置在运行模式下非工作状态选项
    TIM_BDTRConfig(TIM8,&TIM_BDTRStructure);
  

   TIM_ARRPreloadConfig(TIM8,ENABLE);//ARPE使能 
	
   TIM_Cmd(TIM8, ENABLE);  //使能TIM3
   TIM_CtrlPWMOutputs(TIM8, ENABLE); //开启OC和OCN输出									  
}  



//内部触发配置
void TIM8_IN_Config(void)
{
  TIM_SelectSlaveMode(TIM8,TIM_SlaveMode_Reset);             //从模式 复位模式
  TIM_SelectInputTrigger (TIM8,TIM_TS_ITR0);                 //触发源 TIM_TS_ITR0,从TIM8到TIM1
}

//主函数
 	TIM1_PWM_Init();	//84M/84=1Mhz的计数频率,重装载值500,所以PWM频率为 1M/500=2Khz.   40  
  TIM8_PWM_Init();
  TIM8_IN_Config(); //触发配置
  TIM_SetCompare1(TIM1,12500);	//修改比较值,修改占空比
  TIM_SetCompare1(TIM8,12500);	//修改比较值,修改占空比
  while(1) 
	{

	}


 

参考文章:

1.https://blog.youkuaiyun.com/weixin_43128823/article/details/89406246

2.正点原子PWM教程

### STM32F407 生成互补 PWM 形方法 #### 配置定时器和GPIO引脚 为了在STM32F407上生成互补PWM形,首先需要配置相应的硬件资源。这包括使能所需外设的时钟以及初始化GPIO引脚。 对于TIM时钟和GPIO时钟的使能操作如下: - 使用`RCC_APB1PeriphClockCmd()`函数来开启定时器时钟。 - 利用`RCC_AHB1PeriphClockCmd()`函数启动对应GPIO端口的时钟供应[^2]。 接着要将用于输出PWM信号的GPIO引脚设定为复用功能模式,并指定合适的电气特性参数(比如推挽还是开漏),同时调整驱动能力等级以适应实际需求。 #### 定义高级定时器的工作方式 进入CubeMX图形化界面完成初步设置之后,在HAL库项目里继续深入定制高级定时器的行为特征以便支持互补PWM输出形式。主要涉及以下几个方面: - **通道极性反转**:确保两个关联通道之间存在相位差从而形成互斥关系; - **死区时间插入机制**:防止上下桥臂直通现象发生而损坏功率器件; - **同步事件管理**:协调多路PWM脉冲序列之间的相对位置保持一致[^1]。 ```c // 设置定时器工作于PWM模式并启用预装载寄存器 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, CCR1_Val); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, CCR2_Val); // 启动计数器及相应中断请求 (如果必要的话) HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_ALL); ``` 上述代码片段展示了如何向特定定时器对象写入比较值进而控制占空比大小,同时也开启了全部可用通道上的PWM输出服务。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vicssic

创作不易,感谢您的鼓励和支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值