欢迎光临散文网 会员登陆 & 注册

STM32控制编码器电机速度闭环实现

2021-06-23 10:39 作者:老-_-白  | 我要投稿


STM32编程直流有刷电机PID速度闭环精准变速控制 电机控制例程分享 (第十一期)
STM32编程利用HMI做上位机调参精准PID闭环控制 (第十二期)
模块连接图(够乱的吧 *-*)

利用STM32高级定时器的互补输出模式驱动电机运行

/**

  * 函数功能: BDCMOTOR定时器初始化

  * 输入参数: 无

  * 返 回 值: 无

  * 说    明: 无

  */

void BDCMOTOR_TIMx_Init(void)

{

  TIM_ClockConfigTypeDef sClockSourceConfig;             // 定时器时钟

  TIM_OC_InitTypeDef sConfigOC;                          // 定时器通道比较输出

  TIM_BreakDeadTimeConfigTypeDef  sBDTConfig;            // 定时器死区时间比较输出


  /* 基本定时器外设时钟使能 */

  BDCMOTOR_TIM_RCC_CLK_ENABLE();


  /* 定时器基本环境配置 */

  htimx_BDCMOTOR.Instance = BDCMOTOR_TIMx;                                 // 定时器编号

  htimx_BDCMOTOR.Init.Prescaler = BDCMOTOR_TIM_PRESCALER;                  // 定时器预分频器

  htimx_BDCMOTOR.Init.CounterMode = TIM_COUNTERMODE_UP;                  // 计数方向:向上计数

  htimx_BDCMOTOR.Init.Period = BDCMOTOR_TIM_PERIOD;                        // 定时器周期

  htimx_BDCMOTOR.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;              // 时钟分频

  htimx_BDCMOTOR.Init.RepetitionCounter = BDCMOTOR_TIM_REPETITIONCOUNTER;  // 重复计数器

  /* 初始化定时器比较输出环境 */

  HAL_TIM_PWM_Init(&htimx_BDCMOTOR);


  /* 定时器时钟源配置 */

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;       // 使用内部时钟源

  HAL_TIM_ConfigClockSource(&htimx_BDCMOTOR, &sClockSourceConfig);


  /* 死区刹车配置,配置有效电平是低电平 */

  sBDTConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE ;

  sBDTConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW ;

  sBDTConfig.BreakState = TIM_BREAK_DISABLE ;

  sBDTConfig.DeadTime = 0 ;

  sBDTConfig.LockLevel = TIM_LOCKLEVEL_OFF ;

  sBDTConfig.OffStateIDLEMode= TIM_OSSI_DISABLE ;

  sBDTConfig.OffStateRunMode = TIM_OSSR_ENABLE ;

  HAL_TIMEx_ConfigBreakDeadTime(&htimx_BDCMOTOR,&sBDTConfig);


  /* 定时器比较输出配置 */

  sConfigOC.OCMode = TIM_OCMODE_PWM1;                  // 比较输出模式:PWM1模式

  sConfigOC.Pulse =  PWM_Duty;                         // 占空比

  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;          // 输出极性

  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW;        // 互补通道输出极性

  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;           // 快速模式

  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;       // 空闲电平

  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;     // 互补通道空闲电平

  HAL_TIM_PWM_ConfigChannel(&htimx_BDCMOTOR, &sConfigOC, TIM_CHANNEL_1);


  HAL_TIM_Base_Start(&htimx_BDCMOTOR);

}

驱动模块连接图

电机控制的几个基本操作又一下几个函数完成

/**

  * 函数功能: 设置电机速度

  * 输入函数: Duty,输出脉冲占空比

  * 返 回 值: 无

  * 说    明: 无

  */

void SetMotorSpeed(int16_t Duty)

{

  __HAL_TIM_SetCompare(&htimx_BDCMOTOR,TIM_CHANNEL_1,Duty);

}


/**

  * 函数功能: 设置电机转动方向

  * 输入函数: Dir,电机转动方向

  * 返 回 值: 无

  * 说    明: 无

  */

void SetMotorDir(int16_t Dir)

{

  if(Dir)

  {

    HAL_TIM_PWM_Start(&htimx_BDCMOTOR,TIM_CHANNEL_1);

    HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);         // 停止输出

  }

  else

  {

    HAL_TIM_PWM_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);

    HAL_TIMEx_PWMN_Start(&htimx_BDCMOTOR,TIM_CHANNEL_1);         // 停止输出

  }

}


/**

  * 函数功能: 设置电机停止

  * 输入函数: 无

  * 返 回 值: 无

  * 说    明: 无

  */

void SetMotorStop()

{

  HAL_TIM_PWM_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);

  HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);         // 停止输出

}

/**

  * 函数功能: 设置电机启动

  * 输入函数: 无

  * 返 回 值: 无

  * 说    明: 无

  */

void SetMotorStart()

{

  HAL_TIM_PWM_Start(&htimx_BDCMOTOR,TIM_CHANNEL_1);

  HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);         // 停止输出

}

编码器电机连接图

电机速度控制反馈信号是利用STM32定时器编码器模式读取电机编码器脉冲信号

/**

  * 函数功能: 通用定时器初始化并配置编码器模式

  * 输入参数: 无

  * 返 回 值: 无

  * 说    明: 无

  */

void ENCODER_TIMx_Init(void)

{

  ENCODER_TIM_RCC_CLK_ENABLE();

  htimx_Encoder.Instance = ENCODER_TIMx;

  htimx_Encoder.Init.Prescaler = ENCODER_TIM_PRESCALER;

  htimx_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP;

  htimx_Encoder.Init.Period = ENCODER_TIM_PERIOD;

  htimx_Encoder.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;


  sEncoderConfig.EncoderMode        = TIM_ENCODERMODE_TIx;

  sEncoderConfig.IC1Polarity        = TIM_ICPOLARITY_RISING;

  sEncoderConfig.IC1Selection       = TIM_ICSELECTION_DIRECTTI;

  sEncoderConfig.IC1Prescaler       = TIM_ICPSC_DIV1;

  sEncoderConfig.IC1Filter          = 0;


  sEncoderConfig.IC2Polarity        = TIM_ICPOLARITY_RISING;

  sEncoderConfig.IC2Selection       = TIM_ICSELECTION_DIRECTTI;

  sEncoderConfig.IC2Prescaler       = TIM_ICPSC_DIV1;

  sEncoderConfig.IC2Filter          = 0;

  __HAL_TIM_SET_COUNTER(&htimx_Encoder,0);


  HAL_TIM_Encoder_Init(&htimx_Encoder, &sEncoderConfig);


  __HAL_TIM_CLEAR_IT(&htimx_Encoder, TIM_IT_UPDATE);  // 清除更新中断标志位

  __HAL_TIM_URS_ENABLE(&htimx_Encoder);               // 仅允许计数器溢出才产生更新中断

  __HAL_TIM_ENABLE_IT(&htimx_Encoder,TIM_IT_UPDATE);  // 使能更新中断


  HAL_NVIC_SetPriority(ENCODER_TIM_IRQn, 0, 0);

  HAL_NVIC_EnableIRQ(ENCODER_TIM_IRQn);


  HAL_TIM_Encoder_Start(&htimx_Encoder, TIM_CHANNEL_ALL);

}

编码器电机PID速度闭环控制


编码器电机速度闭环控制由PID算法在调控周期里进行反馈调整

/**

  * 函数名称:速度闭环PID控制设计

  * 输入参数:当前控制量

  * 返 回 值:目标控制量

  * 说    明:无

  */

int32_t SpdPIDCalc(float NextPoint)

{

  float iError,iIncpid;

  iError = (float)sPID.SetPoint - NextPoint; //偏差


  if((iError<0.2f )&& (iError>-0.2f))

    iError = 0.0f;


  iIncpid=(sPID.Proportion * iError)                 //E[k]项

              -(sPID.Integral * sPID.LastError)     //E[k-1]项

              +(sPID.Derivative * sPID.PrevError);  //E[k-2]项


  sPID.PrevError = sPID.LastError;                    //存储误差,用于下次计算

  sPID.LastError = iError;

  return(iIncpid);                                    //返回增量值


}


  /* 速度环周期100ms */

  if(uwTick % pid_n_s == 0) //到达一个调控周期

  {

    //Spd_Pulse  编码器捕获值 Pulse = 累计捕获中断次数*65535 + 通过编码器接口HAL接口读取的脉冲数

Spd_Pulse = (OverflowCount*CNT_MAX) + (int32_t)__HAL_TIM_GET_COUNTER(&htimx_Encoder);

    //检测周期里累计的脉冲数=编码器捕获的脉冲数 - 上次捕获的脉冲值

    Spd_PPS = Spd_Pulse - LastSpd_Pulse;

//记录为上次捕获的脉冲值(为下次计算使用

    LastSpd_Pulse = Spd_Pulse ;


    /*变量pid_1=(圈数/周期)*/

float pid_1 = (float)Spd_PPS/(float)PPR ;

//pid_1:pid_n_s周期内电机转动的圈数=周期内捕获的脉冲数 / 每圈的脉冲数

/*变量pid_2=(转/毫秒)*/

float pid_2 = pid_1 / (float)pid_n_s ;

//pid_2:计算实际测量速度(转/毫秒)=周期内转过的圈数 / 周期时间值 (因为周期单位为毫秒)


/*Spd_RPM=(转/秒)*/

Spd_RPM = pid_2 * (float)1000 ;//单位转换为(转/秒)


   

    /* 计算PID结果 */

    if(Start_flag == 1)

    {

      PWM_Duty += SpdPIDCalc(Spd_RPM);


      /* 判断当前运动方向 */

      if(PWM_Duty < 0)

      {

        Motor_Dir = CW;

        BDDCMOTOR_DIR_CW();

        SetMotorSpeed(-PWM_Duty);

      }

      else

      {

        Motor_Dir = CCW;

        BDDCMOTOR_DIR_CCW();

        SetMotorSpeed(PWM_Duty);

      }

    }

  }

编码器电机PID速度闭环上位机调试


STM32控制编码器电机速度闭环实现的评论 (共 条)

分享到微博请遵守国家法律