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

📄 mc_drv.c

📁 无刷电机驱动原理
💻 C
📖 第 1 页 / 共 2 页
字号:

  switch(hall_state)
  {
  case 2 : Num_turn--;break;
  case 1 : Num_turn++;break;
  default: break;
  }
  hall_state = 3;
}

/**
* @brief Set the duty cycle values in the PSC according to the value calculate by the regulation loop
*/
void mc_duty_cycle(U8 level)
{
  U8 duty;
  duty = level;

  PCNF0 = SET_PLOCK | RAMP_MODE_NUMBER |(1<<PCLKSEL0)|(1<<POP0); /* set plock */
  PCNF1 = SET_PLOCK | RAMP_MODE_NUMBER |(1<<PCLKSEL1)|(1<<POP1); /* set plock */
  PCNF2 = SET_PLOCK | RAMP_MODE_NUMBER |(1<<PCLKSEL2)|(1<<POP2); /* set plock */

  // Duty = 0   => Duty Cycle   0%
  // Duty = 255 => Duty Cycle 100%

  // Set the duty cycle for PSCn0
  OCR0SAH = 0;
  OCR0SAL = 255 - duty;

  OCR1SAH = 0;
  OCR1SAL = 255 - duty;

  OCR2SAH = 0;
  OCR2SAL = 255 - duty;

  // Set the duty cycle for PSCn1 according to the PWM strategy
  #ifdef HIGH_AND_LOW_PWM
  // apply PWM on high side and low side switches
    OCR0SBH = 0;
    OCR0SBL = 255 - duty  ;

    OCR1SBH = 0;
    OCR1SBL = 255 - duty  ;

    OCR2SBH = 0;
    OCR2SBL = 255 - duty  ;
  #else
  // PWM is only applied on high side switches
  // 100% duty cycle on low side switches
    OCR0SBH = 0;
    OCR0SBL = 2;

    OCR1SBH = 0;
    OCR1SBL = 2;

    OCR2SBH = 0;
    OCR2SBL = 2;
  #endif

  Disable_interrupt();
  PCNF0 = RELEASE_PLOCK | RAMP_MODE_NUMBER |(1<<PCLKSEL0)|(1<<POP0); /* release plock */
  PCNF1 = RELEASE_PLOCK | RAMP_MODE_NUMBER |(1<<PCLKSEL1)|(1<<POP1); /* release plock */
  PCNF2 = RELEASE_PLOCK | RAMP_MODE_NUMBER |(1<<PCLKSEL2)|(1<<POP2); /* release plock */
  Enable_interrupt();
}

/**
* @brief Set the Switching Commutation value on outputs
*   according to sensor or estimation position
*
* @param position (1 to 6) and direction (FORWARD or BACKWARD)
*/
void mc_switch_commutation(U8 position)
{
  // get the motor direction to commute the right switches.
  char direction = mci_get_motor_direction();

  // Switches are commuted only if the user start the motor and
  // the speed consign is different from 0.
  if ((mci_motor_is_running()) && (mci_get_motor_speed()!=0))
  {
    mc_duty_cycle(mc_get_Duty_Cycle());
    switch(position)
    {
    // cases according to rotor position
      case HS_001:  if (direction==CCW)  {Set_Q3Q2();}
                    else                 {Set_Q5Q2();}
                    break;

      case HS_101:  if (direction==CCW)  {Set_Q5Q2();}
                    else                 {Set_Q5Q4();}
                    break;

      case HS_100:  if (direction==CCW)  {Set_Q5Q4();}
                    else                 {Set_Q1Q4();}
                    break;

      case HS_110:  if (direction==CCW)  {Set_Q1Q4();}
                    else                 {Set_Q1Q6();}
                    break;

      case HS_010:  if (direction==CCW)  {Set_Q1Q6();}
                    else                 {Set_Q3Q6();}
                    break;

      case HS_011:  if (direction==CCW)  {Set_Q3Q6();}
                    else                 {Set_Q3Q2();}
                    break;
      default : break;
      }
  }
  else
  {
    Set_none(); // all switches are switched OFF
  }
}

/********************************************************************/
/********************************************************************/
/*         TIMER 1 :    Sampling time configuration                 */
/********************************************************************/
/********************************************************************/

/**
 * @brief Timer 1 Configuration
 * Use to generate a 250us activation for main loop
 * @pre None
 * @post An interrupt all 250us
*/
void mc_config_sampling_period(void)
{
  TCCR1A = 0;         /* Normal port operation + Mode CTC */
  TCCR1B = 1<<WGM12 | 1<<CS11 | 1<<CS10 ; /* Mode CTC + prescaler 64 */
  TCCR1C = 0;
  OCR1AH = 0;
  OCR1AL = 7;         /* 31.25 礢 */
  TIMSK1=(1<<OCIE1A); /* Output compare B Match interrupt Enable */
}

/**
* @brief Timer 1 interrupt
  * Timer 1 generates a periodic interrupt for motor and main loop
  * @pre configuration of timer 1 registers
  * @post g_tick is used in main.c for regulation loop
*/
#pragma vector = TIMER1_COMPA_vect
__interrupt void timer1_periodic_interrupt(void)
{
  count_sub_tick --;
  if (count_sub_tick == 0)
  {
    g_tick = TRUE;
    count_sub_tick = 8;
  }

  if (delay_armed == TRUE)
  {
    delay_30d --;
    if (delay_30d == 0)
    {
      delay_armed = FALSE;
      delay_mask = MASK_DEMAG;
      Disable_comparator0_interrupt();
      Disable_comparator1_interrupt();
      Disable_comparator2_interrupt();
      mc_switch_commutation(HALL_SENSOR_VALUE());
    }
  }
  if (delay_mask != 0)
  {
    delay_mask --;
    if (delay_mask == 0)
    {
      ACSR = (1<<AC2IF)|(1<<AC1IF)|(1<<AC0IF);
      Enable_comparator0_interrupt();
      Enable_comparator1_interrupt();
      Enable_comparator2_interrupt();
    }
  }
}

/********************************************************************/
/********************************************************************/
/*       TIMER 0 :  Estimation speed                                */
/********************************************************************/
/********************************************************************/

/**
 * @brief Timer 0 Configuration
 * The timer 0 is used to generate an IT when an overflow occurs
 * @pre None
 * @post Timer0 initialized.
*/
void mc_config_time_estimation_speed(void)
{
  TCCR0A = 0;
  TCCR0B = (0<<CS02)|(1<<CS01)|(1<<CS00); // 64 prescaler (8us)
  TIMSK0 = (1<<TOIE0);
}

/**
  * @brief Timer0 Overflow for speed measurement
  * @pre configuration of timer 0
  * @post generate an overflow when the motor turns too slowly
*/
#pragma vector = TIMER0_OVF_vect
__interrupt void ovfl_timer(void)
{
  TCNT0=0x00;
  ovf_timer++;
  // if they are no commutation after 125 ms
  // 125 ms = (61<<8) * 8us
  if(ovf_timer >= 100)
  {
    ovf_timer = 0;
    mci_store_measured_speed(0);
  }
}

/**
* @brief estimation speed
* @pre configuration of timer 0 and define or not AVERAGE_SPEED_MEASURE in config_motor.h
* @post new value for real speed
*/
void mc_estimation_speed(void)
{
  U16 timer_value;
  U32 new_measured_speed;

  if (g_mc_read_enable==OK)
  {
    // Two 8 bits variables are use to simulate a 16 bits timers
    timer_value = (ovf_timer<<8) + TCNT0;

    /* compute delay for 30 degres */
    comp_delay_30d = (timer_value / 94) - FILTER_DELAY;
    /* apply a saturation */
    if (comp_delay_30d < (S16)MIN_DELAY) comp_delay_30d = MIN_DELAY;
    else if (comp_delay_30d > (S16)MAX_DELAY) comp_delay_30d = MAX_DELAY;

    if (timer_value == 0) {timer_value += 1 ;} // warning DIV by 0
    new_measured_speed = K_SPEED / timer_value;
    if(new_measured_speed > 255) new_measured_speed = 255; // Variable saturation


      // To avoid noise an average is realized on 16 samples
      average += new_measured_speed;
      if(count >= 16)
      {
        count = 1;
        mci_store_measured_speed(average >> 4);
        average = 0;
      }
      else count++;

    // Reset Timer 0 register and variables
    TCNT0=0x00;
    ovf_timer = 0;
    g_mc_read_enable=KO;
  }
}

/********************************************************************/
/********************************************************************/
/*     ADC         use for current measure and potentiometer...     */
/********************************************************************/
/********************************************************************/

/**
* @brief Launch the sampling procedure to get current value
* @pre Amplifier and IT initialization
* @post Set the End Of Conversion flag
*/
#pragma vector = ADC_vect
__interrupt void ADC_EOC(void)
{
  if(State == CONV_CURRENT) mci_store_potentiometer_value(Adc_get_8_bits_result());
  if(State == CONV_POT) mci_store_measured_current(Adc_get_10_bits_result());
  ADC_State = FREE;
}

/**
* @brief Launch the scheduler for the ADC
* @pre none
* @post Get Channel 6 and 12 results for Potentiometer and current values.
*/
void mc_ADC_Scheduler(void)
{
  switch(State)
  {
  case CONV_INIT :
    init_adc();
    init_amp1();
    ADC_State = FREE;
    State = CONV_POT;
    break;

  case CONV_POT :
    if(ADC_State == FREE)
    {
      ADC_State = BUSY;
      State= CONV_CURRENT;
      Left_adjust_adc_result();
      Start_conv_channel(6);
    }
    break;

  case CONV_CURRENT :
    if(ADC_State == FREE)
    {
      ADC_State = BUSY;
      State = CONV_POT;
      Right_adjust_adc_result();
      Start_amplified_conv_channel(12);
//      Start_conv_channel(9);
    }
    break;
  }

}
/********************************************************************/
/********************************************************************/
/*      Over Current Detection                                      */
/********************************************************************/
/********************************************************************/


/**
* @brief Set the Over Current threshold
* @pre DAC initialization
* @post the Over Current threshold is set.
*/
void mc_set_Over_Current(U8 Level)
{
  Set_dac_8_bits(Level);
}


/********************************************************************/
/********************************************************************/
/*                              Number of turns calculation         */
/********************************************************************/
/********************************************************************/

/**
* @brief Get the number of rotor rotation
* @pre none
* @post Get the 32bits signed number of turns
*/
S32 mc_get_Num_Turn()
{
  return Num_turn;
}

/**
* @brief Reset the number of rotor rotation
* @pre none
* @post Number of turns = 0
*/
void mc_reset_Num_Turn()
{
  Num_turn = 0;
}

⌨️ 快捷键说明

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