硬件
STM32F407VGT6、步进电机驱动、步进电机
为什么需要S型曲线加速
如果电机直接告诉启动时可能存在震动、丢步,甚至无法启动的现象,此时使用合适的S型加速曲线,使得电机能够缓慢启动
S型曲线加速是指步进电机的启动速度按照S型曲线逐渐增加,以达到设定的最大速度。具体的S型曲线方程如下:
y = 1/(1+e^x);
此工具下载网址
https://www.newasp.com/soft/434323.html可以根据个人需求进行相关参数的设置
CUBEMX配置
###定时器1配置
###时钟配置
###定时器频率计算
50M/((50-1)*(2000-1))≈500Hz
后期可以根据需求进行修改
###工程管理
##源代码实现
###speed.c
#include "speed.h"
#include "stdio.h"
//#include "data.h"
Motor_t Motor;
extern TIM_HandleTypeDef htim1;
//extern volatile uint16_t AccStep[ACC_STEP_NUM];
uint16_t period_1[SIZE1]={0};
enum
{
SPEED_INCREASE,
SPEED_STABLE,
SPEED_DECREASE
};
//功能:S加速曲线初始化
//参数1 *pbuff 计算出的定时器的周期
//参数2 fre_max 最大频率 Hz
//参数3 fre_min 最小频率 Hz
//参数4 len 加速需要的脉冲数
void CurveS_init(uint16_t *pbuff,uint32_t fre_max,uint32_t fre_min,int16_t len)
{
int16_t i;
uint16_t flexible =4;
//uint16_t pbuff_1[500]={0};
float delt = fre_max-fre_min;
float deno ;
float melo ;
float fre;
#if CHANGE_MODE
for(i=0;i<len;i++)
{
pbuff[i] = AccStep[i];
printf("%d, ",AccStep[i]);
}
// memcpy(pbuff,(const void *)AccStep,800);
printf("\r\n");
for(i=0; i<len; i++)
{
printf("%d, ",pbuff[i]);
}
#else
for(i=0; i<len; i++)
{
melo = flexible* (i-len/2) / (len/2);
deno = 1.0f / (1 + expf(-melo)); //
fre = delt * deno + fre_min;
pbuff[i] = (unsigned short)(TIM1_CLOCK_FREQ / fre);
printf("%d, ",pbuff[i]);
}
#endif
}
//速度调节函数
volatile uint8_t RUN_FLAG = 0;
void SpeedAdjust(void)
{
switch(Motor.Status)
{
/*加速*/
case SPEED_INCREASE:
if(Motor.Count < Motor.CountMax)
{
__HAL_TIM_SET_AUTORELOAD(&htim1,period_1[Motor.Count]);//计算下一个PWM的周期
htim1.Instance->CCR2 = period_1[Motor.Count]/2;//占空比50%
Motor.Count++;//加速次数
}
else
{
Motor.Status = SPEED_STABLE;
Motor.Count--;
}
break;
/*匀速*/
case SPEED_STABLE:
if(Motor.PWMcount >= (Motor.PWMneed - Motor.Count))
{
Motor.Status = SPEED_DECREASE;
}
break;
/*减速*/
case SPEED_DECREASE:
if(Motor.Count >= 0)
{
__HAL_TIM_SET_AUTORELOAD(&htim1,period_1[Motor.Count]);//计算下一个PWM的周期
htim1.Instance->CCR2 = period_1[Motor.Count]/2;
Motor.Count--;
}
if(Motor.PWMcount >= Motor.PWMneed)
{
HAL_TIM_PWM_Stop_IT(&htim1,TIM_CHANNEL_2);
// RUN_FLAG = 1;
}
break;
default :
break;
}
}
//PWM--需要输出的脉冲个数
void StartPWM(uint32_t PWM)
{
Motor.PWMcount = 0;
Motor.PWMneed = PWM;
Motor.Count = 0;
Motor.Status = SPEED_INCREASE;
Motor.CountMax = PWM_Count_Max;
//初始化加速曲线
CurveS_init(period_1,PWM_FREQ_MAX,PWM_FREQ_MIN,Motor.CountMax);
__HAL_TIM_SET_AUTORELOAD(&htim1,period_1[0]);
htim1.Instance->CCR2 = period_1[0];
HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_2); //启动定时器PWM输出
}
###speed.h
#ifndef _SPEED_H
#define _SPEED_H
#include "main.h"
typedef struct{
uint8_t Status; //状态
int32_t Count; //加减速过程脉冲计数
int32_t CountMax; //最大加速脉冲数
uint32_t PWMcount;//PWM计数
uint32_t PWMneed; //需要输出的PWM总数
}Motor_t;
void CurveS_init(uint16_t *pbuff,uint32_t fre_max,uint32_t fre_min,int16_t len);
void SpeedAdjust(void);
void StartPWM(uint32_t PWM);
#endif
#ifndef _SPEED_H
#define _SPEED_H
###main.h中新增
#define TIM1_CLOCK_FREQ 1000000 //定时器1的时钟频率
#define PWM_NUM 20000 //要输出的PWM的步数
#define PWM_Count_Max 8000 //加速度需要的步数
#define PWM_FREQ_MAX 1000 //最大频率
#define PWM_FREQ_MIN 800 //最小频率
#define SIZE1 PWM_NUM
###main.c中
/* USER CODE BEGIN Includes */
#include "speed.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 0 */
extern Motor_t Motor;
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
StartPWM(PWM_NUM);
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
/*S型曲线加速*/
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
/*S型曲线加速*/
Motor.PWMcount++;
SpeedAdjust();//速度调节
}
##程序功能描述
程序启动后,累计输出PWM_NUM(20000)个脉冲,其中加速步数PWM_Count_Max个(8000),最大频率为PWM_FREQ_MAX(1000Hz),最小频率为PWM_FREQ_MIN(800Hz)定时器1的时钟频率1000000是50M经过50分频之后的结果。
其中PWM_NUM为总的脉冲数,PWM_Count_Max为S型曲线加速中的前一部分,最大频率1000Hz决定了加速过程中的最大速度。PWM_FREQ_MIN决定了加速过程中的最小速度,因为步进电机的速度在一定范围内和脉冲的频率呈正相关。
如果想要在S型曲线加速结束后步进电机还能继续转动,把SpeedAdjust()函数中的HAL_TIM_PWM_Stop_IT(&htim1,TIM_CHANNEL_2);注释掉即可。