1、Cubemx配置和T形曲线一致
2、代码
keil ver. V5.29.0.0
cubemx ver. v5.6.0
firmware ver. FW_F4 V1.25.1
PE3 LIMPOS
PE5 LIMNEG
PA4 ORGIN
PA5 ENA
PB0 DIR
PB1 STEP
bsp_stepmotor.c
#include "bsp_stepmotor_t.h"
#include <math.h>
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
#define ROUND_TO_UINT32(x) ((uint32_t)(x)+0.5f)>(x)? ((uint32_t)(x)):((uint32_t)(x)+1)
/* 私有变量 ------------------------------------------------------------------*/
__IO SpeedRampData_Typedef srd = {
STOP,CW,0,0,0,0,0,0}; // 加减速曲线变量
__IO uint8_t LimPosi = FALSE ; // 正方向极限标志位 True:到达极限位 False:未到达极限位
__IO uint8_t LimNega = FALSE ; // 负方向极限标志位
__IO int32_t step_position = 0;// 当前位置 单位:脉冲数
__IO uint8_t Motionstatus = 0;// 电机状态 0:停止 1:运动
void bsp_InitSTEPMOTOR_T_TIMxt(void)
{
HAL_TIM_Base_Start(&htimx_STEPMOTOR);
// HAL_TIM_OC_Start_IT(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x);//启动比较输出使能中断
}
/**
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: StepMotor 线性速度控制参数集合
* 返 回 值: 无
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且
* 速度很慢,那还没达到最大速度就要开始减速
*/
void STEPMOTOR_AxisMoveRel(LineSpdCtrl_Typedef *StepMotor)
{
int32_t step = StepMotor->Step;
uint32_t accel = StepMotor->Accel;
uint32_t decel = StepMotor->Decel;
uint32_t speed = StepMotor->Step;
uint16_t tim_count;//获取定时器的计数值
// 达到最大速度时的步数
uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)
uint32_t accel_lim;
/* 用于计算合适的预分频系数的临时变量 */
uint16_t Prescaler = STEPMOTOR_TIM_PRESCALER;// 默认定时器预分频
float A_T_x10 = 0;
float SM_LSC_TIMx_Freq = 0; // 定时器频率
float SM_LSC_TIMx_Freq_148 = 0; // 定时器频率
if(Motionstatus!=STOP)
return;
/* 方向设定 */
if(step < 0) // 步数为负数
{
srd.dir = (int8_t)CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();
step = -step; // 获取步数绝对值
}
else
{
srd.dir = (int8_t)CW; // 顺时针方向旋转
STEPMOTOR_DIR_FORWARD();
}
if(step == 1) // 步数为1
{
srd.accel_count = -1; // 只移动一步
srd.run_state = DECEL; // 减速状态.
srd.step_delay = 1000; // 短延时
}
else if(step != 0) // 如果目标运动步数不为0
{
// 我们的电机控制专题指导手册有详细的计算及推导过程
do
{
// 这一步是调整定时器预分频,使计算结果不会溢出
__HAL_TIM_SET_PRESCALER(&htimx_STEPMOTOR,Prescaler++);
SM_LSC_TIMx_Freq = ((float)SystemCoreClock/Prescaler);//168M/42
A_T_x10 = ((10.0f * ALPHA * SM_LSC_TIMx_Freq));
SM_LSC_TIMx_Freq_148 = (( (SM_LSC_TIMx_Freq * 0.676f) / 10.0f));
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w
srd.min_delay = ROUND_TO_UINT32(A_T_x10 / speed);
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^2
// step_delay = 1/tt * sqrt(2*alpha/accel)
// step_delay = ( tfreq*0.676/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/100
srd.step_delay = ROUND_TO_UINT32((SM_LSC_TIMx_Freq_148 * sqrt(A_SQ / accel))/10);//C0,初始速度的定时器值
}while(srd.step_delay > (uint32_t)0xFFFF);
/*计算加减速需要的参数*/
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度
if(max_s_lim == 0)
{
max_s_lim = 1;
}
// 计算多少步之后我们必须开始减速
// n1 = (n1+n2)decel / (accel + decel)
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.
if(accel_lim == 0)
{
accel_lim