SPWM原理及STM32生成

绪论
SPWM在单向逆变器中运用的比较多,在电能与电机控制领域现在大都是用SVPWM。先学好spwm,为以后的进阶做准备!本文主要是我学习spwm的一些理解,然后后通过实例代码生成spwm,可以直接复制测试。

一.什么是SPWM

要说SPWM先得说PWM,英文全名Pluse Width Modulation,即脉冲宽度调制,实际上就是周期的矩形波,然后每个周期的占空比都可以自己设置就叫调制。比如Buck电路中开关管的PWM波,当输入不变时可以将它的占空比从40%变到60%就能提高母线输出电压。

在这里插入图片描述
图一 .占空比固定pwm波与载波

而SPWM前面加了个S(Sine),即正弦脉宽调制,意思就是:还是这个周期的矩形波,但不同的是占空比不是如40%固定的,而是按照正弦规律变化的。
SPWM一般由三角波(载波)和正弦波(调制波)比较而成。硬件生成方法是将三角波和正弦波加入比较器得到;软件是通过定时器或者Epwm模块,按照中央计数模式生成三角波,经由CCR比较模块动作产生对应高低电平,即SPWM。

在这里插入图片描述

如图,我们将正弦函数和三角载波都归一化处理,正弦波幅值要小于三角波,这里取0.8。在一个很小的Δt时段内正弦函数值和占空比的值相等。例如图中Δt时段正弦波的值是0.8左右(A点电压值),它的矩形波占空比也是80%。同时我们可以看出矩形波的频率和三角波相等。正弦波被三角波“切割”成高频的spwm,用以控制开关管,然后spwm通过低通滤波滤除高次谐波后,得到原来的正弦波。图示情况下从0开始半个期内SPWM占空比是0->0.8->0按照正弦函数变化,要得到某时的占空比,得到此时的sine值就可以了,sine值可以事先放入表中。

二.SPWM软件生成

利用单片机输出PWM波,然后让占空比正弦规律变化。
实现步骤可以简单分为三步,以stm32为例:
(1)生成载波。比如要生成一个10KHZ的三角波,将计数器设置加减计数、周期设为1/10K就ok啦。这样生成的三角波的幅值是多少呀,3.3V?其实在单片机里面都是数字信号,三角波最高点的时候可以用一个计数值来表示,比如8400,最低点是0。不用管他的电压是多少。
(2)生成正弦波。这一步用软件生成一个正弦表即可。比如将正弦波取200个点,即将一个正弦分割成200份,每个点代表一个幅值。用离散的数字量表达正弦模拟量。
(3)将正弦波和三角波进行比较。
a.什么时候进行比较。设置计数值达到比较值产生动作。
b.比较完之后,需要改变比较值,用于下一个周期进行比较(比较值可以理解为占空比),比较值查正弦表获得,这样就生成了占空比正弦规律变化的SPWM。
C.调制度m。m=正弦表最大值/三角波最大计数值。 如正弦表最大值4200,三角波最大计数值8400,m=4200/8400=0.5,此时spwm最大占空比为50%,设置m=1,spwm最大占空比为100%。

在这里插入图片描述
在这里插入图片描述

如图所示,要注意因为是单极性调制,spwm和三角载波都是大于0的。在单相全桥逆变电路中,开关管交替导通时输出电压Ud自然会倒过来为负,Ud经过滤波就是一个正弦波。

三.实例分析

下面我们来看一个例子,来生成一个开环的三相spwm。单相逆变需生成两组相差180度的spwm,三相即生成三组两两相差120度的spwm,且每组的spwm都是互补的。

在这里插入图片描述

如图,将生成的三组spwm分别加到1、2、3组桥臂,每组spwm互补防止了同一桥臂上下管同时导通会引起短路。


uint16_t Counter_sine1 = 0;		//A相
uint16_t Counter_sine2 = 83;	//滞后A相120度
uint16_t Counter_sine3 = 166;	//超前A相120度
/**
  * 说明    	TIM1GPIO初始化  CH1--A8   CH2--A9   CH3--A10
  *                             CH1N-B13  CH2N-B14  CH3N-B15 
  *
  * 入口参数    None     	
  *          	                       
  * 出口参数  	None
**/
void TIM1_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
                                
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8 | GPIO_Pin_9| GPIO_Pin_10;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;       //复用推挽输出              
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_13| GPIO_Pin_14 | GPIO_Pin_15;  
    GPIO_Init(GPIOB, &GPIO_InitStructure);                                              	
}
 
#define CKTIM	    ((u32)72000000uL)  //主频
#define PWM_PRSC    ((u8)0)            //TIM1分频系数
#define PWM_FREQ    ((u16) 10000)      //PWM频率(Hz)
#define PWM_PERIOD  ((u16) (CKTIM / (u32)(2 * PWM_FREQ *(PWM_PRSC+1))))
#define MODULAT	    (float)0.7           //调制度
/**
  * 说明    	TIM1模式    
  *
  * 入口参数    None     	
  *          	                       
  * 出口参数  	None
**/	
void TIM1_Mode_Config(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    TIM_BDTRInitTypeDef TIM1_BDTRInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
	
    TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD;                 //计数周期
    TIM_TimeBaseStructure.TIM_Prescaler = PWM_PRSC;                //分频系数
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV2;       
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1; 
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
 
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;              //配置为PWM模式1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //使能CHx的PWM输出
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//互补输出使能,使能CHxN的PWM输出
    TIM_OCInitStructure.TIM_Pulse = 0;                          
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;   
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;   
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;  
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;  
	                                                             
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);                       //配置CH1
 
    TIM_OCInitStructure.TIM_Pulse = 0;                         
    TIM_OC2Init(TIM1, &TIM_OCInitStructure);                       //配置CH2
 
    TIM_OCInitStructure.TIM_Pulse = 0;                         
    TIM_OC3Init(TIM1, &TIM_OCInitStructure);                       //配置CH3
 
    //死区时间
    TIM1_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; 
    TIM1_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
    TIM1_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;   
    TIM1_BDTRInitStructure.TIM_DeadTime = 360;              //设置死区时间
    TIM1_BDTRInitStructure.TIM_Break = TIM_Break_Disable;	    
    TIM1_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;         
    TIM1_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;  
    TIM_BDTRConfig(TIM1, &TIM1_BDTRInitStructure);
 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	          //4个抢先级、4个子优先级	
	NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	TIM_ITConfig(TIM1,TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3,ENABLE);  //使能中断
	
    TIM_CtrlPWMOutputs(TIM1, ENABLE);                         //PWM输出使能    
    TIM_Cmd(TIM1, ENABLE);                                    //使能TIM1
}
void TIM1_PWM_Init(void)
{
    TIM1_GPIO_Config();
    TIM1_Mode_Config();
}

//定时器1中断服务函数
void TIM1_CC_IRQHandler(void) 
{	
	if(Counter_sine1>=250)
	{
		Counter_sine1 = 0;
	}
	if(Counter_sine2>=250)
	{
		Counter_sine2 = 0;
	}
	if(Counter_sine3>=250)
	{
		Counter_sine3 = 0;
	}
	
	//CCR1	
	if (TIM_GetITStatus(TIM1, TIM_IT_CC1)!=RESET)
	{
		TIM_SetCompare1(TIM1,(uint32_t)(talab[Counter_sine1])*MODULAT);	//A相	
		Counter_sine1++;
		TIM_ClearITPendingBit(TIM1 , TIM_IT_CC1);
	 }
	//CCR2
    if (TIM_GetITStatus(TIM1, TIM_IT_CC2) !=RESET)
	{
		TIM_SetCompare2(TIM1,((uint32_t)talab[Counter_sine2])*MODULAT);	//B相
		Counter_sine2++;
		TIM_ClearITPendingBit(TIM1 , TIM_IT_CC2);  	
	}
    //CCR3	
	if (TIM_GetITStatus(TIM1, TIM_IT_CC3) !=RESET)
	{
		TIM_SetCompare3(TIM1,(uint32_t)(talab[Counter_sine3])*MODULAT);	//C相
		Counter_sine3++;
		TIM_ClearITPendingBit(TIM1 , TIM_IT_CC3);  	
	}
}
int const talab[250]=
{
 100 , 102 , 108 , 116 , 126 , 140 , 154 , 172 , 194 , 216 ,
 242 , 270 , 300 , 334 , 370 , 408 , 448 , 490 , 536 , 582 ,
 632 , 684 , 738 , 794 , 854 , 914 , 976 ,1040 ,1108 ,1176 ,
1246 ,1320 ,1394 ,1470 ,1548 ,1626 ,1708 ,1790 ,1874 ,1960 ,
2046 ,2136 ,2224 ,2316 ,2408 ,2502 ,2596 ,2690 ,2786 ,2884 ,
2982 ,3080 ,3180 ,3280 ,3382 ,3482 ,3584 ,3686 ,3788 ,3892 ,
3994 ,4096 ,4200 ,4304 ,4406 ,4508 ,4612 ,4714 ,4816 ,4918 ,
5018 ,5120 ,5220 ,5320 ,5418 ,5516 ,5614 ,5710 ,5804 ,5898 ,
5992 ,6084 ,6176 ,6264 ,6354 ,6440 ,6526 ,6610 ,6692 ,6774 ,
6852 ,6930 ,7006 ,7080 ,7154 ,7224 ,7292 ,7360 ,7424 ,7486 ,
7546 ,7606 ,7662 ,7716 ,7768 ,7818 ,7864 ,7910 ,7952 ,7992 ,
8030 ,8066 ,8100 ,8130 ,8158 ,8184 ,8206 ,8228 ,8246 ,8260 ,
8274 ,8284 ,8292 ,8298 ,8300 ,8300 ,8298 ,8292 ,8284 ,8274 ,
8260 ,8246 ,8228 ,8206 ,8184 ,8158 ,8130 ,8100 ,8066 ,8030 ,
7992 ,7952 ,7910 ,7864 ,7818 ,7768 ,7716 ,7662 ,7606 ,7546 ,
7486 ,7424 ,7360 ,7292 ,7224 ,7154 ,7080 ,7006 ,6930 ,6852 ,
6774 ,6692 ,6610 ,6526 ,6440 ,6354 ,6264 ,6176 ,6084 ,5992 ,
5898 ,5804 ,5710 ,5614 ,5516 ,5418 ,5320 ,5220 ,5120 ,5018 ,
4918 ,4816 ,4714 ,4612 ,4508 ,4406 ,4304 ,4200 ,4096 ,3994 ,
3892 ,3788 ,3686 ,3584 ,3482 ,3382 ,3280 ,3180 ,3080 ,2982 ,
2884 ,2786 ,2690 ,2596 ,2502 ,2408 ,2316 ,2224 ,2136 ,2046 ,
1960 ,1874 ,1790 ,1708 ,1626 ,1548 ,1470 ,1394 ,1320 ,1246 ,
1176 ,1108 ,1040 , 976 , 914 , 854 , 794 , 738 , 684 , 632 ,
 582 , 536 , 490 , 448 , 408 , 370 , 334 , 300 , 270 , 242 ,
 216 , 194 , 172 , 154 , 140 , 126 , 116 , 108 , 102 , 100 
};	

TIM1设置为中央计数模式,开启互补通道,设置死区时间,死区时间是多少个时钟计数周期,比如TIM1计数周期是72M,设置为72就是1000ns。
spwm频率设置为10k,然后TIM1每个通道的比较值达到时更新比较值。
调制度m范围为0~1,设为0.7。
正弦调制波的频率是自己设置的,方法是f=载波频率/表中点数,这里设置的是载波频率10K,取250个点
得到的正弦频率就是40HZ,改变载波频率为50*250就得到了50hz的正弦波输出。正弦表可以用取点工具。

在这里插入图片描述
将程序下载到stm32f103单片机,PA8、PA9两个引脚输出spwm波形是相差120度的,如图。
互补通道波形相反,且有死区时间。
将以上程序加到一起就可以实现啦!

刚学习不久,有很多不足之处还请大家多多包涵和指正😊😊😊
后续持续为大家分享电力电子知识。。。

STM32 SPWM是指在STM32微控制器上实现正弦波脉宽调制(SPWM)的技术。SPWM是一种通过合成等高不等宽的PWM波来生成正弦波的方法。在STM32中,可以使用定时器和中断来实现SPWM。 在引用\[1\]中的代码示例中,使用了HAL库中的定时器中断回调函数HAL_TIM_PeriodElapsedCallback来实现SPWM。在每个定时器周期结束时,通过改变占空比来生成SPWM波形。具体的实现是使用三角波作为载波,正弦波作为调制波,通过查表法来生成SPWM波形。 在引用\[2\]中提到,SPWM原理是使用三角波作为载波,正弦波作为调制波合成等高不等宽的PWM波。在编程中,可以使用查表法来实现正弦波。这种方法相对于直接使用三角波模块与正弦波合成更为复杂,但可以减少CPU资源的占用。 在引用\[3\]中提到了两种实现SPWM的方法。一种是使用定时器的捕获/比较中断,在每个ARR周期内,当计数值大于CCR后触发中断,并在中断函数中更新CCR值来改变占空比。另一种方法是开启一个与SPWM相匹配的定时器中断,在这个中断中改变占空比来实现SPWM。 综上所述,STM32 SPWM是一种通过合成等高不等宽的PWM波来生成正弦波的技术,在STM32中可以使用定时器和中断来实现。具体的实现方法可以使用查表法来生成正弦波,并通过改变占空比来实现SPWM波形。 #### 引用[.reference_title] - *1* *2* *3* [STM32CUBEMX—查表法实现SPWM](https://blog.csdn.net/weixin_56659352/article/details/126325168)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值