找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 2935|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

57&42步進(jìn)電機(jī)_速度閉環(huán)_位置式PID STM32源程序

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:301684 發(fā)表于 2019-9-25 09:50 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
黑石H7開發(fā)板步進(jìn)電機(jī)驅(qū)動(dòng)  親測(cè)可用
  1. #include "stm32h7xx_hal.h"
  2. #include "bsp_led.h"
  3. #include "bsp_key.h"
  4. #include "bsp_debug_usart.h"
  5. #include "bsp_stepmotor.h"
  6. #include "bsp_encoder.h"
  7. #include <string.h>
  8. #include <math.h>
  9. #include <stdbool.h>
  10. #include <stdlib.h>

  11. /* 私有類型定義 --------------------------------------------------------------*/
  12. typedef struct
  13. {
  14.   __IO float    SetPoint;    // 目標(biāo)值  單位:r/m
  15.   __IO int32_t  LastError;   // 前一次誤差   
  16.   __IO int32_t  PrevError;   // 前兩次誤差
  17.   __IO int32_t  SumError;    // 累計(jì)誤差
  18.   float    Proportion;       // Kp系數(shù)
  19.   float    Integral;         // Ki系數(shù)
  20.   float    Derivative;       // Kd系數(shù)
  21. }PID_Typedef;

  22. /* 私有宏定義 ----------------------------------------------------------------*/
  23. #define    PID_DEFAULT_P          0.4f  //
  24. #define    PID_DEFAULT_I          0.2f  //
  25. #define    PID_DEFAULT_D          0.0f  //
  26. #define    SPEED                  5.3f  // 移動(dòng)速度 mm/s

  27. #define    MM_ROUND               5   // 絲桿導(dǎo)程 mm/r
  28. #define    INTERVAL               20  //  采樣和PID計(jì)算時(shí)間間隔 ms

  29. /* 私有變量 ------------------------------------------------------------------*/

  30. __IO static PID_Typedef vPID; // 速度環(huán)PID結(jié)構(gòu)體

  31. __IO uint16_t time_count = 0; // 時(shí)間計(jì)數(shù),每1ms增加一(與滴答定時(shí)器頻率有關(guān))
  32. __IO uint8_t Time_Flag   = 0; // 任務(wù)時(shí)間標(biāo)記
  33. bool Start_flag = false;      // 啟動(dòng)/停止

  34. /* 擴(kuò)展變量 ------------------------------------------------------------------*/

  35. /* 私有函數(shù)原形 --------------------------------------------------------------*/

  36. static void SystemClock_Config( void );
  37. static void CPU_CACHE_Enable( void );

  38. /* 函數(shù)體 --------------------------------------------------------------------*/
  39.   
  40. /**
  41.   * 函數(shù)功能:位置式PID速度環(huán)計(jì)算
  42.   * 輸入?yún)?shù): @NextPoint    由編碼器得到的計(jì)數(shù)值
  43.   *           @TargetVal    目標(biāo)值
  44.   * 返 回 值:經(jīng)過PID運(yùn)算得到的增量值
  45.   * 說    明:位置式 PID 速度環(huán)控制設(shè)計(jì),計(jì)算得到的結(jié)果仍然是速度值
  46.   */
  47. float IncPIDCalc(int NextPoint,float TargetVal)       //臨時(shí)變量,期望值
  48. {
  49.   float iError = 0,iIncpid = 0;                       //當(dāng)前誤差
  50.   
  51.   iError = TargetVal - NextPoint;                     // 增量計(jì)算
  52.   if((iError < 0.5f)&&(iError>-0.5f))
  53.     iError = 0;                                       // |e| < 0.5,不做調(diào)整
  54.   
  55.   vPID.PrevError = iError - vPID.LastError;
  56.   vPID.SumError += iError;
  57.   iIncpid=(vPID.Proportion * iError)                  // E[k]項(xiàng)
  58.               +(vPID.Integral * vPID.SumError)        // E[k-1]項(xiàng)
  59.               +(vPID.Derivative * vPID.PrevError);    // E[k-2]項(xiàng)
  60.   
  61.   vPID.PrevError = vPID.LastError;                    // 存儲(chǔ)誤差,用于下次計(jì)算
  62.   vPID.LastError = iError;
  63.   return(iIncpid);                                    // 返回增量值
  64. }

  65. /**
  66.   * 函數(shù)功能: PID結(jié)構(gòu)體初始化
  67.   * 輸入?yún)?shù): 無
  68.   * 返 回 值: 無
  69.   * 說    明: 初始化PID參數(shù)
  70.   */
  71. void Init_PIDStruct()
  72. {
  73.   vPID.SetPoint   = SPEED;          // 目標(biāo)值  單位:mm/s
  74.   vPID.Proportion = PID_DEFAULT_P;  // Kp系數(shù)
  75.   vPID.Integral   = PID_DEFAULT_I;  // Ki系數(shù)
  76.   vPID.Derivative = PID_DEFAULT_D;  // Kd系數(shù)
  77.   vPID.LastError  = 0;
  78.   vPID.PrevError  = 0;
  79.   vPID.SumError   = 0;
  80. }
  81. /**
  82.   * 函數(shù)功能: 主函數(shù).
  83.   * 輸入?yún)?shù): 無
  84.   * 返 回 值: 無
  85.   * 說    明: 無
  86.   */
  87. int main(void)
  88. {
  89.   float     Exp_Val     = 0;  // PID計(jì)算出來的期望值
  90.   float     Vel_Target  = 0;; // 速度目標(biāo)值
  91.   int16_t   MSF = 0;          // 電機(jī)反饋速度
  92.   int32_t   Enc_Cap     = 0;  // 編碼器輸入捕獲數(shù)
  93.   int32_t   lastEnc_Cap = 0;  // 編碼器上一次捕獲值
  94.   
  95.   CPU_CACHE_Enable();
  96.   /* 復(fù)位所有外設(shè),初始化Flash接口和系統(tǒng)滴答定時(shí)器 */
  97.   HAL_Init();
  98.   /* 配置系統(tǒng)時(shí)鐘 */
  99.   SystemClock_Config();
  100.   /* 板載LED,按鍵初始化 */
  101.   LED_GPIO_Init();
  102.   KEY_GPIO_Init();
  103.   /* 初始化PID參數(shù)結(jié)構(gòu)體 */
  104.   Init_PIDStruct();
  105.   /* 調(diào)試串口初始化 */
  106.   MX_DEBUG_UART_Init();

  107.   /* 編碼器定時(shí)器初始化并配置輸入捕獲功能 */
  108.   ENCODER_TIMx_Init();
  109.   /* 啟動(dòng)編碼器接口 */
  110.   HAL_TIM_Encoder_Start(&htimx_Encoder, TIM_CHANNEL_ALL);
  111.   
  112.   HAL_Delay(10);
  113.   
  114.   /* 步進(jìn)電機(jī)定時(shí)器初始化*/
  115.   SMOTOR1_TIMx_Init();
  116.   
  117.   /* 首先禁止步進(jìn)電機(jī)動(dòng)作*/
  118.   SMotor_Set_State(MOTOR_DISABLE);
  119.   /* 比較輸出和中斷 */
  120.   HAL_TIM_OC_Stop_IT(&htimx_SMotor1,TIM_CHANNEL_1);
  121.   
  122.   /* 移動(dòng)速度轉(zhuǎn)換為PID的目標(biāo)值
  123.    * 目標(biāo)值是每個(gè)采樣周期的編碼器計(jì)數(shù)值,SetPoint是移動(dòng)速度(mm/s),INTERVAL是采樣周期間隔
  124.    * 1mm/s對(duì)應(yīng)的編碼器計(jì)數(shù)值是 ENCODER_RESOLUTION/MM_ROUND -> 2400/5 = 480 Hz
  125.    * 每個(gè)采樣周期之間的編碼器計(jì)數(shù)值就是 480/(1000/INTERVAL) = 9.6f
  126.    * SetPoint*9.6 就是 SetPoint mm/s 對(duì)應(yīng)的采樣周期間隔編碼器計(jì)數(shù)值
  127.    */
  128.   Vel_Target = round(fabs(vPID.SetPoint) * (ENCODER_RESOLUTION/MM_ROUND)/(1000/INTERVAL)  );//每單位采樣周期內(nèi)的脈沖數(shù)(頻率)
  129.   
  130.   __HAL_DBGMCU_FREEZE_TIM8();// debug 的時(shí)候停止定時(shí)器時(shí)鐘
  131.   __HAL_DBGMCU_FREEZE_TIM2();// debug 的時(shí)候停止定時(shí)器時(shí)鐘
  132.   while (1)
  133.   {
  134.    
  135.     /* KEY1啟動(dòng)電機(jī),并且使能PID計(jì)算 */
  136.     if(KEY1_StateRead() == KEY_DOWN)
  137.     {
  138.       SMotor_Set_State(MOTOR_ENABLE);
  139.       Exp_Val = 0;
  140.       Init_PIDStruct();
  141.       if(vPID.SetPoint < 0 )
  142.         SMotor_Set_Dir( MOTOR_DIR_CCW );
  143.       else
  144.         SMotor_Set_Dir( MOTOR_DIR_CW );
  145.       SMotor_Set_Speed(0.01); // 低速啟動(dòng)
  146.       HAL_TIM_OC_Start_IT(&htimx_SMotor1,TIM_CHANNEL_1);
  147.       Start_flag = true;           // 啟動(dòng)/停止
  148.       printf("啟動(dòng)PID計(jì)算\n");
  149.       printf("設(shè)置的目標(biāo)值是 %f mm/s \n",vPID.SetPoint);//
  150.       printf("對(duì)應(yīng)的編碼器計(jì)數(shù)值是 %d pulse/s \n",(int32_t)Vel_Target*(1000/INTERVAL));//
  151.     }
  152.     /* KEY2停止電機(jī),并且停止PID計(jì)算 */
  153.     if(KEY2_StateRead() == KEY_DOWN)
  154.     {
  155.       SMotor_Set_State(MOTOR_DISABLE);
  156.       HAL_TIM_OC_Stop_IT(&htimx_SMotor1,TIM_CHANNEL_1);
  157.       Start_flag = false;           // 啟動(dòng)/停止
  158.     }
  159.     /* KEY3/KEY4用于調(diào)控電機(jī)位置 */
  160.     if(KEY3_StateRead() == KEY_DOWN)
  161.     {
  162.       Start_flag = false;          // 啟動(dòng)/停止
  163.       SMotor_Set_State( MOTOR_ENABLE );
  164.       SMotor_Set_Dir( MOTOR_DIR_CW );
  165.       SMotor_Set_Speed( 160 );     //設(shè)置低速啟動(dòng)
  166.       HAL_TIM_OC_Start_IT(&htimx_SMotor1, SMOTOR1_PUL_TIMx_CHANNELx);
  167.     }
  168.     if(KEY4_StateRead() == KEY_DOWN)
  169.     {
  170.       Start_flag = false;          // 啟動(dòng)/停止
  171.       SMotor_Set_State( MOTOR_ENABLE );
  172.       SMotor_Set_Dir( MOTOR_DIR_CCW );
  173.       SMotor_Set_Speed( 160 );     // 設(shè)置低速啟動(dòng)
  174.       HAL_TIM_OC_Start_IT(&htimx_SMotor1, SMOTOR1_PUL_TIMx_CHANNELx);
  175.     }
  176.     // 采樣和控制周期為20ms
  177.     if(Time_Flag & 0x01)
  178.     {
  179.       //獲得編碼器的脈沖值
  180.       Enc_Cap  = YS_Encoder_GetCounting();

  181.       //M法 測(cè)速度
  182.       MSF = Enc_Cap - lastEnc_Cap;
  183.       lastEnc_Cap = Enc_Cap;
  184.       MSF = abs(MSF);
  185.       
  186.       Exp_Val    = IncPIDCalc(MSF, Vel_Target);
  187.       Exp_Val    = fabs(Exp_Val);

  188.       SMotor_Set_Speed(Exp_Val);
  189.       Time_Flag &= ~0x01;
  190.     }
  191.    
  192.     // 數(shù)據(jù)發(fā)送周期為1s, 顯示轉(zhuǎn)速
  193.     if(Time_Flag & 0x02)
  194.     {
  195.       int32_t pulse = YS_Encoder_GetCounting();
  196.       static int32_t tmp = 0;
  197.       float speed = (float)( pulse - tmp ) / ENCODER_RESOLUTION ;
  198.       
  199.       printf("1s內(nèi)的編碼器計(jì)數(shù)值:  %d\n", pulse - tmp);
  200.       printf("電機(jī)轉(zhuǎn)速:  %.2f r/s  \n", speed );
  201.       printf("移動(dòng)速度:  %.1f mm/s \n", speed*5.0f);// 1r就是5mm
  202.       tmp = pulse ;
  203.       Time_Flag &= ~0x02;
  204.     }
  205.   }
  206. }
  207. /**
  208.   * 函數(shù)功能: 系統(tǒng)滴答定時(shí)器中斷回調(diào)函數(shù)
  209.   * 輸入?yún)?shù): 無
  210.   * 返 回 值: 無
  211.   * 說    明: 每發(fā)生一次滴答定時(shí)器中斷進(jìn)入該回調(diào)函數(shù)一次
  212.   */
  213. void HAL_SYSTICK_Callback(void)
  214. {
  215.   // 每1ms自動(dòng)增一
  216.   time_count++;         
  217.   if( (time_count % INTERVAL) == 0)// 20ms讀取一次編碼器數(shù)值
  218.   {
  219.     if(Start_flag )
  220.       Time_Flag |= 0x01;
  221.   }
  222.   else if(time_count >= 1000)      // 1s發(fā)送一次數(shù)據(jù)
  223.   {
  224.     Time_Flag |= 0x02;
  225.     time_count = 0;
  226.   }
  227. }


  228. /**
  229.   * 函數(shù)功能: 定時(shí)器比較輸出中斷回調(diào)函數(shù)
  230.   * 輸入?yún)?shù): htim:定時(shí)器句柄指針
  231.   * 返 回 值: 無
  232.   * 說    明: 控制脈沖輸出
  233.   */
  234. void HAL_TIM_OC_DelayElapsedCallback( TIM_HandleTypeDef * htim)
  235. {
  236.   uint32_t Toggle = 0;
  237.   
  238.   if(htim == &htimx_SMotor1)
  239.   {
  240.     /* 設(shè)置下一次中斷的間隔 */
  241.     Toggle = __HAL_TIM_GET_COMPARE(&htimx_SMotor1, SMOTOR1_PUL_TIMx_CHANNELx);
  242.     Toggle += SMotor1.PulseWidth; // 計(jì)算實(shí)際的比較值
  243.     __HAL_TIM_SET_COMPARE(&htimx_SMotor1, SMOTOR1_PUL_TIMx_CHANNELx, (uint16_t)Toggle);
  244.   }
  245. }
  246. /**
  247.   * 函數(shù)功能: 系統(tǒng)時(shí)鐘配置
  248.   * 輸入?yún)?shù): 無
  249.   * 返 回 值: 無
  250.   * 說    明: 無
  251.   */
  252. static void SystemClock_Config(void)
  253. {
  254.   RCC_OscInitTypeDef RCC_OscInitStruct={0};
  255.   RCC_ClkInitTypeDef RCC_ClkInitStruct={0};

  256.   /* 使能PWR配置更新 */
  257.   MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);

  258.   /* 設(shè)置調(diào)壓器輸出電壓級(jí)別1 */
  259.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  260.   /* 等待D3區(qū)域VOS 輸出準(zhǔn)備就緒 */
  261.   while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) // 等待內(nèi)核電源就緒
  262.   {
  263.    
  264.   }
  265.   /* RCC 內(nèi)部/外部晶振配置 ,用于CPU,AHB,APH總線時(shí)鐘 */
  266.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;// 外部晶振
  267.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;//選擇外部時(shí)鐘晶振 HSE 25MHz
  268.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;//使能PLL
  269.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;//PLL時(shí)鐘源選擇HSE
  270.   RCC_OscInitStruct.PLL.PLLM = 5;  // 外部時(shí)鐘2分頻,得到5MHz 作為PLL時(shí)鐘源
  271.   RCC_OscInitStruct.PLL.PLLN = 160;// PLL 160倍頻,得到800MHz PLLCLK
  272.   RCC_OscInitStruct.PLL.PLLP = 2;  // PLLCLK 2分頻 得到400MHz SYSCLK
  273.   RCC_OscInitStruct.PLL.PLLQ = 2;  // PLLCLK 2分頻 得到400MHz用于部分外設(shè)的時(shí)鐘
  274.   RCC_OscInitStruct.PLL.PLLR = 2;  // PLLCLK 2分頻 得到400MHz用于部分外設(shè)的時(shí)鐘
  275.   RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;// PLL時(shí)鐘輸入范圍4-8MHz
  276.   RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;// PLL時(shí)鐘輸出范圍192-836MHz
  277.   RCC_OscInitStruct.PLL.PLLFRACN = 0;  // 此參數(shù)用于微調(diào) PLL1 VCO 范圍0~2^13-1
  278.   HAL_RCC_OscConfig(&RCC_OscInitStruct);
  279.   
  280.   /* RCC CPU,AHB,APH總線時(shí)鐘配置*/
  281.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  282.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
  283.                               |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  284.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;//SYSCLK 時(shí)鐘源400MHz
  285.   RCC_ClkInitStruct.SYSCLKDivider  = RCC_SYSCLK_DIV1;// SYSCLK 1分頻 HCLK=400MHz
  286.   RCC_ClkInitStruct.AHBCLKDivider  = RCC_HCLK_DIV2;  // HCLK 2分頻,AHB = 200Mhz
  287.   RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; // APB3 2分頻,APB3 = 100MHz
  288.   RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; // APB1 2分頻,APB1 = 100MHz
  289.   RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; // APB2 2分頻,APB2 = 100MHz
  290.   RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; // APB4 2分頻,APB4 = 100MHz
  291.   HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
  292.   

  293.   /* 使能時(shí)鐘安全機(jī)制 */
  294.   HAL_RCC_EnableCSS();

  295.   /* 滴答定時(shí)器配置1ms */
  296.   // SystemCoreClock/1000    1ms中斷一次
  297.         // SystemCoreClock/100000         10us中斷一次
  298.         // SystemCoreClock/1000000 1us中斷一次
  299.   HAL_SYSTICK_Config(SystemCoreClock/(1000));

  300.   /* 系統(tǒng)滴答定時(shí)器時(shí)鐘源 */
  301.   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  302.   /* 系統(tǒng)滴答定時(shí)器中斷優(yōu)先級(jí)配置 */
  303.   HAL_NVIC_SetPriority(SysTick_IRQn, 1, 1);
  304. }

  305. /**
  306.   * 函數(shù)功能: 使能CPU L1-Cache
  307.   * 輸入?yún)?shù): 無
  308.   * 返 回 值: 無
  309.   * 說    明: 無
  310.   */
  311. static void CPU_CACHE_Enable(void)
  312. {
  313.   /* 使能 I-Cache */
  314.   SCB_EnableICache();

  315.   /* 使能 D-Cache */
  316.   SCB_EnableDCache();
  317. }

  318. /********** (C) COPYRIGHT 2019-2030 硬石嵌入式開發(fā)團(tuán)隊(duì) *******END OF FILE******/
復(fù)制代碼


YS-H7Multi_HAL_MOTOR-236. 57&amp;42步進(jìn)電機(jī)_速度閉環(huán)_位置式PID.7z

7.37 MB, 下載次數(shù): 78, 下載積分: 黑幣 -5

黑石H7步進(jìn)電機(jī)驅(qū)動(dòng)

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表