打印
[应用方案]

闭回路无刷直流(BLDC)马达控制

[复制链接]
1469|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)

使用特权

评论回复
沙发
antusheng|  楼主 | 2020-5-12 21:07 | 只看该作者

如何执行范例程序
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)

使用特权

评论回复
地板
antusheng|  楼主 | 2020-5-12 21:08 | 只看该作者
/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     main.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
* [url=home.php?mod=space&uid=247401]@brief[/url]    Close Loop BLDC Motor
*
* @note
* Copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/

/*---------------------------------------------------------------------------------------------------------*/
/* Pin Functions                                                                                           */
/*---------------------------------------------------------------------------------------------------------*/
//P07 - HALL Sensor W Phase, HALL_W
//P06 - HALL Sensor V Phase, HALL_V
//P05 - HALL Sensor U Phase, HALL_U
//P12 - Upper-arm MOS control of U phase, uh
//P14 - Lower-arm MOS control of U phase, ul
//P10 - Upper-arm MOS control of V phase, vh
//P00 - Lower-arm MOS control of V phase, vl
//P01 - Upper-arm MOS control of W phase, wh
//P03 - Lower-arm MOS control of W phase, wl
//P15 - Motor on/off switch
//P02 - UART RX
//P16 - UART TX
//P17 - ADC input

/*---------------------------------------------------------------------------------------------------------*/
/* Include File                                                                                            */
/*---------------------------------------------------------------------------------------------------------*/
#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"

/*---------------------------------------------------------------------------------------------------------*/
/* Macro                                                                                                   */
/*---------------------------------------------------------------------------------------------------------*/

#define UART1_DEBUG 0

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

#define TIMER0_VALUE 65536-13333  //10ms
#define MotorBoostDuty 0.15

#define HallSensorPhase1 (0x05<<5)
#define HallSensorPhase2 (0x01<<5)
#define HallSensorPhase3 (0x03<<5)
#define HallSensorPhase4 (0x02<<5)
#define HallSensorPhase5 (0x06<<5)
#define HallSensorPhase6 (0x04<<5)

#define ADC_CONVERT_FINISH 1
#define MOTOR_ON_OFF_SWITCH P15
#define MOTOR_OFF 0

/*---------------------------------------------------------------------------------------------------------*/
/* Global variables                                                                                        */
/*---------------------------------------------------------------------------------------------------------*/
unsigned char data g_u8HallSensorMotorPhaseState = 0;
unsigned char data g_u8TimerIntCount;
unsigned char data g_u8TH0_Tmp, g_u8TL0_Tmp;
unsigned short data g_u16CurrentSpeed = 0;

/*---------------------------------------------------------------------------------------------------------*/
/* Functions                                                                                               */
/*---------------------------------------------------------------------------------------------------------*/

void CheckMotorPhaseByHallSensor(unsigned char HallSensorInput)
{
    switch (HallSensorInput)
    {
        case HallSensorPhase1:
        {
            g_u8HallSensorMotorPhaseState = 1;
            break;
        }
        case HallSensorPhase2:
        {
            g_u8HallSensorMotorPhaseState = 2;
            break;
        }
        case HallSensorPhase3:
        {
            g_u8HallSensorMotorPhaseState = 3;
            break;
        }
        case HallSensorPhase4:
        {
            g_u8HallSensorMotorPhaseState = 4;
            break;
        }
        case HallSensorPhase5:
        {
            g_u8HallSensorMotorPhaseState = 5;
            break;
        }
        case HallSensorPhase6:
        {
            g_u8HallSensorMotorPhaseState = 6;
            break;
        }
    }
}

void ChangeMotorPhaseClockwise(void)
{
    /* Change motor phase to next phase. */
    switch (g_u8HallSensorMotorPhaseState)
    {
        case 1:
        {
            PMEN = 0xfe; //uh
            PMD = 0x20; //wl
            break;
        }
        case 2:
        {
            PMEN = 0xfb; //vh
            PMD = 0x20; //wl
            break;
        }
        case 3:
        {
            PMEN = 0xfb; //vh
            PMD = 0x02; //ul
            break;
        }
        case 4:
        {
            PMEN = 0xef; //wh
            PMD = 0x02; //ul
            break;
        }
        case 5:
        {
            PMEN = 0xef; //wh
            PMD = 0x08; //vl
            break;
        }
        case 6:
        {
            PMEN = 0xfe; //uh
            PMD = 0x08; //vl
            break;
        }
    }
}

void ChangeMotorPhaseCounterClockwise(void)
{
    /* Change motor phase to next phase. */
    switch (g_u8HallSensorMotorPhaseState)
    {
        case 6:
        {
            PMEN = 0xfe; //uh
            PMD = 0x20; //wl
            break;
        }
        case 5:
        {
            PMEN = 0xfb; //vh
            PMD = 0x20; //wl
            break;
        }
        case 4:
        {
            PMEN = 0xfb; //vh
            PMD = 0x02; //ul
            break;
        }
        case 3:
        {
            PMEN = 0xef; //wh
            PMD = 0x02; //ul
            break;
        }
        case 2:
        {
            PMEN = 0xef; //wh
            PMD = 0x08; //vl
            break;
        }
        case 1:
        {
            PMEN = 0xfe; //uh
            PMD = 0x08; //vl
            break;
        }
    }
}

void InitPWM(unsigned short *u16PWMDutyValue, unsigned char *u8OldMotorPhaseState)
{
    /* Initialize the pwm mode and clock. */
    PWM_GP_MODE_ENABLE;
    PWM_SYNCHRONIZED_MODE;
    PWM_CLOCK_FSYS;
    PWMPH = 0x01;
    PWMPL = 0xF3;
    /*----------------------------------------------------------------------
        PWM frequency = Fpwm/((PWMPH,PWMPL) + 1), Fpwm = Fsys/PWM_CLOCK_DIV
                      = (16MHz)/(0x1F3 + 1)
                      = 32KHz (0.03125 ms)
    ----------------------------------------------------------------------*/
    /* Set PWM duty value on motor boost. */
    *u16PWMDutyValue = 0x1F3 * MotorBoostDuty;
   
    /* Initialize the pwm value */
    PWM0H = HIBYTE(*u16PWMDutyValue);
    PWM0L = LOBYTE(*u16PWMDutyValue);

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

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

void InitTimer2forCapture(void)
{
    /* Initial the Timer2 for capture motor speed */
    TIMER2_CAP0_Capture_Mode;
    IC6_P05_CAP0_RisingEdge_Capture;
    TIMER2_DIV_512;
    /* Enable Capture interrupt */
    set_ECAP;
    /* Triger Timer2 */
    set_TR2;
}

void InitGPIO(void)
{
    Set_All_GPIO_Quasi_Mode;
    P05_Input_Mode;
    P06_Input_Mode;
    P07_Input_Mode;
    P15_Input_Mode;
    P04_PushPull_Mode;
    P12_PushPull_Mode;
    P14_PushPull_Mode;
    P10_PushPull_Mode;
    P00_PushPull_Mode;
    P01_PushPull_Mode;
    P03_PushPull_Mode;
    PWM0_P12_OUTPUT_ENABLE; /* P12 - Upper-arm MOS control of U phase, uh */
    PWM1_P14_OUTPUT_ENABLE; /* P14 - Lower-arm MOS control of U phase, ul */
    PWM2_P10_OUTPUT_ENABLE; /* P10 - Upper-arm MOS control of V phase, vh */
    PWM3_P00_OUTPUT_ENABLE; /* P00 - Lower-arm MOS control of V phase, vl */
    PWM4_P01_OUTPUT_ENABLE; /* P01 - Upper-arm MOS control of W phase, wh */
    PWM5_P03_OUTPUT_ENABLE; /* P03 - Lower-arm MOS control of W phase, wl */
    Enable_ADC_AIN0; /* ADC input */

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

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

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

    set_ET0;        /* enable Timer0 interrupt */
    set_TR0;        /* Timer0 start */
}

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

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

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

void main(void)
{
    int data s16SpeedDiff = 0;
    unsigned int data u16TargetSpeed = 0;
    unsigned char data u8TimerCntForUART;
    unsigned char data u8OldMotorPhaseState;
    unsigned short data u16PWMDutyValue;
   
    InitGPIO();
   
#ifdef UART1_DEBUG
    /* Initialize UART1 for Debug */
    u8TimerCntForUART = 0;
    InitialUART1_Timer3(115200);
#endif
   
    /* Initial PWM for controlling the 3 phase of motor */
    InitPWM(&u16PWMDutyValue, &u8OldMotorPhaseState);
    /* Initial Timer 0 for interrupt per 10 ms */
    InitTimer0();
    /* Initial Timer 2 for capturing the motor speed */
    InitTimer2forCapture();

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

    /* Clear ADC Flag and Reset Timer interrupt cnt */
    clr_ADCF;
    g_u8TimerIntCount = 0;      
   
    /* Enable all interrupts */
    set_EA;
   
    /* Start the ADC and PWM */
    set_ADCS;
    set_LOAD;
    set_PWMRUN;

    while (1)
    {
        /* Get Motor realtime speed by ADC */
        if (ADCF == ADC_CONVERT_FINISH)
        {
            u16TargetSpeed = GetTargetSpeed();
        }

        if (MOTOR_ON_OFF_SWITCH == MOTOR_OFF)
        {
            /* Stop the motor */
            clr_PWMRUN;
            PMEN = 0xff;
            PMD = 0x00;

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

            /* Motor on/off switch is switching to on, re-initial the pwm for starting rotate. */
            
            /* Set PWM duty value on motor boost. */
            u16PWMDutyValue = 0x1F3 * MotorBoostDuty;
            
            /* Initialize the pwm value */
            PWM0H = HIBYTE(u16PWMDutyValue);
            PWM0L = LOBYTE(u16PWMDutyValue);
            
            /* Initialize the Motor phase parameter */
            u8OldMotorPhaseState = 0xFF;
            CheckMotorPhaseByHallSensor((P0 & 0xE0));
            
            /* Start the PWM */
            set_LOAD;
            set_PWMRUN;
            
            /* Clear the Timer interrupt cnt */
            g_u8TimerIntCount = 0;
        }
        else if (g_u8TimerIntCount >= 1) /* if the time past x * 10ms( x = 1 ), entering this if. */
        {
            /* Reset the timer interrupt times counter */
            g_u8TimerIntCount = 0;
            
            /* Calculate the differentiation between target and current speed */
            /*---------------------------------------------------------------------*/
            //    PWM frequency =  32KHz (0.03125 ms)
            //    Timer Capture (PWM clock number) * PWM clock Period = 1/2 Round
            // => Timer Capture (PWM clock number) * PWM clock Period : 1/2 Round = 60s (1min) : X Round
            // => X(s16SpeedDiff) = ((1/2) * 60) / ( 1/32k * Timer Capture (PWM clock number) )
            /*---------------------------------------------------------------------*/
                        
            s16SpeedDiff = (unsigned long int)u16TargetSpeed - ((unsigned long int)30000000 / ((unsigned long int)(g_u16CurrentSpeed) * 32));

#ifdef UART1_DEBUG
            /* Print the speed of motor */
            u8TimerCntForUART++;
            if (u8TimerCntForUART >= 30)   //Per 300ms send UART data
            {
                Send_Data_To_UART1(((u16TargetSpeed - s16SpeedDiff)));
                u8TimerCntForUART = 0;
            }
#endif
            /* Modified the PWM duty for tracing the target speed */
            u16PWMDutyValue += ((s16SpeedDiff > 0) ? 1 : (-1));

            /* Set new PWM duty */
            PWM0H = HIBYTE(u16PWMDutyValue);
            PWM0L = LOBYTE(u16PWMDutyValue);
            set_LOAD;
        }

        /* Change the Motor phase */
        if (u8OldMotorPhaseState != g_u8HallSensorMotorPhaseState)
        {
            /* Record the last motor phase */
            u8OldMotorPhaseState = g_u8HallSensorMotorPhaseState;
            /* Change the motor phase */
            ChangeMotorPhaseClockwise();
        }
    }
}
/*---------------------------------------------------------------------------------------------------------*/
/* Interrupt                                                                                               */
/*---------------------------------------------------------------------------------------------------------*/

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

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

void Capture_ISR(void) interrupt 12
{
    /* Clear capture0 interrupt flag */
    clr_CAPF0;
    /* Get the current motor speed */
    g_u16CurrentSpeed = (C0L + (C0H << 8));

    clr_TF2;
}
/*** (C) COPYRIGHT 2019 Nuvoton Technology Corp. ***/

使用特权

评论回复
5
antusheng|  楼主 | 2020-5-12 21:08 | 只看该作者
更详细 的请下载压缩包,里面是完整的工程与说明。

使用特权

评论回复
6
wahahaheihei| | 2020-5-20 22:43 | 只看该作者
资料很棒。

使用特权

评论回复
7
643757107| | 2020-5-20 23:20 | 只看该作者
没想到003也可以玩这么高级的。

使用特权

评论回复
8
gwsan| | 2020-6-1 17:50 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
9
kxsi| | 2020-6-1 17:50 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
10
nawu| | 2020-6-1 17:51 | 只看该作者
精度能达到多少

使用特权

评论回复
11
qcliu| | 2020-6-1 17:51 | 只看该作者
响应速度快吗

使用特权

评论回复
12
tfqi| | 2020-6-1 17:51 | 只看该作者
驱动能力大不大

使用特权

评论回复
13
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 引脚采集到的电平吗?

使用特权

评论回复
14
rgjinxuan| | 2020-12-5 13:20 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
15
guijial511| | 2020-12-7 21:08 | 只看该作者
学习了,感谢楼主分享经验。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

83

主题

1450

帖子

5

粉丝