步进电机细分控制算法
2、细分算法原理如下图上半部分所示,步进电机的两相线圈中的电流为相差90°的正弦波,一个正弦周期,步进电机转动了四整步。细分算法的基本思想是将一个整步分成若干个微步,控制每个微步的PWM占空比间接控制线圈中的电流大小及方向,从而使线圈中通过的电流近似正弦波。细分生成软件
[*]细分控制算法:
[*]根据细分原理部分电流图下半部分实现对DRV8833的引脚控制,直接贴源码,配合电流图阅读更清晰。
.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 MICROSTEP64 //64细分,一圈需要64*200步
//PWM时钟64MHz不分频,计数值3200
#define PWM_CNT 3200//PWM计数值
#define PWM_CYCLE50 //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 =
{
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;
/**
* @brief设置步进电机速度
* @paramspeed: 转速(单位: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启动步进电机
* @parammode: 0-连续旋转 1-转动指定步数
* @paramdir: 0-顺时针 1-逆时针
* @paramstep: 指定步数(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);
AIN2_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table);
BIN1_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table);
BIN2_SetCompare(TIM3, PWM_CNT - Current_Subdivision_Table);
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 */
}
步进电机细分控制算法
页:
[1]