[电机控制] 步进电机细分控制算法

[复制链接]
85|1
mattlincoln 发表于 2025-9-30 09:22 | 显示全部楼层 |阅读模式
2、细分算法原理如下图上半部分所示,步进电机的两相线圈中的电流为相差90°的正弦波,一个正弦周期,步进电机转动了四整步。细分算法的基本思想是将一个整步分成若干个微步,控制每个微步的PWM占空比间接控制线圈中的电流大小及方向,从而使线圈中通过的电流近似正弦波。




细分生成软件
  • 细分控制算法:
  • 根据细分原理部分电流图下半部分实现对DRV8833的引脚控制,直接贴源码,配合电流图阅读更清晰。
  1. .h文件如下:
  2. #ifndef INC_DRV_STEPPER_H_
  3. #define INC_DRV_STEPPER_H_
  4. #include "main.h"
  5. #include "stdint.h"
  6. #define AIN1_SetCompare(TIMx,CompareValue) TIMx->CCR1 = CompareValue
  7. #define AIN2_SetCompare(TIMx,CompareValue) TIMx->CCR2 = CompareValue
  8. #define BIN1_SetCompare(TIMx,CompareValue) TIMx->CCR4 = CompareValue
  9. #define BIN2_SetCompare(TIMx,CompareValue) TIMx->CCR3 = CompareValue
  10. #define MICROSTEP  64   //64细分,一圈需要64*200步
  11. //PWM时钟64MHz不分频,计数值3200
  12. #define PWM_CNT   3200  //PWM计数值
  13. #define PWM_CYCLE  50   //PWM周期,单位us
  14. typedef struct{
  15.     uint8_t Mode;
  16.     uint8_t Dir;
  17.     int64_t Step;
  18. }
  19. STEPPER_MOTOR;
  20. extern STEPPER_MOTOR sm;
  21. extern uint8_t g_Full_En;
  22. void Set_StepperMotor_Speed(float speed);
  23. void Start_StepperMotor(uint8_t mode, uint8_t dir, uint32_t step);
  24. void Stop_StepperMotor(void);
  25. void Microstep_Control(void);
  26. #endif /* INC_DRV_STEPPER_H_ */
  27. .c文件如下:
  28. /*
  29. * stepper.c
  30. *
  31. *  Created on: Feb 17, 2025
  32. *      Author: 74351
  33. */
  34. #include "drv_stepper.h"
  35. //64细分电流表,半周数据
  36. const uint16_t Current_Subdivision_Table[128] =
  37. {
  38.     0,44,88,132,176,220,264,308,351,394,437,480,523,565,606,648,
  39.     689,729,770,809,849,887,925,963,1000,1036,1072,1107,1142,1176,1209,1241,
  40.     1273,1304,1334,1363,1391,1419,1446,1472,1497,1521,1544,1566,1587,1608,1627,1646,
  41.     1663,1679,1695,1709,1722,1735,1746,1756,1765,1773,1781,1786,1791,1795,1798,1799,
  42.     1800,1799,1798,1795,1791,1786,1781,1773,1765,1756,1746,1735,1722,1709,1695,1679,
  43.     1663,1646,1627,1608,1587,1566,1544,1521,1497,1472,1446,1419,1391,1363,1334,1304,
  44.     1273,1241,1209,1176,1142,1107,1072,1036,1000,963,925,887,849,809,770,729,
  45.     689,648,606,565,523,480,437,394,351,308,264,220,176,132,88,44
  46. };
  47. STEPPER_MOTOR sm = {
  48.     .Mode = 0,
  49.     .Dir = 0,
  50.     .Step = 0
  51. };
  52. static int16_t g_StepLogic = 0;
  53. static uint8_t g_AIN1_Index = 0;
  54. static uint8_t g_AIN2_Index = 0;
  55. static uint8_t g_BIN1_Index = 0;
  56. static uint8_t g_BIN2_Index = 0;
  57. uint8_t g_Full_En = 0;
  58. static uint16_t g_Full_Delay = 30;
  59. static int16_t g_Full_TimerCount = 30;
  60. static int g_Integer = 0;   //整数部分
  61. static int g_Remainder = 0;  //余数部分
  62. static int16_t g_DelayCount1 = 1;
  63. static int16_t g_DelayCount2 = 1;
  64. static int16_t g_TimerCount1 = 0;
  65. static int16_t g_TimerCount2 = 0;
  66. static int16_t g_Step_Count = 0;
  67. /**
  68.   * [url=/u/brief]@brief[/url]  设置步进电机速度
  69.   * @param  speed: 转速(单位:r/min)
  70.   * @retval 无
  71.   */
  72. void Set_StepperMotor_Speed(float speed)
  73. {
  74.     float delay = 0,delay_cnt = 0;
  75.     float time = 60 / speed; //每转所需时间,单位s
  76.     delay = (time * 1000000) - (MICROSTEP * 200 * PWM_CYCLE);
  77.     delay_cnt = delay / PWM_CYCLE;
  78.     g_Integer = (int)delay_cnt / (MICROSTEP * 200);
  79.     g_Remainder = (int)delay_cnt % (MICROSTEP * 200);
  80.     if(g_Integer >= 0)
  81.     {
  82.         g_DelayCount1 = g_Integer + 1;
  83.         g_TimerCount1 = g_DelayCount1;
  84.     }
  85.     if(g_Remainder > 0)
  86.     {
  87.         g_DelayCount2 = g_DelayCount1 + 1;
  88.         g_TimerCount2 = g_DelayCount2;
  89.     }
  90. }
  91. /**
  92.   * @brief  启动步进电机
  93.   * @param  mode: 0-连续旋转 1-转动指定步数
  94.   * @param  dir: 0-顺时针 1-逆时针
  95.   * @param  step: 指定步数(mode=1时有效)
  96.   * @retval 无
  97.   */
  98. void Start_StepperMotor(uint8_t mode, uint8_t dir, uint32_t step)
  99. {
  100.     if(mode == 0)
  101.     {
  102.         sm.Mode = 0;
  103.     }
  104.     else
  105.     {
  106.         sm.Mode = 1;
  107.         sm.Step = step;
  108.     }
  109.     if(dir == 0)
  110.     {
  111.         sm.Dir = 0;
  112.         if(g_Full_En == 0)
  113.         {
  114.             g_StepLogic = MICROSTEP << 2;
  115.         }
  116.         else
  117.         {
  118.             g_StepLogic = 3;
  119.         }
  120.     }
  121.     else
  122.     {
  123.         sm.Dir = 1;
  124.         g_StepLogic = 0;
  125.     }
  126.     if(g_Full_En == 1)
  127.     {
  128.         g_Full_TimerCount = g_Full_Delay;
  129.     }
  130.     TIM3->DIER |= (0x1UL << 0);
  131.     TIM3->CR1 |= (0x1UL << 0);
  132.     AIN1_SetCompare(TIM3, 0);
  133.     AIN2_SetCompare(TIM3, 0);
  134.     BIN1_SetCompare(TIM3, 0);
  135.     BIN2_SetCompare(TIM3, 0);
  136.     TIM3->CCER |= (0x1UL << 0);
  137.     TIM3->CCER |= (0x1UL << 4);
  138.     TIM3->CCER |= (0x1UL << 8);
  139.     TIM3->CCER |= (0x1UL << 12);
  140. }
  141. /**
  142.   * @brief  停止步进电机
  143.   * @retval 无
  144.   */
  145. void Stop_StepperMotor(void)
  146. {
  147.     TIM3->DIER &= ~(0x1UL << 0);
  148.     TIM3->CR1 &= ~(0x1UL << 0);
  149.     AIN1_SetCompare(TIM3, 0);
  150.     AIN2_SetCompare(TIM3, 0);
  151.     BIN1_SetCompare(TIM3, 0);
  152.     BIN2_SetCompare(TIM3, 0);
  153.     TIM3->CCER &= ~(0x1UL << 0);
  154.     TIM3->CCER &= ~(0x1UL << 4);
  155.     TIM3->CCER &= ~(0x1UL << 8);
  156.     TIM3->CCER &= ~(0x1UL << 12);
  157. }
  158. /**
  159.   * @brief  四拍微步控制,需要在PWM定时器UPDATE中断中调用
  160.   * @retval 无
  161.   */
  162. void Microstep_Control(void)
  163. {
  164.     uint8_t phase = 0;
  165.     if(g_Full_En == 0)
  166.     {
  167.         if(g_Step_Count >= (MICROSTEP * 200))
  168.         {
  169.             g_Step_Count = 0;
  170.         }
  171.         if(g_Step_Count < g_Remainder)
  172.         {
  173.             g_TimerCount2--;
  174.         }
  175.         else
  176.         {
  177.             g_TimerCount1--;
  178.         }
  179.         if(g_TimerCount1 <= 0 || g_TimerCount2 <= 0)
  180.         {
  181.             g_TimerCount1 = g_DelayCount1;
  182.             g_TimerCount2 = g_DelayCount2;
  183.             phase = g_StepLogic >> 6;
  184.             switch(phase)
  185.             {
  186.                 case 0:
  187.                 g_AIN1_Index = g_StepLogic;
  188.                 g_AIN2_Index = 0;
  189.                 g_BIN1_Index = 0;
  190.                 g_BIN2_Index = g_StepLogic + MICROSTEP;
  191.                 break;
  192.                 case 1:
  193.                 g_AIN1_Index = g_StepLogic;
  194.                 g_AIN2_Index = 0;
  195.                 g_BIN1_Index = g_StepLogic - MICROSTEP;
  196.                 g_BIN2_Index = 0;
  197.                 break;
  198.                 case 2:
  199.                 g_AIN1_Index = 0;
  200.                 g_AIN2_Index = g_StepLogic - (MICROSTEP << 1);
  201.                 g_BIN1_Index = g_StepLogic - MICROSTEP;
  202.                 g_BIN2_Index = 0;
  203.                 break;
  204.                 case 3:
  205.                 g_AIN1_Index = 0;
  206.                 g_AIN2_Index = g_StepLogic - (MICROSTEP << 1);
  207.                 g_BIN1_Index = 0;
  208.                 g_BIN2_Index = g_StepLogic - ((MICROSTEP << 1) + MICROSTEP);
  209.                 break;
  210.             }
  211.             g_Step_Count++;
  212.             AIN1_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table[g_AIN1_Index]);
  213.             AIN2_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table[g_AIN2_Index]);
  214.             BIN1_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table[g_BIN1_Index]);
  215.             BIN2_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table[g_BIN2_Index]);
  216.             if(sm.Dir == 0)
  217.             {
  218.                 g_StepLogic--;
  219.                 if(g_StepLogic < 0)
  220.                 {
  221.                     g_StepLogic = MICROSTEP << 2;
  222.                 }
  223.             }
  224.             else
  225.             {
  226.                 g_StepLogic++;
  227.                 if(g_StepLogic > ((MICROSTEP << 2) - 1))
  228.                 {
  229.                     g_StepLogic = 0;
  230.                 }
  231.             }
  232.             if(sm.Mode == 1)
  233.             {
  234.                 sm.Step--;
  235.                 if(sm.Step < 0)
  236.                 {
  237.                     sm.Step = 0;
  238.                     Stop_StepperMotor();
  239.                 }
  240.             }
  241.         }
  242.     }
  243.     else
  244.     {
  245.         g_Full_TimerCount--;
  246.         if(g_Full_TimerCount < 0)
  247.         {
  248.             g_Full_TimerCount = g_Full_Delay;
  249.             if(sm.Dir == 0)
  250.             {
  251.                 g_StepLogic--;
  252.                 if(g_StepLogic < 0) g_StepLogic = 3;
  253.             }
  254.             else
  255.             {
  256.                 g_StepLogic++;
  257.                 if(g_StepLogic > 3) g_StepLogic = 0;
  258.             }
  259.             switch (g_StepLogic)
  260.             {
  261.                 case 0:
  262.                 AIN1_SetCompare(TIM3,PWM_CNT);
  263.                 AIN2_SetCompare(TIM3,0);
  264.                 BIN1_SetCompare(TIM3,PWM_CNT);
  265.                 BIN2_SetCompare(TIM3,0);
  266.                 break;
  267.                 case 1:
  268.                 AIN1_SetCompare(TIM3,0);
  269.                 AIN2_SetCompare(TIM3,PWM_CNT);
  270.                 BIN1_SetCompare(TIM3,PWM_CNT);
  271.                 BIN2_SetCompare(TIM3,0);
  272.                 break;
  273.                 case 2:
  274.                 AIN1_SetCompare(TIM3,0);
  275.                 AIN2_SetCompare(TIM3,PWM_CNT);
  276.                 BIN1_SetCompare(TIM3,0);
  277.                 BIN2_SetCompare(TIM3,PWM_CNT);
  278.                 break;
  279.                 case 3:
  280.                 AIN1_SetCompare(TIM3,PWM_CNT);
  281.                 AIN2_SetCompare(TIM3,0);
  282.                 BIN1_SetCompare(TIM3,0);
  283.                 BIN2_SetCompare(TIM3,PWM_CNT);
  284.                 break;
  285.             }
  286.         }
  287.     }
  288. }
  289. 最后在定时器中断中调用Microstep_Control()即可:
  290. void TIM3_IRQHandler(void)
  291. {
  292. /* USER CODE BEGIN TIM3_IRQn 0 */
  293.     if((TIM3->SR & (0x1UL << 0)) == (0x1UL << 0))   //UPDATE中断
  294.     {
  295.         TIM3->SR = ~(0x1UL << 0);
  296.         Microstep_Control();
  297.     }
  298. /* USER CODE END TIM3_IRQn 0 */
  299. /* USER CODE BEGIN TIM3_IRQn 1 */
  300. /* USER CODE END TIM3_IRQn 1 */
  301. }



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
szt1993 发表于 2025-9-30 09:55 | 显示全部楼层
步进电机细分控制算法
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

1615

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部