📄 main.c
字号:
//Change PWM pins to output again to allow PWM control.
EnablePWMOutputs();
}
/*! \brief Configures Timer/Counter1 in braking mode.
*
* This function configures Timer/counter1 in sinusoidal mode in a safe way
* way by disabling all output before any configuration bits are changed.
* After running this function, Timer/counter1 will be in phase and frequency
* correct mode with a duty cycle of 0 on all three phases, resulting in
* low side braking.
*/
#if (TURN_MODE == TURN_MODE_BRAKE)
#pragma inline = forced
static void TimerSetModeBrake(void)
{
//Set PWM pins to input (Hi-Z) while changing modes.
DisablePWMOutputs();
//Set Timer/counter1 in phase and frequency correct mode.
TCCR1A = (0 << COM1A1) | (1 << COM1A0) | (0 << COM1B1) | (1 << COM1B0) | (1 << PWM1A) | (1 << PWM1B);
TCCR1C = (0 << COM1A1S) | (1 << COM1A0S) | (0 << COM1B1S) | (1 << COM1B0S) | (0 << COM1D1) | (1 << COM1D0) | (1 << PWM1D);
TCCR1D &= ~((1 << WGM11) | (1 << WGM10));
TCCR1D |= (0 << WGM11) | (1 << WGM10);
//All output duty cycles at 0 creates a braking force. (Low side braking)
TC1_SET_ALL_COMPARE_VALUES(0x0000);
fastFlags.driveWaveform = WAVEFORM_BRAKING;
//Change PWM pins to output again to allow PWM control.
EnablePWMOutputs();
}
#endif
/*! \brief Sets the duty cycle when operating in block commutation mode.
*
* Calling this function sets the duty cycle when operating in block
* commutation mode (PWM6 mode). Do not use this function when Timer/counter1
* is not operated in PWM6 mode.
*
* Note that the argument specifies the output compare value, not the duty
* cycle in percent. The duty cycle in percent can be calculated as
* duty = (compareValue / PWM_TOP_VALUE) * 100.
*
* \param compareValue Ouput compare value.
*/
#pragma inline = forced
static void BlockCommutationSetDuty(const uint16_t compareValue)
{
TC1_PWM6_SET_DUTY_CYCLE(compareValue);
}
/*! \brief Returns the desired direction.
*
* This function returns the current desired direction.
* \note The direction input is not read at this time. A
* separate pin change interrupt is responsible for reading
* the input.
*
* \retval DIRECTION_FORWARD Forward direction is requested.
* \retval DIRECTION_REVERSE Reverse direction is requested.
*/
#pragma inline = forced
static uint8_t GetDesiredDirection(void)
{
return (uint8_t)fastFlags.desiredDirection;
}
/*! \brief Performs block commutation according to running direction and hall sensor input
*
* This function performs a block commutation according to the
* specified running direction and hall sensor input.
*
* \note Do not use this function while the timers are configured
* for sine wave driving.
*
* \param direction Direction of rotation.
* \param hall Hall sensor value at the same form as returned by GetHall().
*/
#pragma inline = forced
static void BlockCommutate(const uint8_t direction, const uint8_t hall)
{
if (direction == DIRECTION_FORWARD)
{
TCCR1E = blockCommutationTableForward[hall];
}
else
{
TCCR1E = blockCommutationTableReverse[hall];
}
}
/*! \brief Reads the hall sensor inputs.
*
* This function reads the hall sensor inputs and converts it to
* a number from 1 to 6 by combining the hall sensors as bits: H3|H2|H1.
*
* \note It is possible to change the physical placement of hall sensor
* inputs, but the recommended configuration is the one used in this
* example, since it requires very little code to decode the hall values.
*
* \return The decoded hall sensor value.
*
* \retval 0 Illegal hall state. Possible hardware error.
* \retval 1-6 Legal hall sensor values.
* \retval 7 Illegal hall state. Possible hardware error.
*/
#pragma inline = forced
static uint8_t GetHall(void)
{
uint8_t hall;
hall = (PINA) & ((1 << H3_PIN) | (1 << H2_PIN) | (1 << H1_PIN));
hall >>= H1_PIN;
return hall;
}
/*! \brief Updates global desired direction flag.
*
* Running this function triggers a reading of the direction
* input pin. The desiredDirection flag is set accordingly.
*/
#pragma inline = forced
static void DesiredDirectionUpdate(void)
{
if ( (PINA & (1 << DIRECTION_PIN)) != 0 )
{
fastFlags.desiredDirection = DIRECTION_REVERSE;
}
else
{
fastFlags.desiredDirection = DIRECTION_FORWARD;
}
}
/*! \brief Updates global actual direction flag based on the two latest hall values.
*
* Calling this function with the last two hall sensor values as
* parameters triggers an update of the global actualDirection flag.
*
* \param lastHall The last hall value.
* \param newHall The current hall value.
*/
#pragma inline = forced
static void ActualDirectionUpdate(uint8_t lastHall, const uint8_t newHall)
{
//Make sure that lastHall is within bounds of table. If not, set to an
//illegal hall value, but legal table index.
if (lastHall > 7)
{
lastHall = 0;
}
if (expectedHallSequenceForward[lastHall] == newHall)
{
fastFlags.actualDirection = DIRECTION_FORWARD;
}
else if (expectedHallSequenceReverse[lastHall] == newHall)
{
fastFlags.actualDirection = DIRECTION_REVERSE;
}
else
{
PMSMflags_t tempFlags = fastFlags;
tempFlags.actualDirection = DIRECTION_UNKNOWN;
tempFlags.motorSynchronized = FALSE;
fastFlags = tempFlags;
}
}
/*! \brief Calculates step size for sine table iteration.
*
* This function calculates the step size to be used for sine
* table iteration, based on the number of 'ticks' used for each electrical
* revolution.
*
* \param ticks The number of ticks in one electrical revolution.
*
* \return The step size in 8.8 format to be used for sine table iteration.
*/
#pragma inline = forced
static uint16_t SineTableIncrementCalculate(const uint16_t ticks)
{
return (uint16_t)(((SINE_TABLE_LENGTH / 6) << 8) / ticks);
}
/*! \brief Adjusts the sine table index according to the current increment.
*
* This function increases the sine table index with the given increment
* The index is then adjusted to be within the table length.
*
* \param increment The increment (in 8.8 format) added to the sine table index.
*/
#pragma inline = forced
static void AdjustSineTableIndex(const uint16_t increment)
{
sineTableIndex += increment;
// If the table index is out of bounds, wrap the index around the table end
// to continue from the beginning. Also wrap the next sector start index.
if ((sineTableIndex >> 8) >= SINE_TABLE_LENGTH)
{
sineTableIndex -= (SINE_TABLE_LENGTH << 8);
sineTableNextSectorStart -= SINE_TABLE_LENGTH;
}
//Make copy of sineNextSectorStart to specify order of volatile access.
uint8_t nextSectorStart = sineTableNextSectorStart;
if ((sineTableIndex >> 8) > nextSectorStart)
{
sineTableIndex = (nextSectorStart << 8);
}
}
/*! \brief Sets the advance commutation.
*
* This function sets the advance commutation to be used during sine
* wave operation. An increase of one equals 1.875 degrees.
*
* \note There is no checking of the advanceCommutation input parameter, but this
* should not be set to a value above 40 to avoid overflow in the sine table
* index.
*
* \param advanceCommutation The advance commutation. (1 equals 1.875 degrees)
*/
#pragma inline = forced
static void SetAdvanceCommutation(const uint8_t advanceCommutation)
{
advanceCommutationSteps = advanceCommutation;
}
/*! \brief Enable PWM outputs by setting the port direction to output.
*
* Enables PWM outputs by setting the port direction to output for the PWM pins.
*/
#pragma inline = forced
static void EnablePWMOutputs(void)
{
DDRB |= PWM_PIN_MASK_PORTB;
}
/*! \brief Disable PWM outputs by setting the port direction to input.
*
* Disables PWM outputs by setting the port direction to input for the PWM pins.
*/
#pragma inline = forced
static void DisablePWMOutputs(void)
{
DDRB &= (~PWM_PIN_MASK_PORTB);
}
/*! \brief Updates the 'tick' counter and checks for stopped motor.
*
* This function should be run at every PWM timer overflow to ensure
* that all 'ticks' are counted. It increases the 'tick' counter
* until it reaches the maximum tick limit that corresponds to what
* is considered a stopped or stalled motor. In that case, the global
* motor stopped flag is set.
*/
#pragma inline = forced
static void CommutationTicksUpdate(void)
{
if (commutationTicks < COMMUTATION_TICKS_STOPPED)
{
commutationTicks++;
}
else
{
fastFlags.motorStopped = TRUE;
fastFlags.motorSynchronized = FALSE;
sineTableIncrement = 0;
if (fastFlags.driveWaveform != WAVEFORM_BLOCK_COMMUTATION)
{
TimerSetModeBlockCommutation();
BlockCommutate(GetDesiredDirection(), GetHall());
#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
pid_Reset_Integrator(&pidParameters);
#endif
}
}
}
/*! \brief Updates the global motor synchronized flag.
*
* This function updates the global motor synchronized flag. The motor control
* is considered to be synchronized with the motor when it is not stopped and
* the driver has detected a direction of rotation that corresponds to the
* desired direction a predefined number of times.
*/
#pragma inline = forced
static void MotorSynchronizedUpdate(void)
{
static uint8_t synchCount = 0;
PMSMflags_t tempFlags;
tempFlags = fastFlags;
if ((tempFlags.desiredDirection == tempFlags.actualDirection) &&
(tempFlags.motorStopped == FALSE) && (tempFlags.motorSynchronized == FALSE))
{
synchCount++;
if (synchCount >= SYNCHRONIZATION_COUNT)
{
fastFlags.motorSynchronized = TRUE;
}
}
else
{
synchCount = 0;
}
}
/*! \brief Returns the motor synchronized flag.
*
* This function returns the motor synchronized flag.
*
* \return The motor synchronized flag.
*
* \retval TRUE Motor control is synchronized with motor.
* \retval FALSE Motor control is not yet synchronized with motor.
*/
#pragma inline = forced
static uint8_t IsMotorSynchronized(void)
{
return (uint8_t)(fastFlags.motorSynchronized);
}
/*! \brief Get the sine table value from the small sine table.
*
* This function returns the value from the small sine table as if it
* contained information about one full phase.
*
* \param index Sine table index in the range [0..SINE_TABLE_LENGTH - 1].
*/
#if (SINE_TABLE_SIZE == SINE_TABLE_SIZE_SMALL)
#pragma inline = forced
uint8_t SineTableSmallGetValue(uint8_t index)
{
//The last 3rd of the table is zero.
if (index >= (SINE_TABLE_LENGTH * 2 / 3) )
{
return 0;
}
//The second third of the table is a mirror of the first third.
if (index >= (SINE_TABLE_LENGTH / 3) )
{
index = ((SINE_TABLE_LENGTH * 2 / 3) - 1) - index;
}
return sineTable[index];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -