谷动谷力

标题: 【产品方案】基于CW32的无刷直流空心杯电机无感方波控制... [打印本页]

作者: sunsili    时间: 2024-4-17 21:26
标题: 【产品方案】基于CW32的无刷直流空心杯电机无感方波控制...
【产品方案】基于CW32的无刷直流空心杯电机无感方波控制驱动方案


方案概述

本方案采用CW32F030C8T6作为主控芯片,采用无感方波控制算法控制无刷直流空心杯电机。CW32F030C8T6是一款高性能、低功耗的32位微控制器,具有丰富的片上外设资源,可以适合用于电机控制。无感方波控制算法是一种简单有效的电机控制算法,不需要使用霍尔传感器,可以降低硬件成本。本次采用的电机驱动板仍然为CW32_BLDC_EVA V5开发板,具体开发板的信息可以翻看上一节《基于CW32的无刷空心杯电机有感控制驱动方案》,采用的空心杯电机与上一节有所不同,这次使用的空心杯电机的额定电压为 24 V。由于本次采用无感方案,所以只需要将 U、V、W三相电源接上即可,并且三相的顺序并无强制要求,下面我们重心将放在对于无感方波控制的原理部分。

无感方波控制原理

无感方波控制(Sensorless Square Wave Control)是一种用于无刷直流电机(BLDC)驱动的控制方法。与传统的有感控制方法相比,无感方波控制不需要使用位置或速度传感器来反馈电机状态,而是通过检测电机自身的悬空相反电动势变化(Back Electromotive Force,简称BEMF)来实现控制。在无感方波控制中,通过检测电机的悬空相电压的过零点,可以推断出电机转子的位置,根据转子位置进行步状态的切换即可控制电机转动。
2.1 梯形波

无感方波的驱动电路采用三相全桥逆变电路,在理想的情况下,三相全桥逆变电路的电压波形如下图2-1所示,每相导通角度为120°,相与相之间相隔120°。 无刷直流电机驱动所需的电流波形也是上图里的方波,因为电机存在漏感 L ,定子电流会有一定的上升和下降时间,所以使得理想的方波变成了梯形波。
从图2-2中可以看出,无刷直流电机实际运行时的三相电压波形并不是图2-1里的方波,而是梯形波。由于采用了脉宽调制计数(PWM),所以波形看上去由一道道脉冲组成。

2.2 确定换相信号

无感方波驱动与有感最大的区别就在于获取换相信号的方式不同,有感方波通过检测三相霍尔信号的电平,再根据三相电平确定电机此时应该运行在的步状态;无感方波是检测梯形波“斜线”上的反电动势电压来确定换相时刻。霍尔信号对应的相是确定的,所以电机的供电相也要根据霍尔相的顺序来连接,而无感方波驱动只需要检测“斜线”上的“过零点”确定换相时刻后自动换相到下一步状态,而每一个步状态对应事先已经安排好的开关管通断,所以电机的供电相可以随意连接。 PA0、PA1、PA5分别对应CW32F030 ADC的0、1、5通道,我们使用ADC采集三相的电压,但在“过零点”比较中我们实际使用的是未导通相,即悬空相的电压。

2.3电机驱动思路



软件设计

3.1MCU资源分配

本次使用到的CW32内部资源如下:
3.2 部分重要程序介绍

操作 ATIM CH4 的 CCR 寄存器,可以选择 ADC 在一个 PWM 周期内不同位置的采样:
  1. CW_ATIM->CH4CCR=(数字);
复制代码

首先是核心函数:调制换相
  1. /*step,为当前换相序号,PWM_ON_flag=1时启动PWM输出
  2. **Step_Last,记录上一次步状态用于 PWM 占空比的刷新
  3. **Step_Time,记录上一次换相时间
  4. **Flag_Start_OK,判断电机是否启动成功
  5. **Flag_Demagnetize_State,判断退磁状态,1:需要退磁;2:退磁完成;3:检测到过零点,可以换相
  6. **HALLcount,记录换相次数用于转速计算
  7. */
  8. void Commutation(uint32_t step,uint32_t PWM_ON_flag)
  9. {
  10.   if(PWM_ON_flag==0) //不启动则关闭输出
  11.   {
  12.     CW_ATIM->CH1CCRA=0;CW_ATIM->CH2CCRA=0;CW_ATIM->CH3CCRA=0;        
  13.     PWM_AL_OFF; PWM_BL_OFF;PWM_CL_OFF;
  14.     CW_ATIM->CH4CCR=PWM_TS-800;                                       
  15.     return;
  16.   }                        
  17.   //关闭下管           
  18.        if(step==0||step==5){PWM_AL_OFF;PWM_CL_OFF;}
  19.   else if(step==1||step==2){PWM_AL_OFF;PWM_BL_OFF;}
  20.   else if(step==3||step==4){PWM_BL_OFF;PWM_CL_OFF;}
  21.   //打开上管               
  22.   if(step==0||step==1){CW_ATIM->CH2CCRA=0;CW_ATIM->CH3CCRA=0;CW_ATIM->CH1CCRA=OutPwm;}
  23.   if(step==2||step==3){CW_ATIM->CH1CCRA=0;CW_ATIM->CH3CCRA=0;CW_ATIM->CH2CCRA=OutPwm;}
  24.   if(step==4||step==5){CW_ATIM->CH1CCRA=0;CW_ATIM->CH2CCRA=0;CW_ATIM->CH3CCRA=OutPwm;}
  25.   //打开下管                           
  26.   if(step==0||step==5){PWM_BL_ON;}//AB
  27.   else if(step==1||step==2){PWM_CL_ON;}//AC
  28.   else if(step==3||step==4){PWM_AL_ON;}//BA

  29.   Step_Last=step;
  30.   //判断占空比修改采样时刻      
  31.   if(OutPwm>=1200&&Flag_ON_or_OFF==0){Flag_ON_or_OFF=1;CW_ATIM->CH4CCR=300;}        
  32.   else  if(OutPwm<1200&&Flag_ON_or_OFF==1){Flag_ON_or_OFF=0;CW_ATIM->CH4CCR=PWM_TS-600;        }
  33.   //记录上一次的换相时间                  
  34.   Step_Time=BTIM_GetCounter(CW_BTIM2);
  35.   BTIM_SetCounter(CW_BTIM2,0);
  36.   //电机未启动则快速换相               
  37.   if(Flag_Start_OK==0)
  38.   BTIM_SetAutoreload(CW_BTIM3,Step_Time/8);        
  39.   else
  40.   BTIM_SetAutoreload(CW_BTIM3,Step_Time/6);//退磁延迟时间

  41.   BTIM_SetCounter(CW_BTIM3,0);
  42.   BTIM_Cmd(CW_BTIM3, ENABLE);
  43.   //启动退磁
  44.   Flag_Demagnetize_State=1;//退磁状态

  45.   HALLcount++;                  
  46. }
复制代码

接着是第二个核心:换相。
  1. /*Direction,电机运行方向,0:步状态012345,1:步状态054321
  2. **Cur_Step,电机目前的步状态,步状态正常运行顺序为 012345、543210。0:AB、1:AC ……
  3. */
  4. void BTIM3_IRQHandler(void)
  5. {
  6.   if(BTIM_GetITStatus(CW_BTIM3, BTIM_IT_OV))
  7.   {  
  8.     BTIM_ClearITPendingBit(CW_BTIM3, BTIM_IT_OV);

  9.     if(Flag_Demagnetize_State == 1)  //说明退磁结束后第一次进入BTIM3中断
  10.     {
  11.       Flag_Demagnetize_State = 2;    //退磁结束标志
  12.       BTIM_Cmd(CW_BTIM3, DISABLE);
  13.     }
  14.     else if(Flag_Demagnetize_State == 3 && Flag_Start_OK == 1) //退磁完成和启动成功后,决定下一次换相
  15.     {
  16.       BTIM_Cmd(CW_BTIM3, DISABLE);

  17.       if(Direction == 0)          //与RisingFalling的顺序要对应
  18.       {
  19.         Cur_Step++;
  20.         if(Cur_Step == 6)Cur_Step = 0;
  21.       }
  22.       else
  23.       {
  24.         if(Cur_Step == 0)Cur_Step = 5;
  25.         else Cur_Step--;
  26.       }
  27.       Commutation(Cur_Step,Motor_Start_F);
  28.     }
  29.   }
  30. }
复制代码

过零点比较函数如下,此函数在 ADC 完成五次采样后调用。
  1. /*SampleData[5] U反电动势 V反电动势 母线电压 W反电动势 电位器调速电压值
  2. **TAB_BEMFChannel[6]={3,1,0,3,1,0};
  3. **TAB_RisingFalling[2][6]={//判断此刻电压为上升沿还是下降沿,Rising=1;Falling=2
  4.   {FALLING,RISING,FALLING,RISING,FALLING,RISING},
  5.   {RISING,FALLING,RISING,FALLING,RISING,FALLING} }
  6. **Flag_ON_or_OFF,高低电平采样标志位
  7. **RisingFalling,上升沿下降沿比较标志位  
  8. **Count_0V,过零点检测计数  STCount = 15
  9. **Flag_Confirm,启动确认标志位  
  10. */
  11. void ADC_Process(void)
  12. {
  13.   static uint8_t count = 0;  //过零检测计数
  14.   uint32_t Voltage_Bus = 0;  //母线电压
  15.   uint8_t Flag_0V = 0;       //成功检测到过零点标志

  16.   if(Flag_Demagnetize_State != 2)return; //说明退磁未结束

  17.   BEMFConvertedValue =SampleData[TAB_BEMFChannel[Cur_Step]];  //取得反电动势
  18.   RisingFalling=TAB_RisingFalling[Direction][Cur_Step];       //判断上升沿还是下降沿

  19.   if(Flag_ON_or_OFF == 0)Voltage_Bus = 50;   //在PWM低电平时采样则与地比较电压              
  20.   else Voltage_Bus = SampleData[2];          //在PWM高电平时采样则与电源正极比较电压

  21.   if(RisingFalling == FALLING)
  22.   {
  23.     if(BEMFConvertedValue < Voltage_Bus)
  24.     {
  25.       count++;
  26.       if(count >= 2)                        //连续两次都检测到过零,则认为确实过零了
  27.       {
  28.         count = 0;
  29.         Flag_Demagnetize_State = 3;        //退磁完成,可以换相

  30.         Count_0V++;
  31.         Flag_Confirm = 1;
  32.         Flag_0V = 1;                      //成功检测到过零点
  33.       }
  34.     }
  35.     else count = 0;
  36.   }
  37.   else if(RisingFalling == RISING)
  38.   {
  39.     if(BEMFConvertedValue > Voltage_Bus)
  40.     {
  41.       count++;
  42.       if(count >= 2)
  43.       {
  44.         count = 0;
  45.         Flag_Demagnetize_State = 3;

  46.         Count_0V++;
  47.         Flag_Confirm = 1;
  48.         Flag_0V = 1;
  49.       }
  50.     }
  51.     else count = 0;
  52.   }

  53.   if(Count_0V >= STCount && Flag_Start_OK == 0)   
  54.   {  
  55.     Flag_Start_OK = 1;    //连续检测到固定数量的过零时,认为启动成功
  56.   }        

  57.   if(Flag_Start_OK == 1 && Flag_0V == 1)
  58.   {
  59.     Flag_0V = 0;

  60.     BTIM_SetAutoreload(CW_BTIM3,Step_Time/8); //换相延迟时间                        
  61.     BTIM_SetCounter(CW_BTIM3,0);
  62.     BTIM_Cmd(CW_BTIM3, ENABLE);
  63.   }  
  64. }
复制代码

最后是电机的启动部分:
  1. /*TimeCountTemp,计时,1ms增加1
  2. **Com_time,     启动次数
  3. **RAMP_TABLE[64],存储时间的数组
  4. */
  5. do
  6.   {                                                
  7.     if(Direction == 0)               //与RisingFalling的顺序要对应
  8.     {
  9.       Cur_Step++;
  10.       if(Cur_Step >= 6)Cur_Step = 0; //以复位时的步状态为基准,手动换步
  11.     }
  12.     else
  13.     {
  14.       if(Cur_Step == 0)Cur_Step = 5;
  15.       else Cur_Step--;
  16.     }

  17.     Flag_Confirm = 0;
  18.     if(Flag_Start_OK == 0)        
  19.     {
  20.       Commutation(Cur_Step,Motor_Start_F);
  21.     }  
  22.     TimeCountTemp = 0;
  23.     while(TimeCountTemp < RAMP_TABLE[Com_time]) //等待过零点检测
  24.     {
  25.       if(Flag_Confirm == 1 || Flag_Start_OK == 1)break;  //启动成功则不再执行do.....while里的内容
  26.     }

  27.     Com_time++;
  28.     OutPwm+=10;  //没有启动则依次提高占空比
  29.   }while(Flag_Start_OK==0 && Com_time<60 && ErrorCode==0);  
  30.   //跳出循环则 启动成功/超出启动次数/启动报错
复制代码

调试心得










欢迎光临 谷动谷力 (http://bbs.sunsili.com/) Powered by Discuz! X3.2