cubemx配置图
先配置定时器,选择定时器8,内部时钟源,通道1,2,3,4
时钟配置,查看手册可以知道TIM8连接在APB2,定时器8时钟频率为168M。
定时器8参数配置
定时器8GPIO设置
定时器8 中断设置(比较中断)
生成代码
代码修改
1、生成S型加速点比较值及自动重装载值
添加bsp_stepmotor.c文件,主要是计算加速过程中确定加速点的自动重装载值,以及编写比较中断产生后回调函数中每个电机通道的状态机变化。
内容为:
#include "bsp_stepmotor.h"
#include "tim.h"
#include "math.h"
uint16_t step_to_run[4]={6800,6800,6800,6800}; //要匀速运行的步数 总共运行步数 = 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<len; i++)
{
melo = flexible* (i-len/2) / (len/2);
deno = 1.0f / (1 + expf(-melo)); //expf is a library function of exponential(e)?
fre[i] = delt * deno + fre_min;
period[i] = (unsigned short)(10000000.0f / fre[i]); // 10000000 is the timer driver frequency
}
return ;
}
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint32_t count[4]={0,0,0,0};
static uint32_t num_callback[4]={0,0,0,0};
static uint8_t status[4]={1,1,1,1};
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
num_callback[0]++;
if(num_callback[0]%2==0)
{
switch(status[0])
{
case ACCEL://加速
__HAL_TIM_SetAutoreload(&htim8,period[count[0]]);
__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_1,period[count[0]]/2);
count[0]++;
if(count[0]>=ACCELERATED_SPEED_LENGTH)
{
status[0]=3;
}
break;
case RUN://匀速
step_to_run[0]--;
if(step_to_run[0]<1)
status[0]=2;
break;
case DECEL://减速
count[0]--;
__HAL_TIM_SetAutoreload(&htim8,period[count[0]]);
__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_1,period[count[0]]/2);
if(count[0]<1)
status[0]=0;
break;
case STOP://停止
// 关闭通道
TIM_CCxChannelCmd(TIM8, TIM_CHANNEL_1, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htim8, TIM_FLAG_CC1);
break;
}
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
num_callback[1]++;
if(num_callback[1]%2==0)
{
switch(status[1])
{
case ACCEL://加速
__HAL_TIM_SetAutoreload(&htim8,period[count[1]]);
__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_2,period[count[1]]/2);
count[1]++;
if(count[1]>=ACCELERATED_SPEED_LENGTH)
{
status[1]=3;
}
break;
case RUN://匀速
step_to_run[1]--;
if(step_to_run[1]<1)
status[1]=2;
break;
case DECEL://减速
count[1]--;
__HAL_TIM_SetAutoreload(&htim8,period[count[1]]);
__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_2,period[count[1]]/2);
if(count[1]<1)
status[1]=0;
break;
case STOP://停止
// 关闭通道
TIM_CCxChannelCmd(TIM8, TIM_CHANNEL_2, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htim8, TIM_FLAG_CC2);
break;
}
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
num_callback[2]++;
if(num_callback[2]%2==0)
{
switch(status[2])
{
case ACCEL://加速
__HAL_TIM_SetAutoreload(&htim8,period[count[2]]);
__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_3,period[count[2]]/2);
count[2]++;
if(count[2]>=ACCELERATED_SPEED_LENGTH)
{
status[2]=3;
}
break;
case RUN://匀速
step_to_run[2]--;
if(step_to_run[2]<1)
status[2]=2;
break;
case DECEL://减速
count[2]--;
__HAL_TIM_SetAutoreload(&htim8,period[count[2]]);
__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_3,period[count[2]]/2);
if(count[2]<1)
status[2]=0;
break;
case STOP://停止
// 关闭通道
TIM_CCxChannelCmd(TIM8, TIM_CHANNEL_3, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htim8, TIM_FLAG_CC3);
break;
}
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
num_callback[3]++;
if(num_callback[3]%2==0)
{
switch(status[3])
{
case ACCEL://加速
__HAL_TIM_SetAutoreload(&htim8,period[count[3]]);
__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_4,period[count[3]]/2);
count[3]++;
if(count[3]>=ACCELERATED_SPEED_LENGTH)
{
status[3]=3;
}
break;
case RUN://匀速
step_to_run[3]--;
if(step_to_run[3]<1)
status[3]=2;
break;
case DECEL://减速
count[3]--;
__HAL_TIM_SetAutoreload(&htim8,period[count[3]]);
__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_4,period[count[3]]/2);
if(count[3]<1)
status[1]=0;
break;
case STOP://停止
// 关闭通道
TIM_CCxChannelCmd(TIM8, TIM_CHANNEL_4, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htim8, TIM_FLAG_CC4);
break;
}
}
}
}
#ifndef __bsp_stepmotor_H
#define __bsp_stepmotor_H
#include "tim.h"
#ifdef __cplusplus
extern "C" {
#endif
#define S_ACCEL 1
#define T_ACCEL 0
/* 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 // 加减速曲线状态:匀速阶段
void CalculateSModelLine(float fre[], unsigned short period[], float len, float fre_max, float fre_min, float flexible);
#endif
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
设置完定时器各通道参数及回调函数后即可在main函数中启动定时器
...////省略部分代码
CalculateSModelLine(fre,period,ACCELERATED_SPEED_LENGTH,FRE_MAX,FRE_MIN,4);
HAL_TIM_Base_Start(&htim8);//启动定时器
HAL_TIM_OC_Start_IT(&htim8, TIM_CHANNEL_1);//启动定时器8通道1比较输出中断
HAL_TIM_OC_Start_IT(&htim8, TIM_CHANNEL_2);//启动定时器8通道2比较输出中断
HAL_TIM_OC_Start_IT(&htim8, TIM_CHANNEL_3);//启动定时器8通道3比较输出中断
HAL_TIM_OC_Start_IT(&htim8, TIM_CHANNEL_4);//启动定时器8通道4比较输出中断
while(1)
...//省略部分代码
这样代码就完成,烧写进去后每次复位开机可以看到4个电机开始S型加速运行一周,如果需要对电机做不同的加速修改相应的参数即可
单个电机S型加速过程参见上一篇博客