SPWM波指的是占空比呈正弦规律变化的PWM波,生成方式是在定时器中断中调整PWM波的占空比。
对于互补的两路SPWM波,一路为低电平 ‘0’ 时,另一路为高电平 ‘1’,即两路是互补的。
对于STM32F7,使用高级定时器TIM1可以方便地生成互补SPWM波。步骤如下:
1、确定载波周期 Tc,也即是每个SPWM波的周期。对于逆变电路,常采用20kHz,也即 Tc = 50us;
2、确定基波周期 Tb,此处取50Hz,即 Tb = 20ms;
3、计算取点数N,Tb / Tc = 20ms/50us = 4000;半个周期内则为 N = 2000点;
4、计算占空比,Di = sin(i*pi / N), i = 1, 2, 3, ..., N;
5、确定最大最小占空比,例如最小占空比 Dmin = 0,最大占空比Dmax = 100%;
6、计算并修改定时器的比较值。将占空比为0%时,定时器的比较值设置为Cmin = 0;将占空比为100%时,定时器的比较值设为Cmax = 5399;则每中断一次,占空比的值设为 Cmax*Di,直接在中断里完成计算。
根据以上计算,可以修改最小占空比和最大占空比,也可以修改基波与载波频率。
以下是具体定时器配置与中断服务函数程序,基于STM32F767IGBT:
//使用高级定时器 1 完成 //Update--2019.6.3 //sin_k = TIM1_ARR / 200.0 * (float)(spwm_max_duty - spwm_min_duty ) ; //正弦波的比例系数,一个简单的数学代换 //sin_b = TIM1_ARR / 200.0 * (float)(spwm_max_duty + spwm_min_duty ) ; //正弦波的截距 #include "timer1.h" #include "led.h" #include "math.h" TIM_HandleTypeDef TIM1_Handler; //定时器句柄 TIM_OC_InitTypeDef TIM1_CH1Handler; //定时器3通道4句柄 TIM_BreakDeadTimeConfigTypeDef BreakDeadTime_Config; #define PWM_GPIO GPIOA #define PWM_PIN1 GPIO_PIN_8 #define PWM_PIN2 GPIO_PIN_7 #define TIM1_ARR 5399 //SPWM波相关计算 //sin_points -- 一个周期内中断计算的正弦点数,20KHz载波,Tc = 50us,基波周期 Tb = 50us * sin_points //Tb = 20Hz = 50ms = 50,000us, sin_points = 1000 //Tb = 100Hz = 10ms = 10,000us , sin_points = 200 //(-sin_k + sin_b ) / TIM1_ARR = spwm_min_duty % //( sin_k + sin_b ) / TIM1_ARR = spwm_max_duty %,反解出 sin_k, sin_b // sin_k = TIM1_ARR / 200.0 * (float)(spwm_max_duty - spwm_min_duty ) // sin_b = TIM1_ARR / 200.0 * (float)(spwm_max_duty + spwm_min_duty ) uint8_t spwm_min_duty = 10; //SPWM波最小占空比 uint8_t spwm_max_duty = 90; //SPWM波最大占空比 uint16_t count = 0; uint16_t sin_points = 200; uint16_t cc1_value; //比较寄存器 1的值,修改改变占空比 float sin_k,sin_b; //TIM1 PWM部分初始化 //PWM输出初始化 //arr:自动重装值 //psc:时钟预分频数 void TIM1_PWM_Init(u16 arr,u16 psc) { //时钟配置 TIM1_Handler.Instance = TIM1; //定时器3 TIM1_Handler.Init.Prescaler = psc; //定时器分频 TIM1_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式 TIM1_Handler.Init.Period=arr; //自动重装载值 TIM1_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&TIM1_Handler); //初始化PWM,会调用HAL_TIM_PWM_Init(*) //PWM配置 TIM1_CH1Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1 TIM1_CH1Handler.Pulse=arr/2; //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50% TIM1_CH1Handler.OCPolarity = TIM_OCPOLARITY_HIGH;//输出比较极性为高 TIM1_CH1Handler.OCNPolarity = TIM_OCPOLARITY_HIGH; TIM1_CH1Handler.OCIdleState = TIM_OCIDLESTATE_SET; TIM1_CH1Handler.OCNIdleState = TIM_OCIDLESTATE_SET; HAL_TIM_PWM_ConfigChannel(&TIM1_Handler,&TIM1_CH1Handler,TIM_CHANNEL_1);//配置TIM1通道1 //死区时间配置 //https://blog.csdn.net/DZRYWYBL/article/details/82527889 BreakDeadTime_Config.OffStateRunMode = TIM_OSSR_DISABLE; BreakDeadTime_Config.OffStateIDLEMode = TIM_OSSI_DISABLE; BreakDeadTime_Config.LockLevel = TIM_LOCKLEVEL_OFF; BreakDeadTime_Config.DeadTime = 0X00; //0x00~0xFF,当设置为0xFF时,50us周期,约有4.68us死区时间;0x0F约有100ns死区时间 BreakDeadTime_Config.BreakState = TIM_BREAK_DISABLE; BreakDeadTime_Config.BreakPolarity = TIM_BREAKPOLARITY_HIGH; BreakDeadTime_Config.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; HAL_TIMEx_ConfigBreakDeadTime(&TIM1_Handler, &BreakDeadTime_Config); //中断配置 HAL_NVIC_SetPriority(TIM1_CC_IRQn,1,3); //设置中断优先级,抢占优先级1,子优先级3 HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); //开启ITM3中断 //开启PWM并使能中断 HAL_TIM_PWM_Start_IT(&TIM1_Handler, TIM_CHANNEL_1); //开启PWM输出并使能中断 HAL_TIMEx_PWMN_Start(&TIM1_Handler, TIM_CHANNEL_1); //打开互补通道 } //定时器底层驱动,时钟使能,引脚配置 //此函数会被HAL_TIM_PWM_Init()调用 //htim:定时器句柄 void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_TIM1_CLK_ENABLE(); //使能定时器3 __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_Initure.Pin=PWM_PIN1 | PWM_PIN2; //PWM Pin GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推完输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速 GPIO_Initure.Alternate=GPIO_AF1_TIM1; //PA8复用为TIM1_CH1 HAL_GPIO_Init(PWM_GPIO,&GPIO_Initure); } //设置TIM通道4的占空比 //compare:比较值 void TIM_SetTIM1Compare1(u32 compare) { TIM1->CCR1=compare; } //定时器1中断服务函数 void TIM1_CC_IRQHandler(void) //注意名称与通用计时器不同,多了 CC { HAL_TIM_IRQHandler(&TIM1_Handler); } //定时器1中断服务函数调用 void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) { if(htim==(&TIM1_Handler)) { count ++; if(count == sin_points) count = 0; sin_k = TIM1_ARR / 200.0 * (float)(spwm_max_duty - spwm_min_duty ) ; //正弦波的比例系数,一个简单的数学代换//更正为相减 sin_b = TIM1_ARR / 200.0 * (float)(spwm_max_duty + spwm_min_duty ) ; //正弦波的截距//更正为相加 cc1_value = (uint16_t) (sin_k * sin( (double)count * 6.28318 / (double)sin_points) + sin_b); //正弦值计算,得到SPWM波占空比 TIM_SetTIM1Compare1(cc1_value); } }
主函数配置为
TIM1_PWM_Init(5400-1,2-1); //216M / (5400 * 2 ) = 20K