BLDC电机原理以及开发板电机驱动能力评测(含工程源码)

原创 面包板社区 2022-01-21 20:00

前段时间公务繁忙,收到的MM32SPIN160C开发板也无暇顾及,趁周末时间,来体验一下这款开发板的电机驱动能力。


一、硬件方面:
板卡为专用电机驱动板,因此底板加了一块散热片,开发板的四脚加了脚垫,以便更好地散热,防止底板电路与金属物件接触而导致短路。开发板采用ARM Cortex-M0的32位MCU,MCU最高工作频率可达72MHz,内置高速存储器,丰富的I/O 端口和外设连接到外部总线。具有1个12位的ADC、1个比较器、1个16位通用定时器、1个32位通用定时器、3个16位基本定时器和1个16位高级定时器。还包含标准的通信接口,即1个I2C接口、1个SPI接口和1个UART接口。适合开发吊风扇,电动工具,三相永磁无刷电机等多种应用场合。
       由MM32SPIN160C的名称可知该型号的基础配置

       开发板主要功能列表:
①、输入电压范围: 12V~28V
②、使用60V/40A N-MOS管*6
③、使用外挂(SPIN0x) GBW 6MHz 高速运放*4
④、MCU 电源使用5V
⑤、支持有/无霍, 方波/弦波驱动
⑥、支持1/2 Shunt R 三相电流采样
⑦、BEMF 电压回授使用ADC 采样
⑧、DC Bus 电压, 总电流量测
⑨、使用MCU 内建比较器做为过电流保护
       在淘宝上买了个尼得科无刷电机,无刷电机最大优点是没有碳刷转换器,寿命长,适合长时间工作的场所。
      【额定电压】DC 12V
      【空载电流】1A
      【额定功率】10W
      【空载转速】12000转/分钟
      【适合电压】6-12V(6000-12000转)
      【重量】130克

          电机的接口线路如下图所示:


二、电路图方面
      关于该开发板的PCBA点位图如下:

开发板的电路原理图如下:


三、开发环境方面
板上集成了JLink调试接口,支持串行调试(SWD),官方提供的资源包中包括基本工程示例,可使用IAR、MDK工具打开,本人习惯使用MDK,因此将基本工程示例导入进Keil中,如果电脑联网,此时会提示安装“MindMotion.MM32SPIN0x_DFP.1.0.8”pack包;如果电脑处于离线状态,可从灵动微官网下载基于MM32SPIN160C开发板的pack包,如下附件,然后将pack导入Keil工具中,而后直接编译即可。


将JLink烧录器与开发板上的CN7接口相连接,Keil中设置SWD模式,即可识别到调试器,并设置烧录后自动重启。


然后将开发板上CN1、CN2、CN3与电机、电源适配器正确连接,由于板卡支持12~28V的电压输入,而电机的额定电压是12V,因此采用12V/1A的电源适配器,实物连线图如下:




采用不带霍尔的轮询控制方式,直接烧录后,电机起震,没有如期得向逆时针或顺时针旋转,现象如同是前进两步后退两步,一直在抖动。在线调试,发现驱动换相函数存在问题,每种无刷电机的接线有所差异。关于BLDC电机,推荐看看TI的技术视频教程深入理解无刷直流电机(BLDC)原理以及控制,关于有刷电机与无刷电机的工作原理如下:

      由上图,有刷电机的主要结构就是定子+转子+电刷,通过旋转磁场获得转动力矩,从而输出动能。电刷与换向器不断接触摩擦,在转动中起到导电和换相作用。有刷电机采用机械换向,磁极不动,线圈旋转。电机工作时,线圈和换向器旋转,磁钢和碳刷不转,线圈电流方向的交替变化是随电机转动的换相器和电刷来完成的。

       由上图,无刷电机中,换相的工作交由控制器中的控制电路(一般为霍尔传感器+控制器,更先进的技术是磁编码器)来完成。无刷电机采取电子换向,线圈不动,磁极旋转。无刷电机,是使用一套电子设备,通过霍尔元件,感知永磁体磁极的位置,根据这种感知,使用电子线路,适时切换线圈中电流的方向,保证产生正确方向的磁力,来驱动电机,消除了有刷电机的缺点。
       四、工程源码
部分源码如下:

  1. #include "sys.h"


  2. typedef enum {

  3.     CW      = 0,    // 顺时钟方向

  4.     CCW     = 1     // 逆时针方向

  5. } motor_dir_t;


  6. typedef enum {

  7.     START   = 0,    // 启动

  8.     STOP    = 1,    // 停机

  9.     RUN     = 2     // 运行

  10. } motor_state_t;


  11. typedef struct{

  12.     motor_dir_t tMotorDirection;        // 电机旋转方向

  13.     motor_state_t tMotorState;          // 电机状态

  14.     uint16_t tDuty;                     // 速度占空比:0~100  为100是占空比为100%

  15.     uint16_t tSpeed;                    // 电机转速

  16.     uint8_t chHallValue;                // 霍尔状态

  17.     struct{

  18.         uint8_t chStartCount;           // 启动计数

  19.         uint16_t hwTimeCount;           // 堵转超时溢出计数

  20.     }tCount;

  21. }User_TypeDef_t;


  22. volatile User_TypeDef_t g_tMotor = {

  23.     CW,

  24.     START,

  25.     40,

  26.     0,

  27.     1,

  28.     0,

  29.     0

  30. };


  31. extern void Bldc_Phase_Chaneg(uint8_t step);

  32. extern void Hall_Exti_Callback(void);

  33. extern void Systick_Callback(void);


  34. int main(void)

  35. {

  36.     Systick_Init();

  37.    

  38.     Led_Init();

  39.     Hall_Init();

  40.     Bldc_Pwm_Init();

  41.     Gate_Driver_Init();


  42.     while(1) {

  43.         switch(g_tMotor.tMotorState) {

  44.             case START:         // 电机启动

  45.                 if(++g_tMotor.tCount.chStartCount > 20){    //电机启动失败

  46.                     g_tMotor.tMotorState = STOP;

  47.                     g_tMotor.tCount.chStartCount = 0;

  48.                 }

  49.                 SET_DUTY_U(BLDC_TIM_PERIOD * g_tMotor.tDuty / 100);

  50.                 SET_DUTY_V(BLDC_TIM_PERIOD * g_tMotor.tDuty / 100);

  51.                 SET_DUTY_W(BLDC_TIM_PERIOD * g_tMotor.tDuty / 100);

  52.                 GATE_DRIVER_ENABLE();

  53.                 Hall_Exti_Callback();

  54.                 Systick_Delay(5);

  55.                 break;

  56.             case RUN:         // 电机运行

  57.                 if (0){//some err

  58.                     g_tMotor.tMotorState = STOP;

  59.                 }

  60.                 Hall_Exti_Callback();

  61.                 break;

  62.             case STOP:         // 停机

  63.                 GATE_DRIVER_DISABLE();

  64.                 BLDC_UH_DISABLE();

  65.                 BLDC_UL_DISABLE();

  66.                 BLDC_VH_DISABLE();

  67.                 BLDC_VL_DISABLE();

  68.                 BLDC_WH_DISABLE();

  69.                 BLDC_WL_DISABLE();

  70.                 break;

  71.         }

  72.     }

  73. }


  74. void Bldc_Phase_Chaneg(uint8_t step)

  75. {

  76.         Systick_Delay(5);    //为了更好得看清楚,稍加延时

  77.         switch(step) {

  78.         case 3: //A+ C-

  79.             BLDC_UH_ENABLE();

  80.             BLDC_UL_DISABLE();

  81.             BLDC_VH_DISABLE();;

  82.             BLDC_VL_DISABLE();

  83.             BLDC_WH_DISABLE();

  84.             BLDC_WL_ENABLE();

  85.             break;

  86.         case 1: //B+ C-

  87.             BLDC_UH_DISABLE();

  88.             BLDC_UL_DISABLE();

  89.             BLDC_VH_ENABLE();

  90.                                                 BLDC_VL_DISABLE();

  91.             BLDC_WH_DISABLE();

  92.             BLDC_WL_ENABLE();

  93.             break;

  94.         case 5: //B+ A-

  95.             BLDC_UH_DISABLE();

  96.             BLDC_UL_ENABLE();

  97.                                     BLDC_VH_ENABLE();

  98.             BLDC_VL_DISABLE();

  99.             BLDC_WH_DISABLE();

  100.             BLDC_WH_DISABLE();

  101.             break;

  102.         case 4: //C+ A-

  103.             BLDC_UH_DISABLE();

  104.             BLDC_UL_ENABLE();

  105.             BLDC_VH_DISABLE();

  106.             BLDC_VL_DISABLE();

  107.                                     BLDC_WH_ENABLE();

  108.             BLDC_WL_DISABLE();

  109.             break;

  110.         case 6: //C+ B-

  111.             BLDC_UH_DISABLE();

  112.             BLDC_UL_DISABLE();

  113.             BLDC_VH_DISABLE();

  114.             BLDC_VL_ENABLE();

  115.                                     BLDC_WH_ENABLE();

  116.             BLDC_WL_DISABLE();

  117.             break;

  118.         case 2: //A+ B-

  119.                                           BLDC_UH_ENABLE();

  120.             BLDC_UL_DISABLE();

  121.             BLDC_VH_DISABLE();

  122.             BLDC_VL_ENABLE();

  123.             BLDC_WH_DISABLE();

  124.             BLDC_WL_DISABLE();

  125.             break;

  126.                                                

  127.         default:

  128.             BLDC_UH_DISABLE();

  129.             BLDC_UL_DISABLE();

  130.             BLDC_VH_DISABLE();

  131.             BLDC_VL_DISABLE();

  132.             BLDC_WH_DISABLE();

  133.             BLDC_WL_DISABLE();

  134.             break;

  135.     }

  136.        

  137. }


  138. void Systick_Callback(void)

  139. {

  140.     if(RUN == g_tMotor.tMotorState) {

  141.         g_tMotor.tCount.hwTimeCount ++;

  142.         if(g_tMotor.tCount.hwTimeCount > 2000) { // 2s超时,电机卡住不运转超过2s时间

  143.             GATE_DRIVER_DISABLE();

  144.             BLDC_UH_DISABLE();

  145.             BLDC_UL_DISABLE();

  146.             BLDC_VH_DISABLE();

  147.             BLDC_VL_DISABLE();

  148.             BLDC_WH_DISABLE();

  149.             BLDC_WL_DISABLE();

  150.             g_tMotor.tMotorState = STOP;

  151.             g_tMotor.tCount.hwTimeCount = 0;

  152.         }

  153.     }

  154. }


  155. void Hall_Exti_Callback(void)

  156. {

  157.     volatile uint8_t chStep = 0;

  158. //    chStep = (uint8_t)((HALL_PORT_U->IDR >> HALL_PINSOURCE_U) |

  159. //                       (HALL_PORT_V->IDR >> (HALL_PINSOURCE_V - 1)) |

  160. //                       (HALL_PORT_W->IDR >> (HALL_PINSOURCE_W - 2))) & 0x07;

  161.     if(g_tMotor.tMotorState == STOP) {

  162.         return;

  163.     }

  164.     if((HALL_PORT_U ->IDR & HALL_PIN_U) != (uint32_t)Bit_RESET) {

  165.         chStep |= 0x01;

  166.     }

  167.     if((HALL_PORT_V ->IDR & HALL_PIN_V) != (uint32_t)Bit_RESET) {

  168.         chStep |= 0x02;

  169.     }

  170.     if((HALL_PORT_W ->IDR & HALL_PIN_W) != (uint32_t)Bit_RESET) {

  171.         chStep |= 0x04;

  172.     }

  173.                

  174.     if (g_tMotor.chHallValue != chStep) {   //判断是否换向

  175.         g_tMotor.tMotorState = RUN;

  176.         g_tMotor.chHallValue = chStep ;

  177.     }


  178.     if(g_tMotor.tMotorDirection == CCW) {   // 方向判断

  179.         chStep =  7 - chStep;

  180.     }

  181.     Bldc_Phase_Chaneg(chStep);    //驱动换相

  182.        

  183.     g_tMotor.tCount.hwTimeCount = 0;

  184. }


       Jumper设定为出厂设置状态,工程编译后,烧录完成,电机顺利启动,代码中稍加了点延时,方便更清楚得看到电机的转动,电机转动又快又有劲,可与通用电动螺丝批相比较,但噪声有点大,有待优化。驱动工程源码见如下附件,通过MM32SPIN160C电机驱动板的使用,体验了灵动微MCU的库函数与ST的相兼容,移植起来更便捷,如果灵动微有像ST一样CubeMX开发工具就更强了。


下载程序源代码等资料,请点击阅读原文!