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 + -
显示快捷键?