zoukankan      html  css  js  c++  java
  • SVPWM-实战

    接SVPWM原理分析-基于STM32 MC SDK 5.0这篇文章,分析了基本原理和代码

    本章节讲实战操作,通过本文可以了解到程序的完整运行流程。,

    1.硬件篇,要调试首先要了解基本的硬件状态,本文调试使用的是STM32F302的主控。

    MOS管驱动部分如图1所示

       

    配置接口如下:

    PA7 ------> TIM1_CH1N

    PB0 ------> TIM1_CH2N

    PB1 ------> TIM1_CH3N

    PA8 ------> TIM1_CH1

    PA9 ------> TIM1_CH2

    PA10 ------> TIM1_CH3

       

    配置高级定时器TIM1 产生6路互补的PWM,带刹车保护,详细配置代码如下,

    把下面的程序段拷贝到main.c 中直接可以输出PWM波形(BKIN下拉),方便读者验证

    先看主程序:

     

     Volt_Components Vtest;
    
    int8_t bSector;
    
    int32_t wX, wY, wZ, wUAlpha, wUBeta;
    
    int16_t hTimePhA=0, hTimePhB=0, hTimePhC=0;
    
       
    
    int main(void)
    
    {
    
    HAL_Init();
    
    SystemClock_Config();
    
    MX_GPIO_Init();
    
    MX_TIM1_Init();
    
    Vtest.qV_Component1=-5000;
    
    Vtest.qV_Component2=-2000;
    
     
    
    while (1)
    
    {
    
    HAL_Delay(500);
    
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
    
    CALC_SVPWM( Vtest);
    
    }
    

     

     

       

    第一部分,定时器的初始化,如何判断初始化正确:

    static void MX_TIM1_Init(void)
    
    {
    
       
    
    /* USER CODE BEGIN TIM1_Init 0 */
    
       
    
    /* USER CODE END TIM1_Init 0 */
    
       
    
    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    
    TIM_OC_InitTypeDef sConfigOC = {0};
    
    TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
    
       
    
    /* USER CODE BEGIN TIM1_Init 1 */
    
       
    
    /* USER CODE END TIM1_Init 1 */
    
    htim1.Instance = TIM1;//设置频率为16k
    
    htim1.Init.Prescaler = ((TIM_CLOCK_DIVIDER) - 1);//分频系数为0
    
    htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;//TIM中央对齐模式1计数模式
    
    htim1.Init.Period = ((PWM_PERIOD_CYCLES) / 2);/*Period max 4500 设置了在下一个更新事件装入活动的自动重装载寄存器周期的值。
    
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV2;/*设置定时器时钟CK_INT频率与死区发生器以及数字滤波器采样时钟频率分频化。Val ue:*/
    
    htim1.Init.RepetitionCounter = REP_RATE;/*是否使用重复定时器,
    
    当该值不为0的时候,计数器计数值达到周期数时,该值减1,计数器重新计数,当该值减到0的时候才会产生事件。*/
    
    htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    
    if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
    
    {
    
    Error_Handler();
    
    }
    
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    
    if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
    
    {
    
    Error_Handler();
    
    }
    
    if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
    
    {
    
    Error_Handler();
    
    }
    
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC4REF;
    
    sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
    
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    
    if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
    
    {
    
    Error_Handler();
    
    }
    
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    
    sConfigOC.Pulse = 0;
    
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
    
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
    
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    
    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
    
    {
    
    Error_Handler();
    
    }
    
    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
    
    {
    
    Error_Handler();
    
    }
    
    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
    
    {
    
    Error_Handler();
    
    }
    
    sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
    
    sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
    
    sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1;
    
    sBreakDeadTimeConfig.DeadTime = DEADTIME;
    
    sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
    
    sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;
    
    sBreakDeadTimeConfig.BreakFilter = 0;
    
    sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
    
    sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_LOW;
    
    sBreakDeadTimeConfig.Break2Filter = 0;
    
    sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
    
    if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
    
    {
    
    Error_Handler();
    
    }
    
    /* USER CODE BEGIN TIM1_Init 2 */
    
       
    
    /* USER CODE END TIM1_Init 2 */
    
    HAL_TIM_MspPostInit(&htim1);
    
    HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
    
    HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1);
    
       
    
     
    
    HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
    
    HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2);
    
     
    
    HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
    
    HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3);
    
     
    
    // TIM1->CCR1=1000;//
    
    //        TIM1->CCR2=4500/2;
    
    // TIM1->CCR3=75;
    
       
    
    } 
    

     以下内容是重点,关于确认TIM定制器的配置是否ok

     HAL_TIM_MspPostInit(&htim1); //GPIO 初始化
    
    //以下是测试代码:判断GPIO的初始化是否OK,可以判断死区的设置时间是否正确
    
    HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
    
    HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1);
    
     
    
    HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
    
    HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2);
    
     
    
    HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
    
    HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3);
    
     
    
    TIM1->CCR1=1000;//
    
      TIM1->CCR2=4500/2;
    
    TIM1->CCR3=75;
       
       

    PWM输出占空比的范围测试:

    htim1.Init.Period =4500 ,频率16K,对应的周期为:62.5uS,设定死区时间1000ns=1us。约占1.6%

    占空比范围测试:

    序号

    CCRX的值

    TIM1_CH1N

    占空比大小

    TIM1_CH1N

    高电平时间

    TIM1_CH1

    占空比大小

    TIM1_CH1

    高电平时间

    备注

    1

    100

    0.64%

    0.4uS

    96.15%

    60us

      

    2

    500

    9.615%

    6us

    87.18%

    54.4us

      

    3

    1000

    21.05%

    13.2us

    76.28%

    47.6us

      

    4

    2250

    48.72%

    30.40

    48.41%

    30.4us

             

    5

    4420

    96.79%

    60.40us

    0.32%

    0.2us

      

    6

    4450

    97.12%

    (62.5-1.8)us

    0

    0

    超限制

    7

    4490

    98.08%

    (62.5-1.2)us

    0

    0

      

    8

    70

    0

    0

    96.8%

    (62.5-2)us

      

    9

    5

    0

    0

    98.4%

    (62.5-1)us

      

       

    从以上实验可知,超出4420之后TIM1_CH1N输出高电平,TIM1_CH1输出低电平

    实测在4420-4500和 0-100,存在一部分单桥臂占空比变化区间

     

       

       

       

       

       

       

    通过以上测试可以得到CCRX的值的变化范围,极其对应占空比的大小变化范围。

    结论如下:CCRX的变化为为:100-4400,对应的占空比变化范围为:0.64%~96.79%。

    如何判断死区时间是否合适?

    CH1,CH2为单片机的输出信号,CH3MOS输出信号,可以看到,时序上有明显的滞后

    滞后的主要原因在于MOS驱动电路的延时,驱动芯片采购:IRS2005驱动芯片

       

    有驱动芯片可以得到,延时时间在160ns-220ns(驱动延时)左右。实际的延时误差值在235ns(包含两部分,驱动延时和mos开启延时)

       

    通道2PWM输出,通道3位驱动芯片输出端,延时位186ns。

       

       

       

       

       

       

    CH1,CH2 MCU输出波形,CH3CH4位驱动芯片输出波形。

       

    CH1 MOS输出的波形, CH2为TIM1_CH1N,CH3为TIM1_CH1。实测占空比如下,调节TIM1_CH1的占空比其实就是调整

    MOS输出的占空比。上图是CCRX的值为100是的数据。

       

    CCRX=2500时的波形如下所示:

       

       

    CCRX=4100时的波形如下所示:

       

       

    通过以上可以看到,CCRX的值和MOS输出的波形的占空比成正比,机CCRX值越大,MOS输出的占空比越大。

       

    死区时间的本质是为了防止上下管同时导通,造成MOS烧毁,或者损耗增大, 软件设置死区时间为1000ns.

    #define DEADTIME_NS        ((uint16_t)1000) //死区时间(ns),范围:0-3500,死区时间:

       

       

    #define DEADTIME_NS        ((uint16_t)1500) //死区时间(ns),范围:0-3500,死区时间:

       

    可以看到死区时间明显改变,死区时间的大小和MOS的性能相关性比较大,一般来说推荐设置为1000ns,可以可以根据实际情况具体调整,判断的依据,就是死区时间要大于MOS管的开区和关闭时间,即CH1的波形的上升时间和下降时间。

    上升时间:100ns,下降时间100ns,选择不同 MOS参数会有差异。

       

    以上讲了这么多,主要是梳理了一下PWMMCU的引脚输出到控制MOS的输出,整个流程,同时也回答了,如何判断MOS死区时间设置是否争取的问题。整个流程供大家参考。以上提供的丰富的波形,方便大家调试才考使用。

       

    3.第三部分,回到正题,验证第一篇文章中SVPWM函数输入的Vα和Vβ到3路占空比的计算公式,是否正确。

       

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    85

    86

    87

    88

    89

    90

    91

    92

    93

    94

    95

    96

    97

    98

    99

    100

    101

    102

    103

    104

    105

    106

    107

    108

    109

    110

    /* Private macro -------------------------------------------------------------*/

    /* USER CODE BEGIN PM */

    #define SYSCLK_FREQ 72000000uL

    #define TIM_CLOCK_DIVIDER 1

    #define ADV_TIM_CLK_MHz 144

    #define ADC_CLK_MHz 12

    #define HALL_TIM_CLK 72000000uL

    #define PWM_FREQUENCY 16000

    #define SW_DEADTIME_NS 1000 /*!< Dead-time to be inserted

    by FW, only if low side

    signals are enabled */

    #define DEAD_TIME_ADV_TIM_CLK_MHz (ADV_TIM_CLK_MHz * TIM_CLOCK_DIVIDER)

       

    #define REP_RATE (1) //该参数可以调整电流环的刷新频率,刷新周期:(REP_RATE + 1)/(2*PWM_FREQ)

    #define PWM_PERIOD_CYCLES (uint16_t)(ADV_TIM_CLK_MHz*

    (unsigned long long)1000000u/((uint16_t)(PWM_FREQUENCY)))

       

    #define DEADTIME_NS        ((uint16_t)1000) //死区时间(ns),范围:0-3500,死区时间:

              

    #define DEADTIME (uint16_t)((unsigned long long)SYSCLK_FREQ/ 1*(unsigned long long)DEADTIME_NS/1000000000uL)

    /* USER CODE END PM */

    //SVPWM波形

    #define SQRT_3                1.732051 //根号3

    #define T           (PWM_PERIOD_CYCLES * 2) //TIM1 ARR值的4((PWM_PERIOD_CYCLES) / 2)

    #define T_SQRT3 (uint16_t)(T * SQRT_3)

    #define SECTOR_1        (uint32_t)1

    #define SECTOR_2        (uint32_t)2

    #define SECTOR_3        (uint32_t)3

    #define SECTOR_4        (uint32_t)4

    #define SECTOR_5        (uint32_t)5

    #define SECTOR_6        (uint32_t)6

       

    void CALC_SVPWM(Volt_Components Stat_Volt_Input)

    {

    // int8_t bSector;

    // int32_t wX, wY, wZ, wUAlpha, wUBeta;

    // int16_t hTimePhA=0, hTimePhB=0, hTimePhC=0;                

    wUAlpha = Stat_Volt_Input.qV_Component1 * T_SQRT3;

    wUBeta = -(Stat_Volt_Input.qV_Component2 * T);

    wX = wUBeta;

    wY = (wUBeta + wUAlpha)/2;

    wZ = (wUBeta - wUAlpha)/2;

    //下面是查找定子电流的扇区号

    if (wY<0)

    {

    if (wZ<0)

    {

    bSector = SECTOR_5;

    }

    else // wZ >= 0

    if (wX<=0)

    {

    bSector = SECTOR_4;

    }

    else // wX > 0

    {

    bSector = SECTOR_3;

    }

    }

    else // wY > 0

    {

    if (wZ>=0)

    {

    bSector = SECTOR_2;

    }

    else // wZ < 0

    if (wX<=0)

    {

    bSector = SECTOR_6;

    }

    else // wX > 0

    {

    bSector = SECTOR_1;

    }

    }                                                        

    switch(bSector)                 //根据所在扇区号,计算三相占空比

    {

    case SECTOR_1:

    case SECTOR_4:

    hTimePhA = (T/8) + ((((T + wX) - wZ)/2)/131072);

    hTimePhB = hTimePhA + wZ/131072;

    hTimePhC = hTimePhB - wX/131072;

    break;

    case SECTOR_2:

    case SECTOR_5:

    hTimePhA = (T/8) + ((((T + wY) - wZ)/2)/131072);

    hTimePhB = hTimePhA + wZ/131072;

    hTimePhC = hTimePhA - wY/131072;

    break;

    case SECTOR_3:

    case SECTOR_6:

    hTimePhA = (T/8) + ((((T - wX) + wY)/2)/131072);

    hTimePhC = hTimePhA - wY/131072;

    hTimePhB = hTimePhC + wX/131072;

    break;

    default:

    break;

    }

    TIM1->CCR1 = hTimePhA;

    TIM1->CCR2 = hTimePhB;

    TIM1->CCR3 = hTimePhC;

    }

       

     

    代码分析可以,Vtest.qV_Component1即为Vα Vtest.qV_Component2即为Vβ,下文直接用Vα ,Vβ表示

    Vα ,Vβ值的变化范围为:-32767~+32767。可以根据上表的数据大小范围,推算出不用扇区并计算出对应的hTimePhA,hTimePhB和hTimePhC的值。

    注意Vα,(未转换)的值模值不可超过32767,超出范围的电压矢量不可以生成。当控制矢量在空间旋转 360°后,逆变器就能输出一个周期的正弦波电压。

       

    扇区

    hTimePhA

    hTimePhB

    hTimePhC

    V1

    V2

    V3

    A占空比

    C占空比

    D占空比

    备注

    I

    1000

    -1000

    2343

    2293

    2156

    12.37

    11.95

    11.03

    51.92%

    51.04%

    47.92%

    占空比1>2>3

    I

    20000

    -5000

    3600

    1576

    890

    19.28

    8.421

    4.755

    80.13%

    35.14%

    19.81%

    21

    II

    2000

    -5000

    2487

    2593

    1906

    13.16

    13.63

    9.66

    55.13%

    57.51%

    42.31%

    占空比2>1>3

    Ii

    2000

    -20000

    2487

    3622

    876

    12.97

    19.24

    4.093

    55.13%

    80.51%

    19.55%

    22

    III

    -2000

    -2000

    2063

    2473

    2163

    10.59

    12.52

    11.32

    45.69%

    53.99%

    48.08%

    占空比2>3>1

    III

    -30000

    -2000

    398

    4102

    3828

    2.384

    21.95

    20.73

    8.654%

    91.05%

    85.26%

    23

    IV

    -2000

    2000

    2063

    2163

    2437

    10.59

    10.98

    12.86

    45.69

    48.08

    53.99

    占空比3>2>1

    IV

    -20000

    5000

    890

    2925

    3611

    5.118

    15.43

    19.18

    19.55

    65.96

    80.19

    24

    V

    -2000

    5000

    2013

    1908

    2594

    10.36

    9.753

    13.65

    44.55

    42.49

    57.69

    占空比3>1>2

    V

    -2000

    30000

    2013

    191

    4310

    10.37

    1.062

    23.14

    44.55

    4.167

    95.83

    25

    VI

    2000

    3000

    2471

    2029

    2440

    13.00

    10.43

    12.79

    54.81

    45.05

    54.17

    占空比1>3>2

    VI

    20000

    3000

    3542

    959

    1370

    18.94

    5.201

    7.017

    78.59

    21.41

    30.45

    Tu 26

      

      

      

      

      

      

      

      

      

      

      

      

      

       

       

    hTimePhx=4500X占空比。

       

     21

       

       

    图22

       

       

       

     图23

     

     图24

     

     

     图25

     

     

     图26

       

      

    这样理论分析就和实际的计算统一了,扇区也对上了。总结如下所示

       

       

       

       

     

    4.通过以上3个部分,完成了Vα到Vβ的每个转换过程的分析,通过实战了解每个过程的变化。存在问题,欢迎大家指正

       

       

       

  • 相关阅读:
    教你轻松搞定javascript中的正则
    带你学习javascript的函数进阶(二)
    带你学习Javascript中的函数进阶(一)
    带你学习ES5中新增的方法
    作为前端,你需要懂得javascript实现继承的方法
    作为前端,你需要了解的js构造函数和原型
    ES6学习笔记(三):教你用js面向对象思维来实现 tab栏增删改查功能
    企业级zabbix监控搭建及邮件报警
    -bash: netstat: 未找到命令
    shell点名脚本不重复人名
  • 原文地址:https://www.cnblogs.com/temo/p/14017898.html
Copyright © 2011-2022 走看看