这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取手持数字示波器】+与同事对定时器输出相位可调PWM移相全桥控制分享

共8条 1/1 1 跳转至

【换取手持数字示波器】+与同事对定时器输出相位可调PWM移相全桥控制分享

工程师
2024-03-24 23:23:55   被打赏 50 分(兑奖)     打赏

STM32F1定时器输出两路相位可调PWM(可用于移相全桥控制或硬开关逆变全桥)引言

假设要驱动一个H桥(如下图所示)实现DC/AC的变换。

image.png



先把原理说一下:

基于您所描述的要求,我们需要设计两组开关(S1和S4,S2和S3)的驱动信号,以确保它们能够交替导通,同时避免桥臂上的开关管直通。以下是重新生成的驱动信号的设计要点:

设计要点:

  1. 相位互补:两组开关管(S1和S4,S2和S3)的驱动信号必须保持180°的相位差,即互补关系。当S1和S4导通时,S2和S3必须关断;反之亦然。

  2. PWM占空比相同:为了保持桥臂开关的对称性,两组开关的PWM占空比应该相同。这意味着在一个完整的PWM周期内,S1和S4导通的时间应该等于S2和S3导通的时间。

  3. 死区时间:为了避免开关管直通,需要在每组开关管交替导通时插入死区时间。这个死区时间应该足够长,以确保在从一个开关组切换到另一个开关组时,前一个开关组已经完全关断,而后一个开关组才开始导通。在这个例子中,我们假设死区时间为PWM周期的10%。

驱动信号实现

在实际应用中,驱动信号通常由微控制器(如MCU或DSP)通过PWM发生器产生。为了实现上述要求,可以配置两个互补的PWM通道,每个通道控制一组开关管。此外,还需要在PWM信号的切换点加入死区时间。

具体实现步骤可能包括:

  • 配置PWM发生器的占空比,确保两组开关的占空比相同。

  • 设置PWM通道的相位关系,使两组开关的驱动信号相位互补。

  • 在PWM信号的切换点插入死区时间,确保开关管不会直通。

注意事项

  • 死区时间的长度需要根据实际应用中开关管的特性以及系统的需求来确定。过长的死区时间可能会导致输出电压的失真,而过短的死区时间则可能无法有效防止直通。

  • 在设计驱动电路时,还需要考虑开关管的驱动能力和开关速度,以确保驱动信号能够有效地控制开关管的导通和关断。

通过上述设计要点和实现步骤,可以生成满足要求的驱动信号,确保开关管组1(S1和S4)和开关管组2(S2和S3)能够交替导通,并避免桥臂上的开关管直通。


通过查阅数据手册,可采用两个定时器同步的模式(定时器级联)来进行驱动,采用主从模式进行控制。具体实现为主定时器TIM1输出两路PWM信号,其中通道1(CH1)用作管子驱动,通道2(CH2)设定比较值为周期的一半(实现主定时器TIM1通道1和从定时器TIM2通道1的固定相位差),配置MMS寄存器为100,将其比较有效信号OC2REF设定为主定时器TIM1输出,用于触发从定时器TIM2进行复位。定时器TIM2设置为从模式(SMS)复位模式(100),将触发信号TS设置为内部触发ITRx(具体实施需对照数据手册,定时器主从对照表)


主从定时器控制结构示意图

image.png

寄存器描述


image.png


程序示例

具体程序实现,实验平台为STM32F103ZE,用到TIM2做主定时器CH4为触发信号输出通道,TIM1做从定时器复位模式。

void TIM1_PWM_Init(void)  
{  
	GPIO_InitTypeDef GPIO_InitStructure;  
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
	TIM_OCInitTypeDef TIM_OCInitStructure;  
  
	// 使能TIM1定时器时钟  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);  
	// 使能GPIOE端口和AFIO复用功能时钟  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE);  
  
	// 定时器TIM1的部分引脚重映射,可能是为了改变PWM波形的输出引脚  
	GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE);  
  
	// 初始化GPIOE端口的两个引脚(PE11和PE10),作为TIM1的PWM输出  
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10; // 设置要初始化的引脚  
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 设置为复用推挽输出模式  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置GPIO的输出速度为50MHz  
	GPIO_Init(GPIOE, &GPIO_InitStructure); // 初始化GPIOE端口  
  
	// 初始化TIM1定时器的时间基准  
	TIM_TimeBaseStructure.TIM_Period = 899; // 设置自动重装载寄存器的值  
	TIM_TimeBaseStructure.TIM_Prescaler = 0; // 设置预分频值(这里减一可能是一个错误,应该是直接赋值)  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 设置时钟分割  
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置定时器向上计数模式  
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // 初始化TIM1的时间基准  
  
	// 初始化TIM1的通道2为PWM模式  
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置PWM模式  
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能PWM输出  
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; // 设置PWM输出极性为低电平有效  
	TIM_OCInitStructure.TIM_Pulse = 899 / 2; // 设置PWM脉冲宽度  
  
	// 以下三个字段可能用于互补PWM输出配置,但在单通道PWM输出中不需要  
	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;  
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;  
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;  
  
	// 初始化TIM1的通道2  
	TIM_OC2Init(TIM1, &TIM_OCInitStructure);  
  
	// 选择TIM1的触发源和从模式,但在PWM输出配置中可能不需要  
	TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);  
	TIM_SelectInputTrigger(TIM1, TIM_TS_ITR1);  
  
	// 使能TIM1的自动重装载寄存器预装载功能  
	TIM_ARRPreloadConfig(TIM1, ENABLE);  
	// 使能TIM1的通道2的预装载寄存器  
	TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);  
  
	// 设置TIM1的通道2的比较值为0,即初始PWM输出占空比为0  
	TIM_SetCompare2(TIM1, 0);  
  
	// 开启TIM1的PWM输出  
	TIM_CtrlPWMOutputs(TIM1, ENABLE);  
  
	// 使能TIM1定时器  
	TIM_Cmd(TIM1, ENABLE);  
}  

void TIM2_PWM_Init(void)  
{  
	GPIO_InitTypeDef GPIO_InitStructure;  
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
	TIM_OCInitTypeDef TIM_OCInitStructure;  
  
	// 使能TIM2定时器的时钟  
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  
	// 使能GPIOB端口的时钟以及AFIO复用功能模块时钟  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);  
  
	// 定时器TIM2的部分引脚重映射  
	GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);  
  
	// 初始化GPIOB端口的两个引脚为复用推挽输出,用于TIM2的PWM输出  
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;  
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
	GPIO_Init(GPIOB, &GPIO_InitStructure);  
  
	// 初始化TIM2定时器的时间基准  
	TIM_TimeBaseStructure.TIM_Period = 899; // 设置自动重装载寄存器的值  
	TIM_TimeBaseStructure.TIM_Prescaler = 0; // 设置预分频值(这里减一可能是个错误,应该直接赋值)  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 设置时钟分割  
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置定时器向上计数模式  
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  
  
	// 初始化TIM2的通道3为PWM模式  
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 选择PWM模式  
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能PWM输出  
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 设置PWM输出极性为高电平有效  
	TIM_OCInitStructure.TIM_Pulse = 899 / 2; // 设置PWM脉冲宽度  
	TIM_OC3Init(TIM2, &TIM_OCInitStructure); // 初始化TIM2的通道3  
  
	// 初始化TIM2的通道4为PWM模式(此代码块与通道3初始化相似,可能需要确认是否确实需要两个通道)  
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;  
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  
	TIM_OCInitStructure.TIM_Pulse = 899 / 2;  
	TIM_OC4Init(TIM2, &TIM_OCInitStructure);  
  
	// 使能TIM2的主从模式  
	TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);  
	// 设置TIM2的输出触发源为通道4的比较输出  
	TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_OC4Ref);  
  
	// 使能TIM2的通道3和通道4的预装载寄存器  
	TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);  
	TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);  
  
	// 设置TIM2的通道3的比较值为0,即初始PWM输出占空比为0  
	TIM_SetCompare3(TIM2, 0);  
	// 设置TIM2的通道4的比较值(如果需要的话,此处同样需要设置)  
	// TIM_SetCompare4(TIM2, 0);  
  
	// 使能TIM2定时器  
	TIM_Cmd(TIM2, ENABLE);  
} 
  
// 注释说明:  
// 这是一个初始化TIM1定时器以产生PWM波形的函数。函数通过配置GPIO端口、TIM1定时器的时间基准和PWM模式通道来初始化TIM1,并使其产生PWM波形。  
// 函数中使用了STM32的标准外设库函数来配置相关硬件。  
// 需要注意的是,预分频值`TIM_Prescaler`被错误地设置为`1 - 1`,这可能是一个笔误,应该直接设置为需要的预分频值(如0表示不分频)。  
// 此外,函数中还包含了互补PWM输出的一些配置字段,但在单通道PWM输出配置中并不需要这些字段,它们可以被移除或注释掉。  
// 最后,函数通过调用`TIM_Cmd(TIM1, ENABLE)`来启动TIM1定时器。

主代码:
int main(void)
{
	TIM1_PWM_Init();
	TIM2_PWM_Init();
	TIM_SetCompare2(TIM1, 100);
	TIM_SetCompare3(TIM2, 100);
	while (1)
	{
		TIM_Cmd(TIM1, DISABLE);
		TIM_Cmd(TIM2, DISABLE);
		delay_ms(1);
		TIM_Cmd(TIM1, ENABLE);
		TIM_Cmd(TIM2, ENABLE);
		delay_ms(1);
	}
}

用到keil内置的逻辑分析工具,将TIM对应引脚添加为输入,设定为BIT模式。

image.png


定时器2通道3和4相位相差180°,且在定时器2通道4变为高电平的同时定时器1通道也变为高电平,实现了两个定时器的同步。

image.png

为了实现定时器TIM2的通道3(CH3)和通道4(CH4)输出相位相差180°,并且使TIM2的通道4变为高电平的同时TIM1的某个通道也变为高电平,我们需要重新配置这两个定时器的PWM输出以及它们之间的同步关系。下面是一个简化的示例,它展示了如何配置TIM2以产生相位相差180°的PWM信号,以及如何实现TIM2和TIM1的同步。

1、主定时器配置的时候,为实现相位移动,需要将使用的两个通道配成不同的PWM模式,上面给出的程序示例中一个是PWM1,另一个是PWM2。
2、可以通过修改TIM2 CH4 的比较值CRR来实现两路PWM相位的改变,可用于控制移相全桥。


专家
2024-03-25 06:33:23     打赏
2楼

这说得比较清楚


专家
2024-03-27 07:39:30     打赏
3楼

谢谢分享


高工
2024-03-27 21:03:08     打赏
4楼

这还使用STM32F103芯片做项目开发啊!


工程师
2024-03-28 14:20:19     打赏
5楼

学习了


工程师
2024-04-02 09:12:46     打赏
6楼

学习了。谢谢分享。


菜鸟
2024-04-24 14:26:08     打赏
7楼

看懂的都是牛人


高工
2024-11-19 20:25:15     打赏
8楼

KEIL就是好


共8条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]