S型曲线的的方程,在[-5,5]的图形如下图所示:
如要将此曲线应用在步进电机的加、减速过程中,需要将方程在XY坐标系进行平移,同时对曲线进行拉升变化:
其中的A分量在y方向进行平移,B分量在y方向进行拉伸,ax+b分量在x方向进行平移和拉伸。
根据项目的需要,在加速过程中采用的曲线方程为:。
其中的Fcurrent为length(3000)个点中的单个频率值。Fmin起始频率为500; Fmax为最大频率35000; -flexible*(i - num)/num是对S型曲线进行拉伸变化,其中flexible代表S曲线区间(越大代表压缩的最厉害,中间(x坐标0点周围)加速度越大;越小越接近匀加速。理想的S曲线的取值为4-6),i是在循环计算过程中的索引,从0开始,num为 length/2 大小(这样可以使得S曲线对称)。在项目中i的区间[0,3000), num=3000/2=1500。
提供的计算接口如下。
对应的计算接口code:
/* calculate the Period and Freq array value, fill the Period value into the Period register during the timer interrupt.
*calculate the acceleration procedure , a totally 1000 elements array.
* parameter fre[]: point to the array that keeps the freq value.
* period[]: point to the array that keeps the timer period value.
* len: the procedure of acceleration length.it is best thing to set the float number, some compile software maybe transfer error if set it as a int
* fre_max: maximum speed, frequency vale.
* fre_min: start minimum speed, frequency vale. mind : 10000000/65535 = 152, so fre_min can't less than 152.
* flexible: flexible value. adjust the S curves
*/
void CalculateSModelLine(float fre[], unsigned short period[], float len, float fre_max, float fre_min, float flexible)
{
int i=0;
float deno ;
float melo ;
float delt = fre_max-fre_min;
for(; i
可以看到最小起始频率和当前定时器的频率有关,fre_min = 定时器时钟频率/自动装载值,这里定时器时钟频率经过分频后得到是10MHz,这样计算后得到起始频率最小值为152
S型加速实现思想就是根据S曲线函数计算一定的采样点,在每个采样点进行速度修改最后拟合出S曲线。
通过以上的代码已经计算出每个采样点需要的自动装载值和频率,只要比较中断处理函数处理更改自动装载值和比较值就可以进行S型加速。旋转方向根据驱动器DIR接口设置不同电平即可控制旋转方向。这样接基本完成一个步进电机的S型加速,如果需要记录当前绝对位置可以通过在中断里设置变量记录脉冲值即可。
项目中采用的是上海鸣志步进电机,驱动器为SR2,主控为STM32F407,使用的HAL库。
主要代码如下:
/* main.c */
uint32_t step_to_run= 6800+12800*10; //要匀速运行的步数 总共运行步数 = ACCELERATED_SPEED_LENGTH*2 + step_to_run
float fre[ACCELERATED_SPEED_LENGTH]; //数组存储加速过程中每一步的频率
unsigned short period[ACCELERATED_SPEED_LENGTH]; //数组储存加速过程中每一步定时器的自动装载值
void CalculateSModelLine(float fre[], unsigned short period[], float len, float fre_max, float fre_min, float flexible)
{
int i=0;
float deno ;
float melo ;
float delt = fre_max-fre_min;
for(; i
/* bsp_stepmotor.h */
#if S_ACCEL
/* S型加速参数 */
#define ACCELERATED_SPEED_LENGTH 3000 //定义加速度的点数(其实也是3000个细分步的意思),调这个参数改变加速点
#define FRE_MIN 500 //最低的运行频率,调这个参数调节最低运行速度
#define FRE_MAX 35000 //最高的运行频率,调这个参数调节匀速时的最高速度35000
#define STOP 0 // 加减速曲线状态:停止
#define ACCEL 1 // 加减速曲线状态:加速阶段
#define DECEL 2 // 加减速曲线状态:减速阶段
#define RUN 3 // 加减速曲线状态:匀速阶段
#endif
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
static uint32_t i=0;
static uint8_t status = 1; //状态机状态
static uint32_t num=0; //进入中断次数
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)
{
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
i++;
#if S_ACCEL
if(i%2==0) //每进入两次中断才是一个完整脉冲
{
switch(status)
{
case ACCEL://加速
__HAL_TIM_SET_AUTORELOAD(&htimx_STEPMOTOR,period[num]);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,period[num]/2);
num++;
if(num>=ACCELERATED_SPEED_LENGTH)
{
status=3;
}
break;
case RUN://匀速
step_to_run--;
if(step_to_run<1)
status=2;
break;
case DECEL://减速
num--;
__HAL_TIM_SET_AUTORELOAD(&htimx_STEPMOTOR,period[num]);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,period[num]/2);
if(num<1)
status=0;
break;
case STOP://停止
// 关闭通道
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);
STEPMOTOR_OUTPUT_DISABLE();
break;
}
}
#endif
}
/* 定时器参数设置 */
/*
#define STEPMOTOR_TIMx TIM8
#define STEPMOTOR_TIM_RCC_CLK_ENABLE() __HAL_RCC_TIM8_CLK_ENABLE()
#define STEPMOTOR_TIM_RCC_CLK_DISABLE() __HAL_RCC_TIM8_CLK_DISABLE()
#define STEPMOTOR_TIM_IT_CCx TIM_IT_CC1
#define STEPMOTOR_TIM_FLAG_CCx TIM_FLAG_CC1
#define STEPMOTOR_TIMx_IRQn TIM8_CC_IRQn
#define STEPMOTOR_TIMx_IRQHandler TIM8_CC_IRQHandler
#define STEPMOTOR_TIM_CHANNEL_x TIM_CHANNEL_1
#define STEPMOTOR_TIM_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() // 输出控制脉冲给电机驱动器
#define STEPMOTOR_TIM_PUL_PORT GPIOC // 对应驱动器的PUL-(驱动器使用共阳接法)
#define STEPMOTOR_TIM_PUL_PIN GPIO_PIN_6 // 而PLU+直接接开发板的VCC
#define STEPMOTOR_DIR_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() // 电机旋转方向控制,如果悬空不接默认正转
#define STEPMOTOR_DIR_PORT GPIOD // 对应驱动器的DIR-(驱动器使用共阳接法)
#define STEPMOTOR_DIR_PIN GPIO_PIN_3 // 而DIR+直接接开发板的VCC
#define GPIO_PIN_AF_AS_SYS GPIO_AF0_RTC_50Hz // 引脚不作为复用功能使用
#define STEPMOTOR_ENA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() // 电机脱机使能控制,如果悬空不接默认使能电机
#define STEPMOTOR_ENA_PORT GPIOD // 对应驱动器的ENA-(驱动器使用共阳接法)
#define STEPMOTOR_ENA_PIN GPIO_PIN_7 // 而ENA+直接接开发板的VCC
#define STEPMOTOR_DIR_FORWARD() HAL_GPIO_WritePin(STEPMOTOR_DIR_PORT,STEPMOTOR_DIR_PIN,GPIO_PIN_RESET)
#define STEPMOTOR_DIR_REVERSAL() HAL_GPIO_WritePin(STEPMOTOR_DIR_PORT,STEPMOTOR_DIR_PIN,GPIO_PIN_SET)
#define STEPMOTOR_OUTPUT_ENABLE() HAL_GPIO_WritePin(STEPMOTOR_ENA_PORT,STEPMOTOR_ENA_PIN,GPIO_PIN_RESET)
#define STEPMOTOR_OUTPUT_DISABLE() HAL_GPIO_WritePin(STEPMOTOR_ENA_PORT,STEPMOTOR_ENA_PIN,GPIO_PIN_SET)
*/
/**
* 函数功能: 驱动器相关GPIO初始化配置
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
static void STEPMOTOR_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 引脚端口时钟使能 */
STEPMOTOR_TIM_GPIO_CLK_ENABLE();
STEPMOTOR_DIR_GPIO_CLK_ENABLE();
STEPMOTOR_ENA_GPIO_CLK_ENABLE();
/* 驱动器脉冲控制引脚IO初始化 */
GPIO_InitStruct.Pin = STEPMOTOR_TIM_PUL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF3_TIM8; // GPIO引脚用做TIM复用功能
HAL_GPIO_Init(STEPMOTOR_TIM_PUL_PORT, &GPIO_InitStruct);
/* 驱动器方向控制引脚IO初始化 */
GPIO_InitStruct.Pin = STEPMOTOR_DIR_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_TRACE; // GPIO引脚用做系统默认功能
HAL_GPIO_Init(STEPMOTOR_DIR_PORT, &GPIO_InitStruct);
/* 驱动器脱机使能控制引脚IO初始化 */
GPIO_InitStruct.Pin = STEPMOTOR_ENA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_TRACE; // GPIO引脚用做系统默认功能
HAL_GPIO_Init(STEPMOTOR_ENA_PORT, &GPIO_InitStruct);
STEPMOTOR_DIR_FORWARD();
STEPMOTOR_OUTPUT_DISABLE();
}
/**
* 函数功能: 驱动器定时器初始化
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
void STEPMOTOR_TIMx_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig; // 定时器时钟
TIM_OC_InitTypeDef sConfigOC; // 定时器通道比较输出
STEPMOTOR_TIM_RCC_CLK_ENABLE();
/* STEPMOTOR相关GPIO初始化配置 */
STEPMOTOR_GPIO_Init();
/* 定时器基本环境配置 */
htimx_STEPMOTOR.Instance = STEPMOTOR_TIMx; // 定时器编号
htimx_STEPMOTOR.Init.Prescaler = STEPMOTOR_TIM_PRESCALER; // 定时器预分频器
htimx_STEPMOTOR.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数方向:向上计数
htimx_STEPMOTOR.Init.Period = STEPMOTOR_TIM_PERIOD; // 定时器周期
htimx_STEPMOTOR.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; // 时钟分频
HAL_TIM_Base_Init(&htimx_STEPMOTOR);
/* 定时器时钟源配置 */
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; // 使用内部时钟源
HAL_TIM_ConfigClockSource(&htimx_STEPMOTOR, &sClockSourceConfig);
/* 定时器比较输出配置 */
sConfigOC.OCMode = TIM_OCMODE_TOGGLE; // 比较输出模式:反转输出
sConfigOC.Pulse = 0xFFFF; // 脉冲数
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; // 输出极性
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW; // 互补通道输出极性
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 快速模式
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; // 空闲电平
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; // 互补通道空闲电平
HAL_TIM_OC_ConfigChannel(&htimx_STEPMOTOR, &sConfigOC, STEPMOTOR_TIM_CHANNEL_x);
/* 使能比较输出通道 */
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE);
/* 配置定时器中断优先级并使能 */
HAL_NVIC_SetPriority(STEPMOTOR_TIMx_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(STEPMOTOR_TIMx_IRQn);
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);
/* 使能定时器比较输出 */
__HAL_TIM_ENABLE_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
/* Enable the main output */
__HAL_TIM_MOE_ENABLE(&htimx_STEPMOTOR);
HAL_TIM_Base_Start(&htimx_STEPMOTOR);// 使能定时器
}
/**
* 函数功能: 基本定时器硬件初始化配置
* 输入参数: htim_base:基本定时器句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==STEPMOTOR_TIMx)
{
/* 基本定时器外设时钟使能 */
STEPMOTOR_TIM_RCC_CLK_ENABLE();
}
}
/**
* 函数功能: 基本定时器硬件反初始化配置
* 输入参数: htim_base:基本定时器句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==STEPMOTOR_TIMx)
{
/* 基本定时器外设时钟禁用 */
STEPMOTOR_TIM_RCC_CLK_DISABLE();
HAL_GPIO_DeInit(STEPMOTOR_TIM_PUL_PORT,STEPMOTOR_TIM_PUL_PIN);
HAL_GPIO_DeInit(STEPMOTOR_DIR_PORT,STEPMOTOR_DIR_PIN);
HAL_GPIO_DeInit(STEPMOTOR_ENA_PORT,STEPMOTOR_ENA_PIN);
HAL_NVIC_DisableIRQ(STEPMOTOR_TIMx_IRQn);
}
}
源代码:
CSDN资源直接搜索“STM32F407实现鸣志步进电机S型加速实现代码”
步进电机S型加速源代码
文档更新地址:
为知笔记文档保存
步进电机梯形加速原理不在叙述,直接上源代码
更新笔记:STM32单步进电机S型加减速实现