[应用方案] 闭回路无刷直流(BLDC)马达控制

[复制链接]
2153|14
 楼主| antusheng 发表于 2020-5-12 21:06 | 显示全部楼层 |阅读模式
本范例代码基于N76E003平台,使用PWM功能控制闭回路无刷直流马达马达。
脉冲宽度调制(Pulse Width Modulation, PWM),是一种输出方波的技巧,透过改变占空比来改
变等效的输出能量与电压,例如马达调速、阀门控制等都是透过这种方式控制的。要产生一个
三相弦波,可以在PWM的基础上改变调制脉冲的方式,将脉冲宽度时间的占空比按照正弦波规
律排列,即可获得正弦波输出,以控制逆变器电路中的开关通断,这种调制方式在现今的变频
器领域已经被广泛地采用,可用于控制三相电动机等。
无刷直流马达 (Brushless DC Motor, BLDC Motor) 在整流的处理上舍弃了传统马达所使用的电
刷,以电子装置取代,因此能够提升其可靠度与耐用度。无刷直流马达马达其优势为:体积比
相同功率输出的有刷马达更小更轻、可靠度与耐用度高。无刷直流马达马达的缺点为:需要电
子管理装置(微控制器)才能够运作。一个基本的无刷直流马达会配有霍尔传感器,依照霍尔传
感器回馈的转子位置讯号,微控制器能够输出对应的控制讯号,因此一个三相马达需要六组
PWM控制上下臂,以及三条线接收霍尔讯号。
开回路控制是一种控制器,使用系统数学模型与目前状态产生控制讯号,闭回路控制器则会加
入回授信号来判断系统是否已达到理想输出状态。在开回路与闭回路的差异上,开回路的架构
相对闭回路简单,系统稳定性较闭回路差,但成本较低。若是系统比较不需要精准性控制,可
采用开回路系统实现。
本范例程序使用闭回路的方式控制BLDC马达,并使用可变电阻控制转速。
N76E003_Close_Loop_BLDC_Motor_Readme_SC.pdf (644.37 KB, 下载次数: 96)

 楼主| antusheng 发表于 2020-5-12 21:07 | 显示全部楼层
608475eba9f6b0b6d3.png
如何执行范例程序
1. 根据目录信息章节进入 EC_N76E003_Close_Loop_BLDC_Motor_V1.00\
Sample_Code\ExampleCode\Close_Loop_BLDC_Motor_V1.00,双击路径中
CloseLoopBLDCMotor.uvproj 开启专案。
2. 进入编译模式接口
a. 编译
b. 下载代码至内存
c. 进入 / 离开除错模式
3. 进入除错模式接口
a. 执行代码
 楼主| antusheng 发表于 2020-5-12 21:07 | 显示全部楼层
EC_N76E003_Close_Loop_BLDC_Motor_V1.00.zip (641.23 KB, 下载次数: 104)
 楼主| antusheng 发表于 2020-5-12 21:08 | 显示全部楼层
  1. /**************************************************************************//**
  2. * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  3. * [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]    Close Loop BLDC Motor
  5. *
  6. * @note
  7. * Copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
  8. *****************************************************************************/

  9. /*---------------------------------------------------------------------------------------------------------*/
  10. /* Pin Functions                                                                                           */
  11. /*---------------------------------------------------------------------------------------------------------*/
  12. //P07 - HALL Sensor W Phase, HALL_W
  13. //P06 - HALL Sensor V Phase, HALL_V
  14. //P05 - HALL Sensor U Phase, HALL_U
  15. //P12 - Upper-arm MOS control of U phase, uh
  16. //P14 - Lower-arm MOS control of U phase, ul
  17. //P10 - Upper-arm MOS control of V phase, vh
  18. //P00 - Lower-arm MOS control of V phase, vl
  19. //P01 - Upper-arm MOS control of W phase, wh
  20. //P03 - Lower-arm MOS control of W phase, wl
  21. //P15 - Motor on/off switch
  22. //P02 - UART RX
  23. //P16 - UART TX
  24. //P17 - ADC input

  25. /*---------------------------------------------------------------------------------------------------------*/
  26. /* Include File                                                                                            */
  27. /*---------------------------------------------------------------------------------------------------------*/
  28. #include "N76E003.h"
  29. #include "Common.h"
  30. #include "Delay.h"
  31. #include "SFR_Macro.h"
  32. #include "Function_define.h"

  33. /*---------------------------------------------------------------------------------------------------------*/
  34. /* Macro                                                                                                   */
  35. /*---------------------------------------------------------------------------------------------------------*/

  36. #define UART1_DEBUG 0

  37. #define ABS(X) (X) >= 0 ? (X) : -(X)

  38. #define TIMER0_VALUE 65536-13333  //10ms
  39. #define MotorBoostDuty 0.15

  40. #define HallSensorPhase1 (0x05<<5)
  41. #define HallSensorPhase2 (0x01<<5)
  42. #define HallSensorPhase3 (0x03<<5)
  43. #define HallSensorPhase4 (0x02<<5)
  44. #define HallSensorPhase5 (0x06<<5)
  45. #define HallSensorPhase6 (0x04<<5)

  46. #define ADC_CONVERT_FINISH 1
  47. #define MOTOR_ON_OFF_SWITCH P15
  48. #define MOTOR_OFF 0

  49. /*---------------------------------------------------------------------------------------------------------*/
  50. /* Global variables                                                                                        */
  51. /*---------------------------------------------------------------------------------------------------------*/
  52. unsigned char data g_u8HallSensorMotorPhaseState = 0;
  53. unsigned char data g_u8TimerIntCount;
  54. unsigned char data g_u8TH0_Tmp, g_u8TL0_Tmp;
  55. unsigned short data g_u16CurrentSpeed = 0;

  56. /*---------------------------------------------------------------------------------------------------------*/
  57. /* Functions                                                                                               */
  58. /*---------------------------------------------------------------------------------------------------------*/

  59. void CheckMotorPhaseByHallSensor(unsigned char HallSensorInput)
  60. {
  61.     switch (HallSensorInput)
  62.     {
  63.         case HallSensorPhase1:
  64.         {
  65.             g_u8HallSensorMotorPhaseState = 1;
  66.             break;
  67.         }
  68.         case HallSensorPhase2:
  69.         {
  70.             g_u8HallSensorMotorPhaseState = 2;
  71.             break;
  72.         }
  73.         case HallSensorPhase3:
  74.         {
  75.             g_u8HallSensorMotorPhaseState = 3;
  76.             break;
  77.         }
  78.         case HallSensorPhase4:
  79.         {
  80.             g_u8HallSensorMotorPhaseState = 4;
  81.             break;
  82.         }
  83.         case HallSensorPhase5:
  84.         {
  85.             g_u8HallSensorMotorPhaseState = 5;
  86.             break;
  87.         }
  88.         case HallSensorPhase6:
  89.         {
  90.             g_u8HallSensorMotorPhaseState = 6;
  91.             break;
  92.         }
  93.     }
  94. }

  95. void ChangeMotorPhaseClockwise(void)
  96. {
  97.     /* Change motor phase to next phase. */
  98.     switch (g_u8HallSensorMotorPhaseState)
  99.     {
  100.         case 1:
  101.         {
  102.             PMEN = 0xfe; //uh
  103.             PMD = 0x20; //wl
  104.             break;
  105.         }
  106.         case 2:
  107.         {
  108.             PMEN = 0xfb; //vh
  109.             PMD = 0x20; //wl
  110.             break;
  111.         }
  112.         case 3:
  113.         {
  114.             PMEN = 0xfb; //vh
  115.             PMD = 0x02; //ul
  116.             break;
  117.         }
  118.         case 4:
  119.         {
  120.             PMEN = 0xef; //wh
  121.             PMD = 0x02; //ul
  122.             break;
  123.         }
  124.         case 5:
  125.         {
  126.             PMEN = 0xef; //wh
  127.             PMD = 0x08; //vl
  128.             break;
  129.         }
  130.         case 6:
  131.         {
  132.             PMEN = 0xfe; //uh
  133.             PMD = 0x08; //vl
  134.             break;
  135.         }
  136.     }
  137. }

  138. void ChangeMotorPhaseCounterClockwise(void)
  139. {
  140.     /* Change motor phase to next phase. */
  141.     switch (g_u8HallSensorMotorPhaseState)
  142.     {
  143.         case 6:
  144.         {
  145.             PMEN = 0xfe; //uh
  146.             PMD = 0x20; //wl
  147.             break;
  148.         }
  149.         case 5:
  150.         {
  151.             PMEN = 0xfb; //vh
  152.             PMD = 0x20; //wl
  153.             break;
  154.         }
  155.         case 4:
  156.         {
  157.             PMEN = 0xfb; //vh
  158.             PMD = 0x02; //ul
  159.             break;
  160.         }
  161.         case 3:
  162.         {
  163.             PMEN = 0xef; //wh
  164.             PMD = 0x02; //ul
  165.             break;
  166.         }
  167.         case 2:
  168.         {
  169.             PMEN = 0xef; //wh
  170.             PMD = 0x08; //vl
  171.             break;
  172.         }
  173.         case 1:
  174.         {
  175.             PMEN = 0xfe; //uh
  176.             PMD = 0x08; //vl
  177.             break;
  178.         }
  179.     }
  180. }

  181. void InitPWM(unsigned short *u16PWMDutyValue, unsigned char *u8OldMotorPhaseState)
  182. {
  183.     /* Initialize the pwm mode and clock. */
  184.     PWM_GP_MODE_ENABLE;
  185.     PWM_SYNCHRONIZED_MODE;
  186.     PWM_CLOCK_FSYS;
  187.     PWMPH = 0x01;
  188.     PWMPL = 0xF3;
  189.     /*----------------------------------------------------------------------
  190.         PWM frequency = Fpwm/((PWMPH,PWMPL) + 1), Fpwm = Fsys/PWM_CLOCK_DIV
  191.                       = (16MHz)/(0x1F3 + 1)
  192.                       = 32KHz (0.03125 ms)
  193.     ----------------------------------------------------------------------*/
  194.     /* Set PWM duty value on motor boost. */
  195.     *u16PWMDutyValue = 0x1F3 * MotorBoostDuty;
  196.    
  197.     /* Initialize the pwm value */
  198.     PWM0H = HIBYTE(*u16PWMDutyValue);
  199.     PWM0L = LOBYTE(*u16PWMDutyValue);

  200.     /* Initialize the Motor phase parameter */
  201.     *u8OldMotorPhaseState = 0xFF;
  202.     CheckMotorPhaseByHallSensor((P0 & 0xE0));

  203.     /* Initialize the pwm pin mode and close whole MOS. */
  204.     PMEN = 0xff;
  205.     PMD = 0x00;
  206. }

  207. void InitTimer2forCapture(void)
  208. {
  209.     /* Initial the Timer2 for capture motor speed */
  210.     TIMER2_CAP0_Capture_Mode;
  211.     IC6_P05_CAP0_RisingEdge_Capture;
  212.     TIMER2_DIV_512;
  213.     /* Enable Capture interrupt */
  214.     set_ECAP;
  215.     /* Triger Timer2 */
  216.     set_TR2;
  217. }

  218. void InitGPIO(void)
  219. {
  220.     Set_All_GPIO_Quasi_Mode;
  221.     P05_Input_Mode;
  222.     P06_Input_Mode;
  223.     P07_Input_Mode;
  224.     P15_Input_Mode;
  225.     P04_PushPull_Mode;
  226.     P12_PushPull_Mode;
  227.     P14_PushPull_Mode;
  228.     P10_PushPull_Mode;
  229.     P00_PushPull_Mode;
  230.     P01_PushPull_Mode;
  231.     P03_PushPull_Mode;
  232.     PWM0_P12_OUTPUT_ENABLE; /* P12 - Upper-arm MOS control of U phase, uh */
  233.     PWM1_P14_OUTPUT_ENABLE; /* P14 - Lower-arm MOS control of U phase, ul */
  234.     PWM2_P10_OUTPUT_ENABLE; /* P10 - Upper-arm MOS control of V phase, vh */
  235.     PWM3_P00_OUTPUT_ENABLE; /* P00 - Lower-arm MOS control of V phase, vl */
  236.     PWM4_P01_OUTPUT_ENABLE; /* P01 - Upper-arm MOS control of W phase, wh */
  237.     PWM5_P03_OUTPUT_ENABLE; /* P03 - Lower-arm MOS control of W phase, wl */
  238.     Enable_ADC_AIN0; /* ADC input */

  239.     PICON = 0xFC;   /* PORT 0 interrupt (Pin int control) */
  240.     PINEN = 0XE0;   /* Generates the pin interrupt when falling edge trigger */
  241.     PIPEN = 0XE0;   /* Generates the pin interrupt when rising edge trigger */
  242.     set_EPI;        /* Enable pin interrupt */
  243.     set_EX0;        /* Enable external interrupt */
  244. }

  245. void InitTimer0(void)
  246. {
  247.     clr_T0M;        /* T0M=0, Timer0 Clock = Fsys/12 */
  248.     TMOD |= 0x01;   /* Timer0 is 16-bit mode */
  249.    
  250.     /* Calculate the timer counter value for controlling the interrupt period on 10ms. */
  251.     g_u8TH0_Tmp = HIBYTE(TIMER0_VALUE);
  252.     g_u8TL0_Tmp = LOBYTE(TIMER0_VALUE);

  253.     /* Sets the timer counter value for controlling the interrupt period. The period is setting on 10ms. */
  254.     TH0 = g_u8TH0_Tmp;
  255.     TL0 = g_u8TL0_Tmp;

  256.     set_ET0;        /* enable Timer0 interrupt */
  257.     set_TR0;        /* Timer0 start */
  258. }

  259. unsigned int GetTargetSpeed(void)
  260. {
  261.     unsigned int data u16TargetSpeed;
  262.     /* ADC will sample the variable resistor value on ADCRH. */
  263.     /* Calculate the percentage of Max rotate speed 4500 rpm to target speed. */
  264.     u16TargetSpeed = (((unsigned long int)4500 * (unsigned long int)ADCRH) / 255);

  265.     /* Set the upper bound and lower bound on 450 and 4500 rpm. */
  266.     if (u16TargetSpeed < 450) u16TargetSpeed = 450;
  267.     if (u16TargetSpeed > 4500) u16TargetSpeed = 4500;

  268.     /* Clear ADN interrupt flag and re-trigger ADC to convert. */
  269.     clr_ADCF;
  270.     set_ADCS;
  271.     return u16TargetSpeed;
  272. }

  273. void main(void)
  274. {
  275.     int data s16SpeedDiff = 0;
  276.     unsigned int data u16TargetSpeed = 0;
  277.     unsigned char data u8TimerCntForUART;
  278.     unsigned char data u8OldMotorPhaseState;
  279.     unsigned short data u16PWMDutyValue;
  280.    
  281.     InitGPIO();
  282.    
  283. #ifdef UART1_DEBUG
  284.     /* Initialize UART1 for Debug */
  285.     u8TimerCntForUART = 0;
  286.     InitialUART1_Timer3(115200);
  287. #endif
  288.    
  289.     /* Initial PWM for controlling the 3 phase of motor */
  290.     InitPWM(&u16PWMDutyValue, &u8OldMotorPhaseState);
  291.     /* Initial Timer 0 for interrupt per 10 ms */
  292.     InitTimer0();
  293.     /* Initial Timer 2 for capturing the motor speed */
  294.     InitTimer2forCapture();

  295.     /* Reset timer and check the motor phase */
  296.     CheckMotorPhaseByHallSensor((P0 & 0xE0));

  297.     /* Clear ADC Flag and Reset Timer interrupt cnt */
  298.     clr_ADCF;
  299.     g_u8TimerIntCount = 0;      
  300.    
  301.     /* Enable all interrupts */
  302.     set_EA;
  303.    
  304.     /* Start the ADC and PWM */
  305.     set_ADCS;
  306.     set_LOAD;
  307.     set_PWMRUN;

  308.     while (1)
  309.     {
  310.         /* Get Motor realtime speed by ADC */
  311.         if (ADCF == ADC_CONVERT_FINISH)
  312.         {
  313.             u16TargetSpeed = GetTargetSpeed();
  314.         }

  315.         if (MOTOR_ON_OFF_SWITCH == MOTOR_OFF)
  316.         {
  317.             /* Stop the motor */
  318.             clr_PWMRUN;
  319.             PMEN = 0xff;
  320.             PMD = 0x00;

  321.             /* If the on/off switch is keeping in off state, stay on this while loop. */
  322.             while (MOTOR_ON_OFF_SWITCH == MOTOR_OFF);

  323.             /* Motor on/off switch is switching to on, re-initial the pwm for starting rotate. */
  324.             
  325.             /* Set PWM duty value on motor boost. */
  326.             u16PWMDutyValue = 0x1F3 * MotorBoostDuty;
  327.             
  328.             /* Initialize the pwm value */
  329.             PWM0H = HIBYTE(u16PWMDutyValue);
  330.             PWM0L = LOBYTE(u16PWMDutyValue);
  331.             
  332.             /* Initialize the Motor phase parameter */
  333.             u8OldMotorPhaseState = 0xFF;
  334.             CheckMotorPhaseByHallSensor((P0 & 0xE0));
  335.             
  336.             /* Start the PWM */
  337.             set_LOAD;
  338.             set_PWMRUN;
  339.             
  340.             /* Clear the Timer interrupt cnt */
  341.             g_u8TimerIntCount = 0;
  342.         }
  343.         else if (g_u8TimerIntCount >= 1) /* if the time past x * 10ms( x = 1 ), entering this if. */
  344.         {
  345.             /* Reset the timer interrupt times counter */
  346.             g_u8TimerIntCount = 0;
  347.             
  348.             /* Calculate the differentiation between target and current speed */
  349.             /*---------------------------------------------------------------------*/
  350.             //    PWM frequency =  32KHz (0.03125 ms)
  351.             //    Timer Capture (PWM clock number) * PWM clock Period = 1/2 Round
  352.             // => Timer Capture (PWM clock number) * PWM clock Period : 1/2 Round = 60s (1min) : X Round
  353.             // => X(s16SpeedDiff) = ((1/2) * 60) / ( 1/32k * Timer Capture (PWM clock number) )
  354.             /*---------------------------------------------------------------------*/
  355.                         
  356.             s16SpeedDiff = (unsigned long int)u16TargetSpeed - ((unsigned long int)30000000 / ((unsigned long int)(g_u16CurrentSpeed) * 32));

  357. #ifdef UART1_DEBUG
  358.             /* Print the speed of motor */
  359.             u8TimerCntForUART++;
  360.             if (u8TimerCntForUART >= 30)   //Per 300ms send UART data
  361.             {
  362.                 Send_Data_To_UART1(((u16TargetSpeed - s16SpeedDiff)));
  363.                 u8TimerCntForUART = 0;
  364.             }
  365. #endif
  366.             /* Modified the PWM duty for tracing the target speed */
  367.             u16PWMDutyValue += ((s16SpeedDiff > 0) ? 1 : (-1));

  368.             /* Set new PWM duty */
  369.             PWM0H = HIBYTE(u16PWMDutyValue);
  370.             PWM0L = LOBYTE(u16PWMDutyValue);
  371.             set_LOAD;
  372.         }

  373.         /* Change the Motor phase */
  374.         if (u8OldMotorPhaseState != g_u8HallSensorMotorPhaseState)
  375.         {
  376.             /* Record the last motor phase */
  377.             u8OldMotorPhaseState = g_u8HallSensorMotorPhaseState;
  378.             /* Change the motor phase */
  379.             ChangeMotorPhaseClockwise();
  380.         }
  381.     }
  382. }
  383. /*---------------------------------------------------------------------------------------------------------*/
  384. /* Interrupt                                                                                               */
  385. /*---------------------------------------------------------------------------------------------------------*/

  386. void PinInterrupt_ISR(void) interrupt 7
  387. {
  388.     /* Detecting the motor phase by hall sensor. */
  389.     CheckMotorPhaseByHallSensor(P0 & 0xe0);
  390.     /* Clear the Pin interrupt flag. */
  391.     PIF = 0x00;
  392. }

  393. void Timer0_ISR(void) interrupt 1
  394. {
  395.     /* Sets the timer counter value for controlling the interrupt period. The period is setting on 10ms. */
  396.     TH0 = g_u8TH0_Tmp;
  397.     TL0 = g_u8TL0_Tmp;
  398.     /* Recorded the interrupt times. */
  399.     g_u8TimerIntCount++;
  400. }

  401. void Capture_ISR(void) interrupt 12
  402. {
  403.     /* Clear capture0 interrupt flag */
  404.     clr_CAPF0;
  405.     /* Get the current motor speed */
  406.     g_u16CurrentSpeed = (C0L + (C0H << 8));

  407.     clr_TF2;
  408. }
  409. /*** (C) COPYRIGHT 2019 Nuvoton Technology Corp. ***/
 楼主| antusheng 发表于 2020-5-12 21:08 | 显示全部楼层
更详细 的请下载压缩包,里面是完整的工程与说明。
wahahaheihei 发表于 2020-5-20 22:43 | 显示全部楼层
资料很棒。
643757107 发表于 2020-5-20 23:20 | 显示全部楼层
没想到003也可以玩这么高级的。
gwsan 发表于 2020-6-1 17:50 | 显示全部楼层
非常感谢楼主分享
kxsi 发表于 2020-6-1 17:50 | 显示全部楼层
非常感谢楼主分享
nawu 发表于 2020-6-1 17:51 | 显示全部楼层
精度能达到多少
qcliu 发表于 2020-6-1 17:51 | 显示全部楼层
响应速度快吗
tfqi 发表于 2020-6-1 17:51 | 显示全部楼层
驱动能力大不大
guyufeng×× 发表于 2020-10-5 15:02 | 显示全部楼层
小白请教问题:
#define HallSensorPhase1 (0x05<<5)
#define HallSensorPhase2 (0x01<<5)
#define HallSensorPhase3 (0x03<<5)
#define HallSensorPhase4 (0x02<<5)
#define HallSensorPhase5 (0x06<<5)
#define HallSensorPhase6 (0x04<<5)
这几个值是什么值?是HALL 引脚采集到的电平吗?
rgjinxuan 发表于 2020-12-5 13:20 | 显示全部楼层
非常感谢楼主分享
guijial511 发表于 2020-12-7 21:08 来自手机 | 显示全部楼层
学习了,感谢楼主分享经验。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

86

主题

1723

帖子

5

粉丝
快速回复 在线客服 返回列表 返回顶部