欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于STM32F767两路互补SPWM波(HAL库)

程序员文章站 2022-08-17 15:07:37
SPWM波指的是占空比呈正弦规律变化的PWM波,生成方式是在定时器中断中调整PWM波的占空比。 对于互补的两路SPWM波,一路为低电平 ‘0’ 时,另一路为高电平 ‘1’,即两路是互补的。 对于STM32F7,使用高级定时器TIM1可以方便地生成互补SPWM波。步骤如下: 1、确定载波周期 Tc,也 ......

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