⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 Luminary Micro BLDC motor control software
💻 C
📖 第 1 页 / 共 5 页
字号:
//! The angle of the motor drive will be updated, and new waveform values
//! computed and supplied to the PWM module.
//!
//! \note Since this interrupt is software triggered, there is no interrupt
//! source to clear in this handler.
//!
//! \return None.
//
//*****************************************************************************
void
MainWaveformTick(void)
{
    unsigned long ulTemp, pulDutyCycles[3];
    unsigned long ulHall;

    //
    // There is nothing to be done if the motor drive is not running.
    //
    if((g_ulState == STATE_STOPPED) || (g_ulState == STATE_PRECHARGE) ||
       (g_ulState == STATE_BACK_PRECHARGE))
    {
        //
        // Reduce the PWM period count based on the number of updates that
        // would have occurred if the motor drive was running.
        //
        PWMReducePeriodCount((PWMGetPeriodCount() /
                              (g_sParameters.ucUpdateRate + 1)) *
                             (g_sParameters.ucUpdateRate + 1));

        //
        // Return without doing anything further.
        //
        return;
    }

    //
    // Current Control Loop:  When the target current is non-zero, and the
    // motor current exceeds the target current value, the duty cycle will
    // be reduced to limit the current to the target settings.
    //
    if((g_sParameters.sTargetCurrent != 0) &&
       (g_sMotorCurrent > g_sParameters.sTargetCurrent))
    {
        static short sPreviousMotorCurrent = 0;

        if(sPreviousMotorCurrent != g_sMotorCurrent)
        {
            //
            // Save the motor current value.
            //
            sPreviousMotorCurrent = g_sMotorCurrent;

            //
            // Get the difference between the target and motor current.
            //
            ulTemp = (g_sMotorCurrent - g_sParameters.sTargetCurrent);

            //
            // Compute the percentage over, in 16.16 fixed point format.
            //
            ulTemp = ((ulTemp * 65536) / g_sParameters.sTargetCurrent);

            //
            // Compute the equivalent percentage of the current duty cycle.
            //
            ulTemp = ((ulTemp * g_ulDutyCycle) / 65536);

            //
            // Reduce the duty cycle.
            //
            g_ulDutyCycle = g_ulDutyCycle - ulTemp;
        }
    }

    //
    // Loop until the PWM period count is less than the update rate.  The angle
    // is updated based on the number of update periods that have passed, which
    // may be more than one.  After the angle is updated, the waveform
    // moulations are computed.  Since the period count may go above the update
    // rate while computing the waveform modulation, this outer loop is
    // required to ensure that the all update periods are accounted for before
    // this routine returns.
    //
    while(PWMGetPeriodCount() > g_sParameters.ucUpdateRate)
    {
        //
        // Get the number of updates that are pending.  Normally, this will be
        // one, but may be larger if the processor is heavily loaded.
        //
        ulTemp = PWMGetPeriodCount() / (g_sParameters.ucUpdateRate + 1);

        //
        // See if the motor drive direction is forward or backward.
        //
        if(g_ulState & STATE_FLAG_FORWARD)
        {
            //
            // The motor drive direction is forward, so increment the motor
            // drive angle by the angle delta.
            //
            g_ulAngle += (g_ulAngleDelta * (g_sParameters.ucUpdateRate + 1) *
                          ulTemp);
        }
        else
        {
            //
            // The motor drive direction is backward, so decrement the motor
            // drive angle by the angle delta.
            //
            g_ulAngle -= (g_ulAngleDelta * (g_sParameters.ucUpdateRate + 1) *
                          ulTemp);
        }

        //
        // Reduce the PWM period count by the number of updates just performed.
        //
        PWMReducePeriodCount(ulTemp * (g_sParameters.ucUpdateRate + 1));

        //
        // Perform trapezoid modulation.
        //
        if(HWREGBITH(&(g_sParameters.usFlags), FLAG_DRIVE_BIT) ==
                FLAG_DRIVE_TRAPEZOID)
        {
            //
            // Set the duty cycle for each phase to the amplitude.
            //
            pulDutyCycles[0] = pulDutyCycles[1] = pulDutyCycles[2] =
                g_ulDutyCycle;

            //
            // For sensored operation, check the sensor type.
            //
            if(HWREGBITH(&(g_sParameters.usFlags), FLAG_SENSOR_BIT) ==
                    FLAG_SENSOR_PRESENT)
            {
                //
                // For digital/gpio hall sensor, set the previous and current
                // values to the same, to skip the modulation code (it is
                // run directly from the hall interrupt).
                //
                if(HWREGBITH(&(g_sParameters.usFlags), FLAG_SENSOR_TYPE_BIT) ==
                        FLAG_SENSOR_TYPE_GPIO)
                {
                    ulHall = g_ulHallValue;
                    g_ulHallPrevious = ulHall;
                }

                //
                // For linear hall sensor, use the linear hall value calculated
                // in the ADC module.
                //
                else
                {
                    ulHall = g_ulLinearHallValue;
                }
            }

            //
            // For Sensorless operation, check if the mode is startup or
            // run mode.
            //
            else
            {
                //
                // Use the startup sequence hall values for startup mode.
                //
                if(g_ulState & STATE_FLAG_STARTUP)
                {
                    ulHall = g_ulStartupHallValue;
                }

                //
                // Use the Back EMF hall values for run mode.
                //
                else
                {
                    ulHall = g_ulBEMFHallValue;
                }
            }

            //
            // Run the trapezoid modulation based on the Hall sensor value.
            //
            if(ulHall != g_ulHallPrevious)
            {
                TrapModulate(ulHall);
                g_ulHallPrevious = ulHall;
            }
        }

        //
        // Perform sine wave modulation.
        //
        else if(HWREGBITH(&(g_sParameters.usFlags), FLAG_DRIVE_BIT) ==
                FLAG_DRIVE_SINE)
        {
            static const unsigned long ulHallToAngle[] =
                { 0, 270, 30, 330, 150, 210, 90, 0 };

            //
            // Check for change in Hall State.
            //
            if((g_ulHallPrevious != g_ulHallValue) &&
               ((g_ulSineTarget != g_ulSpeed) || (g_ulHallValue == 5)))
            {
                g_ulAngle = ulHallToAngle[g_ulHallValue];
                if((g_ulState & STATE_FLAG_FORWARD) == STATE_FLAG_BACKWARD)
                {
                    g_ulAngle += 60;
                    g_ulAngle %= 360;
                }
                g_ulAngle = (((g_ulAngle << 16) / 360) << 16);
            }
            g_ulHallPrevious = g_ulHallValue;

            //
            // Run the sine modulation code.
            //
            SineModulate(g_ulAngle, g_ulDutyCycle, pulDutyCycles);

            //
            // If running in reverse, the duty cycles must be inverted
            //
            if((g_ulState & STATE_FLAG_FORWARD) == STATE_FLAG_BACKWARD)
            {
                pulDutyCycles[0] = 65536 - pulDutyCycles[0];
                pulDutyCycles[1] = 65536 - pulDutyCycles[1];
                pulDutyCycles[2] = 65536 - pulDutyCycles[2];
            }
        }

        //
        // For now, there are no other modulations enabled, so ensure that
        // the Duty Cycle is set to minimal.
        // 
        else 
        {
            pulDutyCycles[0] = pulDutyCycles[1] = pulDutyCycles[2] = 0;
        }

        //
        // Set the new duty cycle.
        //
        //g_ulDebugInfo = (g_ulDutyCycle * 100) / 65536;
        PWMSetDutyCycle(pulDutyCycles[0], pulDutyCycles[1], pulDutyCycles[2]);
    }
}

//*****************************************************************************
//
//! Handles the gate driver precharge mode of the motor drive.
//!
//! This function performs the processing and state transitions associated with
//! the gate driver precharge mode of the motor drive.
//!
//! \return None.
//
//*****************************************************************************
static void
MainPrechargeHandler(void)
{
    //
    // Punch the watchdog to prevent timeout from killing our startup
    // sequence.
    //
    WatchdogReloadSet(WATCHDOG_BASE, WATCHDOG_RELOAD_VALUE);

    //
    // Decrement the count of milliseconds while in this state.
    //
    g_ulStateCount--;

    //
    // See if the motor drive has been in the precharge state long enough.
    //
    if(g_ulStateCount != 0)
    {
        //
        // There is nothing further to be done for this state.
        //
        return;
    }

    if(HWREGBITH(&(g_sParameters.usFlags), FLAG_SENSOR_BIT) ==
                FLAG_SENSOR_ABSENT)
    {
        //
        // For the manual commutation sequence in startup, set the commutation
        // period to an integer number of milliseconds.
        //
        g_ulStartupHallStateCount = g_ulStartupHallStateCountReload = 50;

        //
        // Set the intial duty cycle.
        //
        g_ulDutyCycle = ((65536 * g_sParameters.ucStartupDutyCycle) / 100);
        PWMSetDutyCycle(g_ulDutyCycle, g_ulDutyCycle, g_ulDutyCycle);

        //
        // Set the duration of the startup mode.
        //
        g_ulStateCount = g_sParameters.ulStartupCount;

        //
        // Set the forward/reverse state accordingly.
        //
        if(g_ulState == STATE_PRECHARGE)
        {
            g_ulState = STATE_STARTUP;
        }
        else
        {
            g_ulState = STATE_BACK_STARTUP;
        }

        //
        // And return.
        //
        return;
    }

    //
    // Set the miniumum duty cycle.
    //
    g_ulDutyCycle = 0;
    PWMSetDutyCycle(g_ulDutyCycle, g_ulDutyCycle, g_ulDutyCycle);

    //
    // If trapezoid drive, kick start the motor by running a Hall interrupt.
    // Otherwise, enable all the PWM outputs for other drive modes.
    //
    if(HWREGBITH(&(g_sParameters.usFlags), FLAG_DRIVE_BIT) ==
            FLAG_DRIVE_TRAPEZOID)
    {
        GPIOBIntHandler();
    }
    else
    {
        PWMOutputOn();
    }
    
    //
    // Advance the state machine to the appropriate acceleration state based on
    // the motor direction.
    //
    if(g_ulState == STATE_PRECHARGE)
    {
        g_ulState = STATE_RUN;
    }
    else
    {
        g_ulState = STATE_BACK_RUN;
    }

    //
    // Start the motor drive at zero.
    //
    g_ulSpeed = 0;

    //
    // Reset the integrator.
    //
    g_lSpeedIntegrator = 0;

    //
    // Start the motor drive at an angle of zero degrees.
    //
    g_ulAngle = 0;
}

//*****************************************************************************
//
//! Handles the startup mode of the motor drive.
//!
//! This function performs the processing and state transitions associated with
//! the startup mode of the motor drive for sensorless operation.
//!
//! \return None.
//
//*****************************************************************************
static void
MainStartupHandler(void)
{
    static unsigned char ucHallSequence[] = {5, 1, 3, 2, 6, 4};
    static unsigned char ucHallState = 0;

    //
    // Punch the watchdog to prevent timeout from killing our startup
    // sequence.
    //
    WatchdogReloadSet(WATCHDOG_BASE, WATCHDOG_RELOAD_VALUE);

    //
    // See if the motor drive has been in the startup state long enough.
    //
    if(g_ulStateCount == 0)
    {
        //

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -