main.c
来自「ATtiny261 461 861 这份资料介绍了执行Attiny261 461」· C语言 代码 · 共 1,105 行 · 第 1/3 页
C
1,105 行
}
#endif
/*! \brief Updates the PWM outputs according to the current position and amplitude.
*
* This functon uses the current position and amplitude setting to update
* the PWM outputs. This version uses the large sine table (3 * 192 elements).
*/
#if (SINE_TABLE_SIZE == SINE_TABLE_SIZE_LARGE)
#pragma inline = forced
static void SineOutputUpdate(void)
{
uint8_t const __flash * sineTablePtr = sineTable;
uint16_t temp;
//Add sine table offset to pointer. Must be multiplied by 3, since one
//value for each phase is stored in the table.
//sineTablePtr += (uint8_t)(sineTableIndex >> 8) * 3;
{
uint8_t tempIndex = (uint8_t)(sineTableIndex >> 8);
sineTablePtr += tempIndex;
sineTablePtr += tempIndex;
sineTablePtr += tempIndex;
}
//Calculate output duty cycles. Since one phase is always zero, the scaling
//is only performed on the two non-zero phases, saving one multiply.
//Calculate U phase output duty cycle.
temp = *sineTablePtr++;
if (temp != 0)
{
temp = MultiplyUS15x8(amplitude, temp);
}
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_U, temp);
//Calculate U + 240 degree phase output duty cycle.
temp = *sineTablePtr++;
if (temp != 0)
{
temp = MultiplyUS15x8(amplitude, temp);
}
if (GetDesiredDirection() == DIRECTION_FORWARD)
{
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_V, temp);
}
else
{
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_W, temp);
}
//Calculate U + 120 degree phase output duty cycle.
temp = *sineTablePtr++;
if (temp != 0)
{
temp = MultiplyUS15x8(amplitude, temp);
}
if (GetDesiredDirection() == DIRECTION_FORWARD)
{
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_W, temp);
}
else
{
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_V, temp);
}
}
#endif
/*! \brief Updates the PWM outputs according to the current position and amplitude.
*
* This functon uses the current position and amplitude setting to update
* the PWM outputs. This version uses the small sine table (64 elements).
*/
#if (SINE_TABLE_SIZE == SINE_TABLE_SIZE_SMALL)
#pragma inline = forced
static void SineOutputUpdate(void)
{
uint16_t temp;
uint8_t tempIndex;
//Calculate U phase output duty cycle.
tempIndex = (uint8_t)(sineTableIndex >> 8);
temp = SineTableSmallGetValue(tempIndex);
if (temp != 0)
{
temp = MultiplyUS15x8(amplitude, temp);
}
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_U, temp);
//Calculate U phase + 120 degree output duty cycle.
tempIndex += (SINE_TABLE_LENGTH / 3);
if (tempIndex >= SINE_TABLE_LENGTH)
{
tempIndex -= SINE_TABLE_LENGTH;
}
temp = SineTableSmallGetValue(tempIndex);
if (temp != 0)
{
temp = MultiplyUS15x8(amplitude, temp);
}
if (GetDesiredDirection() == DIRECTION_FORWARD)
{
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_W, temp);
}
else
{
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_V, temp);
}
//Calculate U phase + 240 degree output duty cycle.
tempIndex += (SINE_TABLE_LENGTH / 3);
if (tempIndex >= SINE_TABLE_LENGTH)
{
tempIndex -= SINE_TABLE_LENGTH;
}
temp = SineTableSmallGetValue(tempIndex);
if (temp != 0)
{
temp = MultiplyUS15x8(amplitude, temp);
}
if (GetDesiredDirection() == DIRECTION_FORWARD)
{
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_V, temp);
}
else
{
TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_W, temp);
}
}
#endif
/*! \brief Hall sensor change interrupt service routine.
*
* This ISR is run every time one of the hall sensor inputs changes value.
* The responsibilities of this ISR are:
* - Synchronize sine wave generation to hall sensors.
* - Block commutation.
* - Direction control.
* - Synchronization control.
* - Sine table increment calculation.
* - Stop detection.
*/
#pragma vector = PCINT0_vect
__interrupt void HallChangeISR()
{
static uint8_t lastHall = 0xff;
uint8_t hall;
hall = GetHall();
//Make sure that the hall sensors really changed.
if (hall == lastHall)
{
return;
}
MotorSynchronizedUpdate();
uint8_t synch = IsMotorSynchronized();
if ((fastFlags.driveWaveform != WAVEFORM_SINUSOIDAL) && (synch))
{
TimerSetModeSinusoidal();
}
//If sinusoidal driving is used, synchronize sine wave generation to the
//current hall sensor value. Advance commutation (lead angle) is also
//added in the process.
if (fastFlags.driveWaveform == WAVEFORM_SINUSOIDAL)
{
uint16_t tempIndex;
if (GetDesiredDirection() == DIRECTION_FORWARD)
{
tempIndex = (CSOffsetsForward[hall] + advanceCommutationSteps) << 8;
}
else
{
tempIndex = (CSOffsetsReverse[hall] + advanceCommutationSteps) << 8;
}
sineTableIndex = tempIndex;
//Adjust next sector start index. It might be set to a value larger than
//SINE_TABLE_LENGTH at this point. This is adjusted in AdjustSineTableIndex
//and should not be done here, as it will cause problems when advance
//commutation is used.
sineTableNextSectorStart = (tempIndex >> 8) + TABLE_ELEMENTS_PER_COMMUTATION_SECTOR;
}
//If block commutation is used. Commutate according to hall signal.
else if (fastFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION)
{
BlockCommutate(GetDesiredDirection(), hall);
}
//Update the actual direction flag.
ActualDirectionUpdate(lastHall, hall);
lastHall = hall;
//Calculate new step size for sine wave generation and reset commutation
//timer.
sineTableIncrement = SineTableIncrementCalculate(commutationTicks);
commutationTicks = 0;
//Since the hall sensors are changing, the motor can not be stopped.
fastFlags.motorStopped = FALSE;
}
/*! \brief Timer/counter1 overflow interrupt service routine
*
* This ISR is run every time Timer/counter1 overflows. This is the same moment
* as the double buffered PWM outputs are updated.
*
* The responsibilities of this ISR are:
* - Sine wave modulation update.
* - Direction command input.
* - Stop detection.
* - Speed controller timing.
*/
#pragma vector = TIM1_OVF_vect
__interrupt void Timer1OverflowISR()
{
PORTA |= (1 << PA4);
if (fastFlags.driveWaveform == WAVEFORM_SINUSOIDAL)
{
AdjustSineTableIndex(sineTableIncrement);
SineOutputUpdate();
}
else if (fastFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION)
{
uint16_t blockCommutationDuty = amplitude * BLOCK_COMMUTATION_DUTY_MULTIPLIER;
if (blockCommutationDuty > PWM_TOP_VALUE)
{
blockCommutationDuty = PWM_TOP_VALUE;
}
BlockCommutationSetDuty(blockCommutationDuty);
}
//Update desired direction flag.
DesiredDirectionUpdate();
static uint8_t lastDesiredDirection = 0xff;
if ( (fastFlags.desiredDirection != lastDesiredDirection))
{
#if (TURN_MODE == TURN_MODE_COAST)
//Disable driver signals to let motor coast. The motor will automatically
//start once it is synchronized or stopped.
DisablePWMOutputs();
fastFlags.motorSynchronized = FALSE;
fastFlags.driveWaveform = WAVEFORM_UNDEFINED;
#endif
#if (TURN_MODE == TURN_MODE_BRAKE)
//Set motor in brake mode. The motor will automatically start once it is
//synchronized or stopped.
fastFlags.motorSynchronized = FALSE;
if (fastFlags.actualDirection != DIRECTION_UNKNOWN)
{
TimerSetModeBrake(); // Automatically sets driveWaveform.
}
#endif
lastDesiredDirection = fastFlags.desiredDirection;
}
CommutationTicksUpdate();
if (speedControllerTimer > 0)
{
speedControllerTimer--;
}
PORTA &= ~(1 << PA4);
}
/*! \brief Hardware fault protection interrupt.
*
* This ISR will be run every time the hardware fault protection disables the
* PWM outputs. The required action to this event will be different from
* application to application. Here, a delay is inserted, before the PWM
* outputs are once again enabled.
*/
#pragma vector = FAULT_PROTECTION
__interrupt void FaultProtectionISR()
{
__delay_cycles(10000000);
TCCR1D |= (1 << FPEN1);
#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
pid_Reset_Integrator(&pidParameters);
#endif
}
/*! \brief Fast unsigned multiply of a 15 bit number with an 8 bit number with 15 bit result.
*
* This function performs a fast unsigned multiply of a 15 bit number with an 8 bit
* number. The lower byte of the result is discarded in the process, returning
* the 15 most significant bytes as result. The function has a fixed execution
* time of 50 CPU clock cycles.
*
* \param m15 15 bit unsigned value (0x0000-0x7fff)
* \param m8 8 bit unsigned value (0x00-0xff)
*
* \returns 15 most significant bits of m15 * m8 (m15 * m8 / 256)
*/
#pragma inline = forced
static unsigned int MultiplyUS15x8(const uint16_t m15, const uint8_t m8)
{
unsigned int result = 0x0000;
if (m8 & (1 << 0))
{
result += m15;
}
result >>= 1;
if (m8 & (1 << 1))
{
result += m15;
}
result >>= 1;
if (m8 & (1 << 2))
{
result += m15;
}
result >>= 1;
if (m8 & (1 << 3))
{
result += m15;
}
result >>= 1;
if (m8 & (1 << 4))
{
result += m15;
}
result >>= 1;
if (m8 & (1 << 5))
{
result += m15;
}
result >>= 1;
if (m8 & (1 << 6))
{
result += m15;
}
result >>= 1;
if (m8 & (1 << 7))
{
result += m15;
}
result >>= 1;
return result;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?