找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3189|回复: 5
收起左侧

STM32编程实现直流有刷电机位置速度电流三闭环PID控制程序

[复制链接]
ID:831137 发表于 2021-6-27 20:31 | 显示全部楼层 |阅读模式
固件库开发的直流电机pid控制系统

单片机源程序如下:
  1. /**
  2.   ******************************************************************************
  3.   * 文件名程: BDCMOTOR.c
  4.   * 作    者: 学习小组
  5.   * 功    能: 有刷直流电机驱动板基本驱动程序
  6.   ******************************************************************************
  7.   * 说明:
  8.   ******************************************************************************
  9.   */
  10. /* 包含头文件 ----------------------------------------------------------------*/
  11. #include "BDCMotor.h"

  12. /* 私有类型定义 --------------------------------------------------------------*/
  13. /* 私有宏定义 ----------------------------------------------------------------*/
  14. /* 私有变量 ------------------------------------------------------------------*/
  15. TIM_HandleTypeDef htimx_BDCMOTOR;
  16. __IO int16_t PWM_Duty=BDCMOTOR_DUTY_ZERO;         // 占空比:PWM_Duty/BDCMOTOR_TIM_PERIOD*100%
  17. /* 扩展变量 ------------------------------------------------------------------*/
  18. /* 私有函数原形 --------------------------------------------------------------*/
  19. /* 函数体 --------------------------------------------------------------------*/
  20. /**
  21.   * 函数功能: 基本定时器硬件初始化配置
  22.   * 输入参数: htim_base:基本定时器句柄类型指针
  23.   * 返 回 值: 无
  24.   * 说    明: BDCMOTOR相关GPIO初始化配置,该函数被HAL库内部调用.
  25.   */
  26. void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
  27. {
  28.   /* BDCMOTOR相关GPIO初始化配置 */
  29.   if(htim == &htimx_BDCMOTOR)
  30.   {
  31.     GPIO_InitTypeDef GPIO_InitStruct;
  32.     /* 引脚端口时钟使能 */
  33.     __HAL_RCC_GPIOE_CLK_ENABLE();
  34.     BDCMOTOR_TIM_CH1_GPIO_CLK_ENABLE();
  35.     BDCMOTOR_TIM_CH1N_GPIO_CLK_ENABLE();
  36.     SHUTDOWN_GPIO_CLK_ENABLE();

  37.     /* BDCMOTOR输出脉冲控制引脚IO初始化 */
  38.     GPIO_InitStruct.Pin = BDCMOTOR_TIM_CH1_PIN;
  39.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  40.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  41.     GPIO_InitStruct.Alternate = GPIO_AFx_TIMx;
  42.     HAL_GPIO_Init(BDCMOTOR_TIM_CH1_PORT, &GPIO_InitStruct);
  43.    
  44.     GPIO_InitStruct.Pin = BDCMOTOR_TIM_CH1N_PIN;
  45.     HAL_GPIO_Init(BDCMOTOR_TIM_CH1N_PORT, &GPIO_InitStruct);
  46.       
  47.     __HAL_RCC_GPIOE_CLK_ENABLE();
  48.     GPIO_InitStruct.Pin = GPIO_PIN_11;
  49.     HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  50.    
  51.     GPIO_InitStruct.Pin = SHUTDOWN_PIN;
  52.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  53.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  54.     GPIO_InitStruct.Alternate = 0;
  55.     HAL_GPIO_Init(SHUTDOWN_PORT, &GPIO_InitStruct);
  56.    
  57.     /* 使能电机控制引脚 */
  58.     ENABLE_MOTOR();

  59.   }
  60. }

  61. /**
  62.   * 函数功能: BDCMOTOR定时器初始化
  63.   * 输入参数: 无
  64.   * 返 回 值: 无
  65.   * 说    明: 无
  66.   */
  67. void BDCMOTOR_TIMx_Init(void)
  68. {
  69.   TIM_ClockConfigTypeDef sClockSourceConfig;             // 定时器时钟
  70.   TIM_OC_InitTypeDef sConfigOC;
  71.   TIM_BreakDeadTimeConfigTypeDef  sBDTConfig;            // 定时器死区时间比较输出

  72.   /* 基本定时器外设时钟使能 */
  73.   BDCMOTOR_TIM_RCC_CLK_ENABLE();
  74.   
  75.   /* 定时器基本环境配置 */
  76.   htimx_BDCMOTOR.Instance = BDCMOTOR_TIMx;                                 // 定时器编号
  77.   htimx_BDCMOTOR.Init.Prescaler = BDCMOTOR_TIM_PRESCALER;                  // 定时器预分频器
  78.   htimx_BDCMOTOR.Init.CounterMode = TIM_COUNTERMODE_UP;                  // 计数方向:向上计数
  79.   htimx_BDCMOTOR.Init.Period = BDCMOTOR_TIM_PERIOD;                        // 定时器周期
  80.   htimx_BDCMOTOR.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;              // 时钟分频
  81.   htimx_BDCMOTOR.Init.RepetitionCounter = BDCMOTOR_TIM_REPETITIONCOUNTER;  // 重复计数器
  82.   /* 初始化定时器比较输出环境 */
  83.   HAL_TIM_PWM_Init(&htimx_BDCMOTOR);

  84.   /* 定时器时钟源配置 */
  85.   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;       // 使用内部时钟源
  86.   HAL_TIM_ConfigClockSource(&htimx_BDCMOTOR, &sClockSourceConfig);

  87.   /* 死区刹车配置,实际上配置无效电平是高电平 */
  88.   sBDTConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE ;
  89.   sBDTConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW ;
  90.   sBDTConfig.BreakState = TIM_BREAK_DISABLE ;
  91.   sBDTConfig.DeadTime = 0 ;
  92.   sBDTConfig.LockLevel = TIM_LOCKLEVEL_OFF ;
  93.   sBDTConfig.OffStateIDLEMode= TIM_OSSI_DISABLE ;
  94.   sBDTConfig.OffStateRunMode = TIM_OSSR_ENABLE ;
  95.   HAL_TIMEx_ConfigBreakDeadTime(&htimx_BDCMOTOR,&sBDTConfig);

  96. /* 定时器比较输出配置 */
  97.   sConfigOC.OCMode = TIM_OCMODE_PWM1;                  // 比较输出模式:PWM1模式
  98.   sConfigOC.Pulse =  PWM_Duty;                         // 占空比
  99.   sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;          // 输出极性
  100.   sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW;        // 互补通道输出极性
  101.   sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;           // 快速模式
  102.   sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;       // 空闲电平
  103.   sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;     // 互补通道空闲电平
  104.   HAL_TIM_PWM_ConfigChannel(&htimx_BDCMOTOR, &sConfigOC, TIM_CHANNEL_1);

  105.         /* 启动定时器 */
  106.   HAL_TIM_Base_Start(&htimx_BDCMOTOR);
  107. }


  108. /**
  109.   * 函数功能: 基本定时器硬件反初始化配置
  110.   * 输入参数: htim_base:基本定时器句柄类型指针
  111.   * 返 回 值: 无
  112.   * 说    明: 该函数被HAL库内部调用
  113.   */
  114. void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
  115. {
  116.   if(htim_base->Instance==BDCMOTOR_TIMx)
  117.   {
  118.     /* 基本定时器外设时钟禁用 */
  119.     BDCMOTOR_TIM_RCC_CLK_DISABLE();
  120.    
  121.     HAL_GPIO_DeInit(BDCMOTOR_TIM_CH1_PORT,BDCMOTOR_TIM_CH1_PIN);
  122.     HAL_GPIO_DeInit(BDCMOTOR_TIM_CH1N_PORT,BDCMOTOR_TIM_CH1N_PIN);
  123.   }
  124. }

  125. /************************************END OF FILE**************************/
复制代码

  1. /**
  2.   ******************************************************************************
  3.   * 文件名程: main.c
  4.   * 作    者: 学习小组
  5.   * 功    能: 位置速度电流闭环控制
  6.   ******************************************************************************
  7.   * 说明:
  8.   ******************************************************************************
  9.   */
  10. /* 包含头文件 ----------------------------------------------------------------*/
  11. #include "stm32f4xx_hal.h"
  12. #include "key.h"
  13. #include "encoder.h"
  14. #include "usartx.h"
  15. #include "adc.h"
  16. #include "BDCMotor.h"
  17. /* 私有类型定义 --------------------------------------------------------------*/
  18. typedef struct
  19. {
  20.   __IO int32_t  SetPoint;     // 设定目标 Desired Value
  21.   __IO float    SumError;     // 误差累计
  22.   __IO float    Proportion;   // 比例常数 Proportional Const
  23.   __IO float    Integral;     // 积分常数 Integral Const
  24.   __IO float    Derivative;   // 微分常数 Derivative Const
  25.   __IO int      LastError;    // Error[-1]
  26.   __IO int      PrevError;    // Error[-2]
  27. }PID_TypeDef;

  28. /* 私有宏定义 ----------------------------------------------------------------*/
  29. #define ADC_Base      8            // 取2的整数倍作为缓存区大小,得到14bits
  30. /* 使用DMA传输数据,采集n个数据点的时间是0.65ms,采样率大约是 1500 KHz */
  31. #define ADC_BUFFER    1024         // 采样数据缓存区


  32. #define SPEEDRATIO    270
  33. #define ENCODER_RESOLUTION    11
  34. #define PPR           ((SPEEDRATIO*ENCODER_RESOLUTION)*4) // Pulse/Round 每圈可捕获到的脉冲数

  35. /*************************************/
  36. // 定义PID相关宏
  37. // 这三个参数设定对电机运行影响非常大
  38. // PID参数跟采样时间息息相关
  39. /*************************************/
  40. #define  CUR_P_DATA     0.35f       // P参数
  41. #define  CUR_I_DATA     0.6f        // I参数
  42. #define  CUR_D_DATA     0.0f        // D参数
  43. #define  TARGET_CURRENT 300         // 最大电流值 300mA

  44. #define  SPD_P_DATA     4.5f        // P参数
  45. #define  SPD_I_DATA     0.5f        // I参数
  46. #define  SPD_D_DATA     0.0f        // D参数
  47. #define  TARGET_SPEED   20.0f       // 目标速度    20r/m

  48. #define  LOC_P_DATA     0.009f      // P参数
  49. #define  LOC_I_DATA     0.002f      // I参数
  50. #define  LOC_D_DATA     0.04f       // D参数
  51. #define  TARGET_LOC     (3*PPR)     // 目标位置    11880Pulse = 1r

  52. /* 私有变量 ------------------------------------------------------------------*/
  53. __IO uint8_t  Start_flag = 0;       // PID 开始标志
  54. uint32_t Motor_Dir = CW;             // 电机方向

  55. __IO int32_t tmpPWM_DutySpd = 0;
  56. __IO int32_t tmpPWM_Duty = 0;
  57. /* 用于保存转换计算后的数值 */
  58. __IO float ADC_VoltBus;                                                          // 总线电压值

  59. __IO int32_t Sample_Pulse;           // 编码器捕获值 Pulse
  60. __IO int32_t LastSample_Pulse;       // 编码器捕获值 Pulse
  61. __IO int32_t Spd_PPS;                // 速度值 Pulse/Sample
  62. __IO float Spd_RPM;                  // 速度值 r/m

  63. /* AD转换结果值 */
  64. __IO int16_t ADC_ConvValueHex[ADC_BUFFER];  // AD转换结果缓存
  65. __IO int32_t AverSum = 0;                   // 平均值的累加值
  66. __IO int32_t AverCnt = 0;                   // 平均值的计数器
  67. __IO uint32_t OffsetCnt_Flag = 0 ;          // 偏差值的计数器标志
  68. __IO int32_t  OffSetHex ;           // 偏差值
  69. /* 扩展变量 ------------------------------------------------------------------ */
  70. extern __IO uint32_t uwTick;

  71. /* PID结构体 */
  72. PID_TypeDef  cPID,sPID,lPID;               // PID参数结构体

  73. /* 扩展变量 ------------------------------------------------------------------*/
  74. /* 私有函数原形 --------------------------------------------------------------*/
  75. void PID_ParamInit(void) ;
  76. int32_t CurPIDCalc(int32_t NextPoint);
  77. int32_t SpdPIDCalc(float NextPoint);
  78. int32_t LocPIDCalc(int32_t NextPoint);
  79. int32_t ADC_GetSampleAvgN(int16_t *Data, uint32_t N );
  80. /* 函数体 --------------------------------------------------------------------*/
  81. /**
  82.   * 函数功能: 系统时钟配置
  83.   * 输入参数: 无
  84.   * 返 回 值: 无
  85.   * 说    明: 无
  86.   */
  87. void SystemClock_Config(void)
  88. {
  89.   RCC_OscInitTypeDef RCC_OscInitStruct;
  90.   RCC_ClkInitTypeDef RCC_ClkInitStruct;

  91.   __HAL_RCC_PWR_CLK_ENABLE();                                     // 使能PWR时钟

  92.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);  // 设置调压器输出电压级别1

  93.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;      // 外部晶振,8MHz
  94.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;                        // 打开HSE
  95.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;                    // 打开PLL
  96.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;            // PLL时钟源选择HSE
  97.   RCC_OscInitStruct.PLL.PLLM = 8;                                 // 8分频MHz
  98.   RCC_OscInitStruct.PLL.PLLN = 336;                               // 336倍频
  99.   RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;                     // 2分频,得到168MHz主时钟
  100.   RCC_OscInitStruct.PLL.PLLQ = 7;                                 // USB/SDIO/随机数产生器等的主PLL分频系数
  101.   HAL_RCC_OscConfig(&RCC_OscInitStruct);

  102.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  103.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  104.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;       // 系统时钟:168MHz
  105.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;              // AHB时钟: 168MHz
  106.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;               // APB1时钟:42MHz
  107.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;               // APB2时钟:84MHz
  108.   HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

  109.   HAL_RCC_EnableCSS();                                            // 使能CSS功能,优先使用外部晶振,内部时钟源为备用
  110.   
  111.         // HAL_RCC_GetHCLKFreq()/1000    1ms中断一次
  112.         // HAL_RCC_GetHCLKFreq()/100000         10us中断一次
  113.         // HAL_RCC_GetHCLKFreq()/1000000 1us中断一次
  114.   HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);                 // 配置并启动系统滴答定时器
  115.   /* 系统滴答定时器时钟源 */
  116.   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  117.   /* 系统滴答定时器中断优先级配置 */
  118.   HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
  119. }
  120.          
  121. /**
  122.   * 函数功能: 主函数.
  123.   * 输入参数: 无
  124.   * 返 回 值: 无                                                                     
  125.   * 说    明: 无
  126.   */
  127. int main(void)
  128. {
  129.   /* 复位所有外设,初始化Flash接口和系统滴答定时器 */
  130.   HAL_Init();
  131.   /* 配置系统时钟 */
  132.   SystemClock_Config();
  133.   /* 串口初始化 */
  134.   MX_USARTx_Init();
  135.   /* 按键初始化 */
  136.   KEY_GPIO_Init();
  137.   /* 编码器初始化及使能编码器模式 */
  138.   ENCODER_TIMx_Init();
  139.         /* ADC-DMA 初始化 */
  140.   MX_ADCx_Init();
  141.   /* 启动AD转换并使能DMA传输和中断 */
  142.   HAL_ADC_Start_DMA(&hadcx,(uint32_t*)ADC_ConvValueHex,ADC_BUFFER);
  143.   __HAL_DMA_DISABLE_IT(&hdma_adcx,DMA_IT_HT);
  144.   __HAL_DMA_DISABLE_IT(&hdma_adcx,DMA_IT_TE);
  145.   __HAL_DMA_DISABLE_IT(&hdma_adcx,DMA_IT_FE);
  146.   __HAL_DMA_DISABLE_IT(&hdma_adcx,DMA_IT_DME);
  147.         /* 高级控制定时器初始化并配置PWM输出功能 */
  148.   BDCMOTOR_TIMx_Init();

  149.   /* 启动定时器通道和互补通道PWM输出 */
  150.   PWM_Duty = 0;
  151.   __HAL_TIM_SET_COMPARE(&htimx_BDCMOTOR,TIM_CHANNEL_1,PWM_Duty);  // 0%

  152.   /* PID 参数初始化 */
  153.   PID_ParamInit();
  154.   /* 无限循环 */
  155.   while (1)
  156.   {
  157.     /* 停止按钮 */
  158.     if(KEY1_StateRead()==KEY_DOWN)
  159.     {
  160.       HAL_TIM_PWM_Start(&htimx_BDCMOTOR,TIM_CHANNEL_1);
  161.       HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
  162.       __HAL_TIM_SET_COMPARE(&htimx_BDCMOTOR,TIM_CHANNEL_1,0);  // 0%
  163.       Start_flag = 1;
  164.     }
  165.     if(KEY2_StateRead()==KEY_DOWN)
  166.     {
  167.       SHUTDOWN_MOTOR();
  168.       HAL_TIM_PWM_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
  169.       HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);         // 停止输出
  170.     }
  171.     if(KEY3_StateRead()==KEY_DOWN)    // 圈数+1
  172.     {
  173.       lPID.SetPoint += PPR;
  174.     }
  175.     if(KEY4_StateRead()==KEY_DOWN)    // 圈数-1
  176.     {
  177.       lPID.SetPoint -= PPR;
  178.     }
  179.   }
  180. }

  181. /**
  182.   * 函数功能: 系统滴答定时器中断回调函数
  183.   * 输入参数: 无
  184.   * 返 回 值: 无
  185.   * 说    明: 每隔一定的时间就执行pid算法
  186.   */
  187. void HAL_SYSTICK_Callback(void)
  188. {
  189.   __IO int32_t ADC_Resul= 0;
  190.   __IO float Volt_Result = 0;
  191.   __IO float ADC_CurrentValue;                                  // 电流

  192.   /* 位置环周期250ms */
  193.   if(uwTick % 250 == 0)
  194.   {
  195.     /* 获取当前位置值,编码器4倍频之后的数值 */
  196.     Sample_Pulse = (OverflowCount*CNT_MAX) + (int32_t)__HAL_TIM_GET_COUNTER(&htimx_Encoder);
  197.     /* 计算PID结果 */
  198.     if(Start_flag == 1)
  199.     {
  200.       tmpPWM_DutySpd = LocPIDCalc(Sample_Pulse);
  201.       
  202.       /* 设定速度环的目标值 */
  203.       if(tmpPWM_DutySpd >= TARGET_SPEED)
  204.         tmpPWM_DutySpd = TARGET_SPEED;
  205.       if(tmpPWM_DutySpd <= -TARGET_SPEED)
  206.         tmpPWM_DutySpd = -TARGET_SPEED;
  207.     }
  208.   }
  209.   /* 速度环周期100ms */
  210.   if(uwTick % 100 == 0)
  211.   {
  212.     /* 获得当前速度 */
  213.     Sample_Pulse = (OverflowCount*CNT_MAX) + (int32_t)__HAL_TIM_GET_COUNTER(&htimx_Encoder);
  214.     Spd_PPS = Sample_Pulse - LastSample_Pulse;
  215.     LastSample_Pulse = Sample_Pulse ;
  216.     /* 11线编码器,270减速比,一圈脉冲信号是11*270*4 PPR */
  217.     Spd_RPM = ((((float)Spd_PPS/(float)PPR)*10.0f)*(float)60);//单位是rpm
  218.    
  219.     /* 计算PID结果 */
  220.     if(Start_flag == 1)
  221.     {
  222.       sPID.SetPoint = tmpPWM_DutySpd;
  223.       tmpPWM_Duty = SpdPIDCalc(Spd_RPM);
  224.       
  225.       /* 根据速度环的计算结果判断当前运动方向 */
  226.       if(tmpPWM_Duty < 0)
  227.       {
  228.         Motor_Dir = CW;
  229.         BDDCMOTOR_DIR_CW();
  230.         tmpPWM_Duty = -tmpPWM_Duty;
  231.         
  232.       }
  233.       else
  234.       {
  235.         Motor_Dir = CCW;
  236.         BDDCMOTOR_DIR_CCW();
  237.       }
  238.       
  239.       /* 设定电流环的目标值,电流没有负数 */
  240.       if(tmpPWM_Duty >= TARGET_CURRENT)
  241.         tmpPWM_Duty = TARGET_CURRENT;
  242.     }
  243.   }
  244.   /* 电流环周期是40ms,电流单次采集周期大约是 2ms,最好不要低于2ms */
  245.   if(uwTick % 40 == 0)
  246.   {
  247.     ADC_Resul = AverSum/AverCnt ;
  248.     /* 连续采样16次以后,作为偏差值 */
  249.     OffsetCnt_Flag++;
  250.     if(OffsetCnt_Flag >= 16)
  251.     {
  252.       if(OffsetCnt_Flag == 16)
  253.       {
  254.         OffSetHex /= OffsetCnt_Flag-1;
  255.       }
  256.       OffsetCnt_Flag = 32;
  257.       ADC_Resul -= OffSetHex;//减去偏差值
  258.     }
  259.     else
  260.       OffSetHex += ADC_Resul;
  261.     /* 计算电压值和电流值 */
  262.     Volt_Result = ( (float)( (float)(ADC_Resul) * VOLT_RESOLUTION) );
  263.     ADC_CurrentValue = (float)( (Volt_Result / GAIN) / SAMPLING_RES);
  264.     if(Volt_Result<0)
  265.       Volt_Result = 0;
  266.     /* 清空计数 */
  267.     AverCnt = 0;
  268.     AverSum = 0;
  269.    
  270.     /* 计算PID结果 */
  271.     if(Start_flag == 1)
  272.     {  
  273.       cPID.SetPoint = tmpPWM_Duty ;
  274.       PWM_Duty = CurPIDCalc( (int32_t)ADC_CurrentValue);
  275.       if(PWM_Duty >= BDCMOTOR_DUTY_FULL)
  276.         PWM_Duty = BDCMOTOR_DUTY_FULL;
  277.       if(PWM_Duty <=0)
  278.           PWM_Duty = 0;
  279.       __HAL_TIM_SET_COMPARE(&htimx_BDCMOTOR,TIM_CHANNEL_1,PWM_Duty);
  280.     }
  281.     printf("LOC:%d Sped: %2.2f r/m Curr: %d mA \n",Sample_Pulse,
  282.               Spd_RPM ,(int32_t)ADC_CurrentValue);
  283.   }
  284. }


  285. /**
  286.   * 函数功能: ADC转换完成回调函数
  287.   * 输入参数: hadc:ADC外设设备句柄
  288.   * 返 回 值: 无
  289.   * 说    明: 中断一次的时间是1.479ms,利用过采样和求均值方法,提高分辨率
  290.   */
  291. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)  
  292. {
  293.   int32_t ADConv = 0 ;
  294.   /* ADC采集太快,需要先停止再处理数据 */
  295.   HAL_ADC_Stop_DMA(hadc);
  296.   /* 采集总线电压 */
  297.   SetChannelAsRank1(hadc,ADC_VOLT_CHANNEL);
  298.   HAL_ADC_Start(hadc);
  299.   
  300.   /* 去掉高和低总共SORT_NUM个采样数据,取中间部分的数据做平均 */
  301.         ADConv = ADC_GetSampleAvgN((int16_t*)&ADC_ConvValueHex,ADC_BUFFER);
  302.   
  303.   /* 累加采样结果并记录采样次数*/
  304.   AverSum += ADConv;
  305.   AverCnt++;

  306.   /* 读取总线电压值 */
  307.   HAL_ADC_Stop(hadc);
  308.   SetChannelAsRank1(hadc,ADC_CURRENT_CHANNEL);
  309.   
  310.   HAL_ADC_Start_DMA(hadc,(uint32_t*)ADC_ConvValueHex,ADC_BUFFER);
  311. }

  312. /**
  313.   * 函数功能: ADC看门狗中断回调函数
  314.   * 输入参数: ADC句柄
  315.   * 返 回 值: 无
  316.   * 说    明: 检测到电压过低或者过高的时候就调用这个函数,停止输出.
  317.   */
  318. void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc)
  319. {
  320.   /* 使能电机控制引脚 */
  321.   static uint8_t i = 0;
  322.   i++;
  323.   if(ADC_VoltBus > VOLT_LIMIT_MIN && ADC_VoltBus < VOLT_LIMIT_MAX)
  324.     i = 0 ;
  325.   else if(i>=6)
  326.   {
  327.     SHUTDOWN_MOTOR();
  328.     HAL_TIM_PWM_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
  329.     HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
  330.     PWM_Duty = 0;
  331.     printf("Bus Voltage is out of range!!\n");
  332.     printf("Please Reset the Target!\n");
  333.     while(1);
  334.   }
  335. }
  336. /**
  337.         * 函数功能: 得到N 个ADC 采样的均值
  338.         * 输入参数: 要做平均的ADC 采样数
  339.         * 返 回 值: 均值
  340.         * 说                明: 计算平均值,获得14bitsADC值
  341.         */
  342. int32_t ADC_GetSampleAvgN(int16_t *Data, uint32_t N)
  343. {
  344.         int32_t avg_sample =0x00;
  345.         uint32_t index=0x00;

  346.         /* 累加N 个ADC 采样 */
  347.         for (index = 0; index < N; index++)
  348.         {
  349.                 avg_sample += ((int32_t)Data[index]);
  350.         }
  351.         /* 计算N 个ADC 采样的均值 */
  352.         avg_sample >>= ADC_Base;
  353.         /* 返回均值 */
  354.         return avg_sample;
  355. }
  356. /******************** PID 控制设计 ***************************/
  357. /**
  358.   * 函数功能: PID参数初始化
  359.   * 输入参数: 无
  360.   * 返 回 值: 无
  361.   * 说    明: 无
  362.   */
  363. void PID_ParamInit()
  364. {
  365.     cPID.LastError = 0;            // Error[-1]
  366.     cPID.PrevError = 0;            // Error[-2]
  367.     cPID.Proportion = CUR_P_DATA;  // 比例常数 Proportional Const
  368.     cPID.Integral = CUR_I_DATA;    // 积分常数  Integral Const
  369.     cPID.Derivative = CUR_D_DATA;  // 微分常数 Derivative Const
  370.     cPID.SetPoint = TARGET_CURRENT;// 设定目标Desired Value

  371.     sPID.LastError = 0;               // Error[-1]
  372.     sPID.PrevError = 0;               // Error[-2]
  373.     sPID.Proportion = SPD_P_DATA; // 比例常数 Proportional Const
  374.     sPID.Integral = SPD_I_DATA;   // 积分常数  Integral Const
  375.     sPID.Derivative = SPD_D_DATA; // 微分常数 Derivative Const
  376.     sPID.SetPoint = TARGET_SPEED;     // 设定目标Desired Value
  377.   
  378.     lPID.LastError = 0;               // Error[-1]
  379.     lPID.PrevError = 0;               // Error[-2]
  380.     lPID.Proportion = LOC_P_DATA; // 比例常数 Proportional Const
  381.     lPID.Integral = LOC_I_DATA;   // 积分常数  Integral Const
  382.     lPID.Derivative = LOC_D_DATA; // 微分常数 Derivative Const
  383.     lPID.SetPoint = TARGET_LOC;     // 设定目标Desired Value
  384. }

  385. /**
  386.   * 函数名称:电流闭环PID控制设计
  387.   * 输入参数:当前控制量
  388.   * 返 回 值:目标控制量
  389.   * 说    明:无
  390.   */
  391. int32_t CurPIDCalc(int32_t NextPoint)
  392. {
  393.   int32_t iError,dError;
  394.   iError = cPID.SetPoint - NextPoint; //偏差
  395.   /* 设定闭环死区 */
  396.   if((iError >= -3) && (iError <= 3))
  397.     iError = 0;
  398.   
  399.   cPID.SumError += iError; //积分
  400.   dError = iError - cPID.LastError; //微分
  401.   cPID.LastError = iError;
  402.   
  403.   return (int32_t)(cPID.Proportion * (float)iError //比例项
  404.   + cPID.Integral * (float)cPID.SumError //积分项
  405.   + cPID.Derivative * (float)dError);    //微分项
  406. }

  407. /**
  408.   * 函数名称:速度闭环PID控制设计
  409.   * 输入参数:当前控制量
  410.   * 返 回 值:目标控制量
  411.   * 说    明:无
  412.   */
  413. int32_t SpdPIDCalc(float NextPoint)
  414. {
  415.   float iError,dError;
  416.   iError = sPID.SetPoint - NextPoint; //偏差
  417.   
  418.   if((iError<0.3f )&& (iError>-0.3f))
  419.     iError = 0.0f;
  420. ……………………

  421. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码


所有代码51hei提供下载:
STM32编程实现直流有刷电机位置速度电流三闭环PID控制.7z (1.54 MB, 下载次数: 133)
回复

使用道具 举报

ID:871077 发表于 2021-6-28 17:01 | 显示全部楼层
只有代码,没有原理图,作为参考吧。
回复

使用道具 举报

ID:473517 发表于 2023-3-7 16:33 | 显示全部楼层
参考一下
回复

使用道具 举报

ID:291668 发表于 2023-3-8 13:35 | 显示全部楼层
可参考! 配一下简单的说明更好了
回复

使用道具 举报

ID:613605 发表于 2023-5-23 16:13 | 显示全部楼层
有原理图吗?
回复

使用道具 举报

ID:1090151 发表于 2023-8-21 16:07 | 显示全部楼层
参考一下,求原理图
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表