STM32控制编码器直流有刷电机增量式PID速度闭环实现

/**

  ******************************************************************************

  * 文件名程: main.c 

  * 功    能: STM32控制编码器直流有刷电机增量式PID速度闭环实现

  

  */

/* 包含头文件 ----------------------------------------------------------------*/

#include "stm32f1xx_hal.h"

#include "DCMotor/bsp_L298N.h"

#include "key/bsp_key.h"

#include "usart/bsp_debug_usart.h"

#include "DCMotor/bsp_encoder.h"

/* 私有类型定义 --------------------------------------------------------------*/

//定义PID结构体

typedef struct 

{

   __IO int      SetPoint;                                 //设定目标 Desired Value

   __IO double   Proportion;                               //比例常数 Proportional Const

   __IO double   Integral;                                 //积分常数 Integral Const

   __IO double   Derivative;                               //微分常数 Derivative Const

   __IO int      LastError;                                //Error[-1]

   __IO int      PrevError;                                //Error[-2]

}PID;

/* 私有宏定义 ----------------------------------------------------------------*/

/*************************************/

//定义PID相关宏

// 这三个参数设定对电机运行影响非常大

/*************************************/

#define  P_DATA      3.2                                 //P参数

#define  I_DATA      1.1                                //I参数

#define  D_DATA      -0.15                              //D参数

/* 私有变量 ------------------------------------------------------------------*/

__IO uint16_t time_count=0;        // 时间计数,每1ms增加一(与滴定时器频率有关)

__IO uint32_t CaptureNumber=0;     // 输入捕获数

__IO uint8_t  start_flag=0;

__IO double encoder_speed=0;

static PID sPID;

static PID *sptr = &sPID;

/* 扩展变量 ------------------------------------------------------------------*/

/* 私有函数原形 --------------------------------------------------------------*/

void IncPIDInit(void);

int IncPIDCalc(int NextPoint);

/* 函数体 --------------------------------------------------------------------*/

/**

  * 函数功能: 系统时钟配置

  * 输入参数: 无

  * 返 回 值: 无

  * 说    明: 无

  */

void SystemClock_Config(void)

{

  RCC_OscInitTypeDef RCC_OscInitStruct;

  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;  // 外部晶振,8MHz

  RCC_OscInitStruct.HSEState = RCC_HSE_ON;

  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;

  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;  // 9倍频,得到72MHz主时钟

  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;

  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;       // 系统时钟:72MHz

  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;              // AHB时钟:72MHz

  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;               // APB1时钟:36MHz

  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;               // APB2时钟:72MHz

  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);

  // HAL_RCC_GetHCLKFreq()/1000    1ms中断一次

// HAL_RCC_GetHCLKFreq()/100000 10us中断一次

// HAL_RCC_GetHCLKFreq()/1000000 1us中断一次

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);  // 配置并启动系统滴答定时器

  /* 系统滴答定时器时钟源 */

  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* 系统滴答定时器中断优先级配置 */

  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

}

/**

  * 函数功能: 主函数.

  * 输入参数: 无

  * 返 回 值: 无

  * 说    明: 无

  */

int main(void)

  /* 复位所有外设,初始化Flash接口和系统滴答定时器 */

  HAL_Init();

  /* 配置系统时钟 */

  SystemClock_Config();

  KEY_GPIO_Init();

  MX_DEBUG_USART_Init();

  

  IncPIDInit();

  

  ENCODER_TIMx_Init(); 

  HAL_TIM_Base_Start(&htimx_ENCODER);  

  

  /* 高级控制定时器初始化并配置PWM输出功能 */

  L298N_TIMx_Init();

  /* 启动定时器 */

  HAL_TIM_Base_Start(&htimx_L298N);

  

  HAL_TIM_IC_Start_IT(&htimx_ENCODER,ENCODER_TIM_CHANNELx);

  

  /* 启动定时器通道和互补通道PWM输出 */

  L298N_DCMOTOR_Contrl(1,2,0);

  start_flag=1; 

  

  printf("增量式PID算法控制电机旋转\n");

  /* 无限循环 */

  while (1)

  {

    if(KEY1_StateRead()==KEY_DOWN)  // 增速

    {

      /* 设置目标速度 */

      sptr->SetPoint =50;    

    }

    if(KEY2_StateRead()==KEY_DOWN)  // 减速

    {

      /* 设置目标速度 */

      sptr->SetPoint =300;

    }    

  }

}

/**

  * 函数功能: 系统滴答定时器中断回调函数

  * 输入参数: 无

  * 返 回 值: 无

  * 说    明: 每发生一次滴答定时器中断进入该回调函数一次

  */

void HAL_SYSTICK_Callback(void)

{

  if(start_flag) // 等待脉冲输出后才开始计时

  {

    time_count++;         // 每1ms自动增一

    if(time_count==200)

    {

      __IO uint32_t count;

      __IO int para;

      __IO double cal;

      

      /* 得到编码器计数值,数值越大说明速度越大 */

      count=CaptureNumber; 

      CaptureNumber=0;    // 清零,从零开始计数

      

      /* 计数得到增量式PID的增量数值 */

      para=IncPIDCalc(count);

      

      /* 根据增量数值调整当前电机速度 */

      if((para<-3)||(para>3)) // 不做 PID 调整,避免误差较小时频繁调节引起震荡。

      {

        PWM_Duty +=para;  

      }        

      if(PWM_Duty>899)PWM_Duty=899;  

      

      

      // 11:编码器线数(转速一圈输出脉冲数)

      // 34:电机减数比,内部电机转动圈数与电机输出轴转动圈数比,即减速齿轮比      

      cal=sptr->SetPoint;

      printf("\n设定目标速度 -> 编码器在%ds时间计数%d个脉冲\n",time_count,sptr->SetPoint);      

      printf("                相当于实际目标速度为:%0.2f圈/s\n",cal*(1000/time_count)/11/34);

      

      cal=count;

      printf("当前电机速度-> 编码器在%ds时间计数%d个脉冲\n",time_count,count);

      printf("                相当于当前实际速度为:%0.2f圈/s\n",cal*(1000/time_count)/11/34);

      

      printf("增量式PID算法计数结果值:%d   设置新的占空比为:%d\n",para,PWM_Duty);

      

      L298N_DCMOTOR_Contrl(1,2,PWM_Duty); //

      time_count=0;      

    }

  }

}

/**

  * 函数功能: 定时器输入捕获中断回调函数

  * 输入参数: htim:定时器句柄

  * 返 回 值: 无

  * 说    明: 无

  */

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

{

  CaptureNumber++;

}

/**************PID参数初始化********************************/

void IncPIDInit(void) 

{

    sptr->LastError=0;            //Error[-1]

    sptr->PrevError=0;            //Error[-2]

    sptr->Proportion=P_DATA;      //比例常数 Proportional Const

    sptr->Integral=I_DATA;        //积分常数  Integral Const

    sptr->Derivative=D_DATA;      //微分常数 Derivative Const

    sptr->SetPoint=100;           //设定目标Desired Value

}

/********************增量式PID控制设计************************************/

int IncPIDCalc(int NextPoint) 

{

  int iError,iIncpid;                                 //当前误差

  iError=sptr->SetPoint-NextPoint;                    //增量计算

  iIncpid=(sptr->Proportion * iError)                 //E[k]项

              -(sptr->Integral * sptr->LastError)     //E[k-1]项

              +(sptr->Derivative * sptr->PrevError);  //E[k-2]项

              

  sptr->PrevError=sptr->LastError;                    //存储误差,用于下次计算

  sptr->LastError=iError;

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

}

你可能感兴趣的:(嵌入式,stm32,单片机,arm)