- .h文件如下:
- #ifndef INC_DRV_STEPPER_H_
- #define INC_DRV_STEPPER_H_
- #include "main.h"
- #include "stdint.h"
- #define AIN1_SetCompare(TIMx,CompareValue) TIMx->CCR1 = CompareValue
- #define AIN2_SetCompare(TIMx,CompareValue) TIMx->CCR2 = CompareValue
- #define BIN1_SetCompare(TIMx,CompareValue) TIMx->CCR4 = CompareValue
- #define BIN2_SetCompare(TIMx,CompareValue) TIMx->CCR3 = CompareValue
- #define MICROSTEP 64 //64细分,一圈需要64*200步
- //PWM时钟64MHz不分频,计数值3200
- #define PWM_CNT 3200 //PWM计数值
- #define PWM_CYCLE 50 //PWM周期,单位us
- typedef struct{
- uint8_t Mode;
- uint8_t Dir;
- int64_t Step;
- }
- STEPPER_MOTOR;
- extern STEPPER_MOTOR sm;
- extern uint8_t g_Full_En;
- void Set_StepperMotor_Speed(float speed);
- void Start_StepperMotor(uint8_t mode, uint8_t dir, uint32_t step);
- void Stop_StepperMotor(void);
- void Microstep_Control(void);
- #endif /* INC_DRV_STEPPER_H_ */
- .c文件如下:
- /*
- * stepper.c
- *
- * Created on: Feb 17, 2025
- * Author: 74351
- */
- #include "drv_stepper.h"
- //64细分电流表,半周数据
- const uint16_t Current_Subdivision_Table[128] =
- {
- 0,44,88,132,176,220,264,308,351,394,437,480,523,565,606,648,
- 689,729,770,809,849,887,925,963,1000,1036,1072,1107,1142,1176,1209,1241,
- 1273,1304,1334,1363,1391,1419,1446,1472,1497,1521,1544,1566,1587,1608,1627,1646,
- 1663,1679,1695,1709,1722,1735,1746,1756,1765,1773,1781,1786,1791,1795,1798,1799,
- 1800,1799,1798,1795,1791,1786,1781,1773,1765,1756,1746,1735,1722,1709,1695,1679,
- 1663,1646,1627,1608,1587,1566,1544,1521,1497,1472,1446,1419,1391,1363,1334,1304,
- 1273,1241,1209,1176,1142,1107,1072,1036,1000,963,925,887,849,809,770,729,
- 689,648,606,565,523,480,437,394,351,308,264,220,176,132,88,44
- };
- STEPPER_MOTOR sm = {
- .Mode = 0,
- .Dir = 0,
- .Step = 0
- };
- static int16_t g_StepLogic = 0;
- static uint8_t g_AIN1_Index = 0;
- static uint8_t g_AIN2_Index = 0;
- static uint8_t g_BIN1_Index = 0;
- static uint8_t g_BIN2_Index = 0;
- uint8_t g_Full_En = 0;
- static uint16_t g_Full_Delay = 30;
- static int16_t g_Full_TimerCount = 30;
- static int g_Integer = 0; //整数部分
- static int g_Remainder = 0; //余数部分
- static int16_t g_DelayCount1 = 1;
- static int16_t g_DelayCount2 = 1;
- static int16_t g_TimerCount1 = 0;
- static int16_t g_TimerCount2 = 0;
- static int16_t g_Step_Count = 0;
- /**
- * [url=/u/brief]@brief[/url] 设置步进电机速度
- * @param speed: 转速(单位:r/min)
- * @retval 无
- */
- void Set_StepperMotor_Speed(float speed)
- {
- float delay = 0,delay_cnt = 0;
- float time = 60 / speed; //每转所需时间,单位s
- delay = (time * 1000000) - (MICROSTEP * 200 * PWM_CYCLE);
- delay_cnt = delay / PWM_CYCLE;
- g_Integer = (int)delay_cnt / (MICROSTEP * 200);
- g_Remainder = (int)delay_cnt % (MICROSTEP * 200);
- if(g_Integer >= 0)
- {
- g_DelayCount1 = g_Integer + 1;
- g_TimerCount1 = g_DelayCount1;
- }
- if(g_Remainder > 0)
- {
- g_DelayCount2 = g_DelayCount1 + 1;
- g_TimerCount2 = g_DelayCount2;
- }
- }
- /**
- * @brief 启动步进电机
- * @param mode: 0-连续旋转 1-转动指定步数
- * @param dir: 0-顺时针 1-逆时针
- * @param step: 指定步数(mode=1时有效)
- * @retval 无
- */
- void Start_StepperMotor(uint8_t mode, uint8_t dir, uint32_t step)
- {
- if(mode == 0)
- {
- sm.Mode = 0;
- }
- else
- {
- sm.Mode = 1;
- sm.Step = step;
- }
- if(dir == 0)
- {
- sm.Dir = 0;
- if(g_Full_En == 0)
- {
- g_StepLogic = MICROSTEP << 2;
- }
- else
- {
- g_StepLogic = 3;
- }
- }
- else
- {
- sm.Dir = 1;
- g_StepLogic = 0;
- }
- if(g_Full_En == 1)
- {
- g_Full_TimerCount = g_Full_Delay;
- }
- TIM3->DIER |= (0x1UL << 0);
- TIM3->CR1 |= (0x1UL << 0);
- AIN1_SetCompare(TIM3, 0);
- AIN2_SetCompare(TIM3, 0);
- BIN1_SetCompare(TIM3, 0);
- BIN2_SetCompare(TIM3, 0);
- TIM3->CCER |= (0x1UL << 0);
- TIM3->CCER |= (0x1UL << 4);
- TIM3->CCER |= (0x1UL << 8);
- TIM3->CCER |= (0x1UL << 12);
- }
- /**
- * @brief 停止步进电机
- * @retval 无
- */
- void Stop_StepperMotor(void)
- {
- TIM3->DIER &= ~(0x1UL << 0);
- TIM3->CR1 &= ~(0x1UL << 0);
- AIN1_SetCompare(TIM3, 0);
- AIN2_SetCompare(TIM3, 0);
- BIN1_SetCompare(TIM3, 0);
- BIN2_SetCompare(TIM3, 0);
- TIM3->CCER &= ~(0x1UL << 0);
- TIM3->CCER &= ~(0x1UL << 4);
- TIM3->CCER &= ~(0x1UL << 8);
- TIM3->CCER &= ~(0x1UL << 12);
- }
- /**
- * @brief 四拍微步控制,需要在PWM定时器UPDATE中断中调用
- * @retval 无
- */
- void Microstep_Control(void)
- {
- uint8_t phase = 0;
- if(g_Full_En == 0)
- {
- if(g_Step_Count >= (MICROSTEP * 200))
- {
- g_Step_Count = 0;
- }
- if(g_Step_Count < g_Remainder)
- {
- g_TimerCount2--;
- }
- else
- {
- g_TimerCount1--;
- }
- if(g_TimerCount1 <= 0 || g_TimerCount2 <= 0)
- {
- g_TimerCount1 = g_DelayCount1;
- g_TimerCount2 = g_DelayCount2;
- phase = g_StepLogic >> 6;
- switch(phase)
- {
- case 0:
- g_AIN1_Index = g_StepLogic;
- g_AIN2_Index = 0;
- g_BIN1_Index = 0;
- g_BIN2_Index = g_StepLogic + MICROSTEP;
- break;
- case 1:
- g_AIN1_Index = g_StepLogic;
- g_AIN2_Index = 0;
- g_BIN1_Index = g_StepLogic - MICROSTEP;
- g_BIN2_Index = 0;
- break;
- case 2:
- g_AIN1_Index = 0;
- g_AIN2_Index = g_StepLogic - (MICROSTEP << 1);
- g_BIN1_Index = g_StepLogic - MICROSTEP;
- g_BIN2_Index = 0;
- break;
- case 3:
- g_AIN1_Index = 0;
- g_AIN2_Index = g_StepLogic - (MICROSTEP << 1);
- g_BIN1_Index = 0;
- g_BIN2_Index = g_StepLogic - ((MICROSTEP << 1) + MICROSTEP);
- break;
- }
- g_Step_Count++;
- AIN1_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table[g_AIN1_Index]);
- AIN2_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table[g_AIN2_Index]);
- BIN1_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table[g_BIN1_Index]);
- BIN2_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table[g_BIN2_Index]);
- if(sm.Dir == 0)
- {
- g_StepLogic--;
- if(g_StepLogic < 0)
- {
- g_StepLogic = MICROSTEP << 2;
- }
- }
- else
- {
- g_StepLogic++;
- if(g_StepLogic > ((MICROSTEP << 2) - 1))
- {
- g_StepLogic = 0;
- }
- }
- if(sm.Mode == 1)
- {
- sm.Step--;
- if(sm.Step < 0)
- {
- sm.Step = 0;
- Stop_StepperMotor();
- }
- }
- }
- }
- else
- {
- g_Full_TimerCount--;
- if(g_Full_TimerCount < 0)
- {
- g_Full_TimerCount = g_Full_Delay;
- if(sm.Dir == 0)
- {
- g_StepLogic--;
- if(g_StepLogic < 0) g_StepLogic = 3;
- }
- else
- {
- g_StepLogic++;
- if(g_StepLogic > 3) g_StepLogic = 0;
- }
- switch (g_StepLogic)
- {
- case 0:
- AIN1_SetCompare(TIM3,PWM_CNT);
- AIN2_SetCompare(TIM3,0);
- BIN1_SetCompare(TIM3,PWM_CNT);
- BIN2_SetCompare(TIM3,0);
- break;
- case 1:
- AIN1_SetCompare(TIM3,0);
- AIN2_SetCompare(TIM3,PWM_CNT);
- BIN1_SetCompare(TIM3,PWM_CNT);
- BIN2_SetCompare(TIM3,0);
- break;
- case 2:
- AIN1_SetCompare(TIM3,0);
- AIN2_SetCompare(TIM3,PWM_CNT);
- BIN1_SetCompare(TIM3,0);
- BIN2_SetCompare(TIM3,PWM_CNT);
- break;
- case 3:
- AIN1_SetCompare(TIM3,PWM_CNT);
- AIN2_SetCompare(TIM3,0);
- BIN1_SetCompare(TIM3,0);
- BIN2_SetCompare(TIM3,PWM_CNT);
- break;
- }
- }
- }
- }
- 最后在定时器中断中调用Microstep_Control()即可:
- void TIM3_IRQHandler(void)
- {
- /* USER CODE BEGIN TIM3_IRQn 0 */
- if((TIM3->SR & (0x1UL << 0)) == (0x1UL << 0)) //UPDATE中断
- {
- TIM3->SR = ~(0x1UL << 0);
- Microstep_Control();
- }
- /* USER CODE END TIM3_IRQn 0 */
- /* USER CODE BEGIN TIM3_IRQn 1 */
- /* USER CODE END TIM3_IRQn 1 */
- }