(这里用两个定时器主要是为了学习配置多个定时器)
1.motor.c文件
#include "Motor.h"
#include
X_speedRampData X_srd = {STOP,CW,0,0,0,0,0}; // X加减速曲线变量
__IO int32_t X_step_position = 0; // X当前位置
__IO uint8_t X_MotionStatus = 0; //X是否在运动?0:停止,1:运动
Y_speedRampData Y_srd = {STOP,CW,0,0,0,0,0}; // Y加减速曲线变量
__IO int32_t Y_step_position = 0; // Y当前位置
__IO uint8_t Y_MotionStatus = 0; //Y是否在运动?0:停止,1:运动
P_speedRampData P_srd = {STOP,CW,0,0,0,0,0}; // P加减速曲线变量
__IO int32_t P_step_position = 0; // P当前位置
__IO uint8_t P_MotionStatus = 0; //P是否在运动?0:停止,1:运动
extern TIM_HandleTypeDef htim2;
extern TIM_HandleTypeDef htim3;
/**
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).
accel 加速度,实际值为accel*0.025*rad/sec^2
decel 减速度,实际值为decel*0.025*rad/sec^2
speed 最大速度,实际值为speed*0.05*rad/sec
* 返 回 值: 无
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且
* 速度很慢,那还没达到最大速度就要开始减速
*/
/***X电机梯形加减速***/
void X_STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{
__IO uint16_t X_tim_count;
// X达到最大速度时的步数
__IO uint32_t X_max_s_lim;
// X必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t X_accel_lim;
if(step < 0) // 步数为负数
{
X_srd.dir = CCW; // 逆时针方向旋转
X_STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值
}
else
{
X_srd.dir = CW; // 顺时针方向旋转
X_STEPMOTOR_DIR_FORWARD();
}
if(step == 1) // 步数为1
{
X_srd.accel_count = -1; // 只移动一步
X_srd.run_state = DECEL; // 减速状态.
X_srd.step_delay = 1000; // 短延时
}
else if(step != 0) // 如果目标运动步数不为0
{
// 我们的驱动器用户手册有详细的计算及推导过程
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w
X_srd.min_delay = (int32_t)(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
X_srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)
X_max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度
if(X_max_s_lim == 0){
X_max_s_lim = 1;
}
// 计算多少步之后我们必须开始减速
// n1 = (n1+n2)decel / (accel + decel)
X_accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.
if(X_accel_lim == 0){
X_accel_lim = 1;
}
// 使用限制条件我们可以计算出减速阶段步数
if(X_accel_lim <= X_max_s_lim){
X_srd.decel_val = X_accel_lim - step;
}
else{
X_srd.decel_val = -(X_max_s_lim*accel/decel);
}
// 当只剩下一步我们必须减速
if(X_srd.decel_val == 0){
X_srd.decel_val = -1;
}
// 计算开始减速时的步数
X_srd.decel_start = step + X_srd.decel_val;
// 如果最大速度很慢,我们就不需要进行加速运动
if(X_srd.step_delay <= X_srd.min_delay){
X_srd.step_delay = X_srd.min_delay;
X_srd.run_state = RUN;
}
else{
X_srd.run_state = ACCEL;
}
// 复位加速度计数值
X_srd.accel_count = 0;
}
X_MotionStatus = 1; // 电机为运动状态
X_tim_count=__HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,X_tim_count+X_srd.step_delay); // 设置定时器比较值
HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_1);
TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_1, TIM_CCx_ENABLE);// 使能定时器通道
X_STEPMOTOR_OUTPUT_ENABLE();
}
/***Y电机梯形加减速***/
void Y_STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{
__IO uint16_t Y_tim_count;// X达到最大速度时的步数
__IO uint32_t Y_max_s_lim;// X必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t Y_accel_lim;
if(step < 0) // 步数为负数
{
Y_srd.dir = CCW; // 逆时针方向旋转
Y_STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值
}
else
{
Y_srd.dir = CW; // 顺时针方向旋转
Y_STEPMOTOR_DIR_FORWARD();
}
if(step == 1) // 步数为1
{
Y_srd.accel_count = -1; // 只移动一步
Y_srd.run_state = DECEL; // 减速状态.
Y_srd.step_delay = 1000; // 短延时
}
else if(step != 0) // 如果目标运动步数不为0
{
// 我们的驱动器用户手册有详细的计算及推导过程
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w
Y_srd.min_delay = (int32_t)(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
Y_srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)
Y_max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度
if(Y_max_s_lim == 0){
Y_max_s_lim = 1;
}
// 计算多少步之后我们必须开始减速
// n1 = (n1+n2)decel / (accel + decel)
Y_accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.
if(Y_accel_lim == 0){
Y_accel_lim = 1;
}
// 使用限制条件我们可以计算出减速阶段步数
if(Y_accel_lim <= Y_max_s_lim){
Y_srd.decel_val = Y_accel_lim - step;
}
else{
Y_srd.decel_val = -(Y_max_s_lim*accel/decel);
}
// 当只剩下一步我们必须减速
if(Y_srd.decel_val == 0){
Y_srd.decel_val = -1;
}
// 计算开始减速时的步数
Y_srd.decel_start = step + Y_srd.decel_val;
// 如果最大速度很慢,我们就不需要进行加速运动
if(Y_srd.step_delay <= Y_srd.min_delay){
Y_srd.step_delay = Y_srd.min_delay;
Y_srd.run_state = RUN;
}
else{
Y_srd.run_state = ACCEL;
}
// 复位加速度计数值
Y_srd.accel_count = 0;
}
Y_MotionStatus = 1; // 电机为运动状态
Y_tim_count=__HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,Y_tim_count+Y_srd.step_delay); // 设置定时器比较值
HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_2);
TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_2, TIM_CCx_ENABLE);// 使能定时器通道
Y_STEPMOTOR_OUTPUT_ENABLE();
}
/***P电机梯形加减速***/
void P_STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{
__IO uint16_t P_tim_count;
// X达到最大速度时的步数
__IO uint32_t P_max_s_lim;
// X必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t P_accel_lim;
if(step < 0) // 步数为负数
{
P_srd.dir = CCW; // 逆时针方向旋转
P_STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值
}
else
{
P_srd.dir = CW; // 顺时针方向旋转
P_STEPMOTOR_DIR_FORWARD();
}
if(step == 1) // 步数为1
{
P_srd.accel_count = -1; // 只移动一步
P_srd.run_state = DECEL; // 减速状态.
P_srd.step_delay = 1000; // 短延时
}
else if(step != 0) // 如果目标运动步数不为0
{
// 我们的驱动器用户手册有详细的计算及推导过程
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w
P_srd.min_delay = (int32_t)(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
P_srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)
P_max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度
if(P_max_s_lim == 0){
P_max_s_lim = 1;
}
// 计算多少步之后我们必须开始减速
// n1 = (n1+n2)decel / (accel + decel)
P_accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.
if(P_accel_lim == 0){
P_accel_lim = 1;
}
// 使用限制条件我们可以计算出减速阶段步数
if(P_accel_lim <= P_max_s_lim){
P_srd.decel_val = P_accel_lim - step;
}
else{
P_srd.decel_val = -(P_max_s_lim*accel/decel);
}
// 当只剩下一步我们必须减速
if(P_srd.decel_val == 0){
P_srd.decel_val = -1;
}
// 计算开始减速时的步数
P_srd.decel_start = step + P_srd.decel_val;
// 如果最大速度很慢,我们就不需要进行加速运动
if(P_srd.step_delay <= P_srd.min_delay){
P_srd.step_delay = P_srd.min_delay;
P_srd.run_state = RUN;
}
else{
P_srd.run_state = ACCEL;
}
// 复位加速度计数值
P_srd.accel_count = 0;
}
P_MotionStatus = 1; // 电机为运动状态
P_tim_count=__HAL_TIM_GET_COUNTER(&htim2);
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_3,P_tim_count+X_srd.step_delay); // 设置定时器比较值
HAL_TIM_OC_Start_IT(&htim2,TIM_CHANNEL_3);
TIM_CCxChannelCmd(TIM2,TIM_CHANNEL_3, TIM_CCx_ENABLE);// 使能定时器通道
P_STEPMOTOR_OUTPUT_ENABLE();
}
/**
* 函数功能: 定时器中断服务函数
* 输入参数: 无
* 返 回 值: 无
* 说 明: 实现加减速过程
*/
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)//定时器中断处理
{
/*X电机*/
__IO uint16_t X_tim_count=0;
// X保存新(下)一个延时周期
uint16_t X_new_step_delay=0;
// X加速过程中最后一次延时(脉冲周期).
__IO static uint16_t X_last_accel_delay=0;
// X总移动步数计数器
__IO static uint32_t X_step_count = 0;
// X记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t X_rest = 0;
//X定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t X_i=0;
/*Y电机*/
__IO uint16_t Y_tim_count=0;
// Y保存新(下)一个延时周期
uint16_t Y_new_step_delay=0;
// Y加速过程中最后一次延时(脉冲周期).
__IO static uint16_t Y_last_accel_delay=0;
// Y总移动步数计数器
__IO static uint32_t Y_step_count = 0;
// X记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t Y_rest = 0;
//Y定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t Y_i=0;
/*P电机*/
__IO uint16_t P_tim_count=0;
// Y保存新(下)一个延时周期
uint16_t P_new_step_delay=0;
// Y加速过程中最后一次延时(脉冲周期).
__IO static uint16_t P_last_accel_delay=0;
// Y总移动步数计数器
__IO static uint32_t P_step_count = 0;
// X记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t P_rest = 0;
//Y定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t P_i=0;
if(htim->Instance==TIM3)
{
/*X电机的定时器配置*/
if(__HAL_TIM_GET_IT_SOURCE(&htim3, TIM_IT_CC1) !=RESET)
{
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htim3, TIM_IT_CC1);
// 设置比较值
X_tim_count=__HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,X_tim_count+X_srd.step_delay);
X_i++; // 定时器中断次数计数值
if(X_i==2) // 2次,说明已经输出一个完整脉冲
{
X_i=0; // 清零定时器中断次数计数值
switch(X_srd.run_state) // 加减速曲线阶段
{
case STOP:
X_step_count = 0; // 清零步数计数器
X_rest = 0; // 清零余值
// 关闭通道
TIM_CCxChannelCmd(TIM3, TIM_CHANNEL_1, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_CC1);
X_STEPMOTOR_OUTPUT_DISABLE();
X_MotionStatus = 0; // 电机为停止状态
break;
case ACCEL:
X_step_count++; // 步数加1
if(X_srd.dir==CW)
{
X_step_position++; // 绝对位置加1
}
else
{
X_step_position--; // 绝对位置减1
}
X_srd.accel_count++; // 加速计数值加1
X_new_step_delay = X_srd.step_delay - (((2 *X_srd.step_delay) + X_rest)/(4 * X_srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)
X_rest = ((2 * X_srd.step_delay)+X_rest)%(4 * X_srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
if(X_step_count >= X_srd.decel_start)// 检查是够应该开始减速
{
X_srd.accel_count = X_srd.decel_val; // 加速计数值为减速阶段计数值的初始值
X_srd.run_state = DECEL; // 下个脉冲进入减速阶段
}
else if(X_new_step_delay <= X_srd.min_delay) // 检查是否到达期望的最大速度
{
X_last_accel_delay = X_new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)
X_new_step_delay = X_srd.min_delay; // 使用min_delay(对应最大速度speed)
X_rest = 0; // 清零余值
X_srd.run_state = RUN; // 设置为匀速运行状态
}
break;
case RUN:
X_step_count++; // 步数加1
if(X_srd.dir==CW)
{
X_step_position++; // 绝对位置加1
}
else
{
X_step_position--; // 绝对位置减1
}
X_new_step_delay = X_srd.min_delay; // 使用min_delay(对应最大速度speed)
if(X_step_count >= X_srd.decel_start) // 需要开始减速
{
X_srd.accel_count = X_srd.decel_val; // 减速步数做为加速计数值
X_new_step_delay = X_last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
X_srd.run_state = DECEL; // 状态改变为减速
}
break;
case DECEL:
X_step_count++; // 步数加1
if(X_srd.dir==CW)
{
X_step_position++; // 绝对位置加1
}
else
{
X_step_position--; // 绝对位置减1
}
X_srd.accel_count++;
X_new_step_delay = X_srd.step_delay - (((2 * X_srd.step_delay) + X_rest)/(4 * X_srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔)
X_rest = ((2 * X_srd.step_delay)+X_rest)%(4 * X_srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
//检查是否为最后一步
if(X_srd.accel_count >= 0)
{
X_srd.run_state = STOP;
}
break;
}
X_srd.step_delay = X_new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}
}
/*Y电机的定时器配置*/
if(__HAL_TIM_GET_IT_SOURCE(&htim3, TIM_IT_CC2) !=RESET)
{
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htim3, TIM_IT_CC2);
// 设置比较值
Y_tim_count=__HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,Y_tim_count+Y_srd.step_delay);
Y_i++; // 定时器中断次数计数值
if(Y_i==2) // 2次,说明已经输出一个完整脉冲
{
Y_i=0; // 清零定时器中断次数计数值
switch(Y_srd.run_state) // 加减速曲线阶段
{
case STOP:
Y_step_count = 0; // 清零步数计数器
Y_rest = 0; // 清零余值
// 关闭通道
TIM_CCxChannelCmd(TIM3, TIM_CHANNEL_2, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_CC2);
Y_STEPMOTOR_OUTPUT_DISABLE();
Y_MotionStatus = 0; // 电机为停止状态
break;
case ACCEL:
Y_step_count++; // 步数加1
if(Y_srd.dir==CW)
{
Y_step_position++; // 绝对位置加1
}
else
{
Y_step_position--; // 绝对位置减1
}
Y_srd.accel_count++; // 加速计数值加1
Y_new_step_delay = Y_srd.step_delay - (((2 *Y_srd.step_delay) + Y_rest)/(4 * Y_srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)
Y_rest = ((2 * Y_srd.step_delay)+Y_rest)%(4 * Y_srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
if(Y_step_count >= Y_srd.decel_start)// 检查是够应该开始减速
{
Y_srd.accel_count = Y_srd.decel_val; // 加速计数值为减速阶段计数值的初始值
Y_srd.run_state = DECEL; // 下个脉冲进入减速阶段
}
else if(Y_new_step_delay <= Y_srd.min_delay) // 检查是否到达期望的最大速度
{
Y_last_accel_delay = Y_new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)
Y_new_step_delay = Y_srd.min_delay; // 使用min_delay(对应最大速度speed)
Y_rest = 0; // 清零余值
Y_srd.run_state = RUN; // 设置为匀速运行状态
}
break;
case RUN:
Y_step_count++; // 步数加1
if(Y_srd.dir==CW)
{
Y_step_position++; // 绝对位置加1
}
else
{
Y_step_position--; // 绝对位置减1
}
Y_new_step_delay = Y_srd.min_delay; // 使用min_delay(对应最大速度speed)
if(Y_step_count >= Y_srd.decel_start) // 需要开始减速
{
Y_srd.accel_count = Y_srd.decel_val; // 减速步数做为加速计数值
Y_new_step_delay = Y_last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
Y_srd.run_state = DECEL; // 状态改变为减速
}
break;
case DECEL:
Y_step_count++; // 步数加1
if(Y_srd.dir==CW)
{
Y_step_position++; // 绝对位置加1
}
else
{
Y_step_position--; // 绝对位置减1
}
Y_srd.accel_count++;
Y_new_step_delay = Y_srd.step_delay - (((2 * Y_srd.step_delay) + Y_rest)/(4 * Y_srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔)
Y_rest = ((2 * Y_srd.step_delay)+Y_rest)%(4 * Y_srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
//检查是否为最后一步
if(Y_srd.accel_count >= 0)
{
Y_srd.run_state = STOP;
}
break;
}
Y_srd.step_delay = Y_new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}
}
}
if(htim->Instance==TIM2)
{
/*P电机的定时器配置*/
if(__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_CC3) !=RESET)
{
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htim2, TIM_IT_CC3);
// 设置比较值
P_tim_count=__HAL_TIM_GET_COUNTER(&htim2);
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_3,P_tim_count+P_srd.step_delay);
P_i++; // 定时器中断次数计数值
if(P_i==2) // 2次,说明已经输出一个完整脉冲
{
P_i=0; // 清零定时器中断次数计数值
switch(P_srd.run_state) // 加减速曲线阶段
{
case STOP:
P_step_count = 0; // 清零步数计数器
P_rest = 0; // 清零余值
// 关闭通道
TIM_CCxChannelCmd(TIM2, TIM_CHANNEL_3, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_CC3);
P_STEPMOTOR_OUTPUT_DISABLE();
P_MotionStatus = 0; // 电机为停止状态
break;
case ACCEL:
P_step_count++; // 步数加1
if(P_srd.dir==CW)
{
P_step_position++; // 绝对位置加1
}
else
{
P_step_position--; // 绝对位置减1
}
P_srd.accel_count++; // 加速计数值加1
P_new_step_delay = P_srd.step_delay - (((2 *P_srd.step_delay) + P_rest)/(4 * P_srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)
P_rest = ((2 * P_srd.step_delay)+P_rest)%(4 *P_srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
if(P_step_count >= P_srd.decel_start)// 检查是够应该开始减速
{
P_srd.accel_count = P_srd.decel_val; // 加速计数值为减速阶段计数值的初始值
P_srd.run_state = DECEL; // 下个脉冲进入减速阶段
}
else if(P_new_step_delay <= P_srd.min_delay) // 检查是否到达期望的最大速度
{
P_last_accel_delay = P_new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)
P_new_step_delay = P_srd.min_delay; // 使用min_delay(对应最大速度speed)
P_rest = 0; // 清零余值
P_srd.run_state = RUN; // 设置为匀速运行状态
}
break;
case RUN:
P_step_count++; // 步数加1
if(P_srd.dir==CW)
{
P_step_position++; // 绝对位置加1
}
else
{
P_step_position--; // 绝对位置减1
}
P_new_step_delay = P_srd.min_delay; // 使用min_delay(对应最大速度speed)
if(P_step_count >= P_srd.decel_start) // 需要开始减速
{
P_srd.accel_count = P_srd.decel_val; // 减速步数做为加速计数值
P_new_step_delay = P_last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
P_srd.run_state = DECEL; // 状态改变为减速
}
break;
case DECEL:
P_step_count++; // 步数加1
if(P_srd.dir==CW)
{
P_step_position++; // 绝对位置加1
}
else
{
P_step_position--; // 绝对位置减1
}
P_srd.accel_count++;
P_new_step_delay = P_srd.step_delay - (((2 * P_srd.step_delay) + P_rest)/(4 * P_srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔)
P_rest = ((2 * P_srd.step_delay)+P_rest)%(4 * P_srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
//检查是否为最后一步
if(P_srd.accel_count >= 0)
{
P_srd.run_state = STOP;
}
break;
}
P_srd.step_delay = P_new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}
}
}
}
//==================end【By_Gerhart】======================//
2.motor.h文件
#ifndef __MOTOR_H__
#define __MOTOR_H__
/*引用库函数*/
#include "main.h"
#define X_Motor_OFF() HAL_TIM_OC_Stop_IT(&htim3,TIM_CHANNEL_1)
#define Y_Motor_OFF() HAL_TIM_OC_Stop_IT(&htim3,TIM_CHANNEL_2)
#define P_Motor_OFF() HAL_TIM_OC_Stop_IT(&htim2,TIM_CHANNEL_3)
//#define Motor_EN() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
//#define Motor_DIS() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
/* 电机结构体宏定义 ------------------------------------------------------------------*/
typedef struct {
__IO uint8_t run_state ; // 电机旋转状态
__IO uint8_t dir ; // 电机旋转方向
__IO int32_t step_delay; // 下个脉冲周期(时间间隔),启动时为加速度
__IO uint32_t decel_start; // 启动减速位置
__IO int32_t decel_val; // 减速阶段步数
__IO int32_t min_delay; // 最小脉冲周期(最大速度,即匀速段速度)
__IO int32_t accel_count; // 加减速阶段计数值
}X_speedRampData;
typedef struct {
__IO uint8_t run_state ; // 电机旋转状态
__IO uint8_t dir ; // 电机旋转方向
__IO int32_t step_delay; // 下个脉冲周期(时间间隔),启动时为加速度
__IO uint32_t decel_start; // 启动减速位置
__IO int32_t decel_val; // 减速阶段步数
__IO int32_t min_delay; // 最小脉冲周期(最大速度,即匀速段速度)
__IO int32_t accel_count; // 加减速阶段计数值
}Y_speedRampData;
typedef struct {
__IO uint8_t run_state ; // 电机旋转状态
__IO uint8_t dir ; // 电机旋转方向
__IO int32_t step_delay; // 下个脉冲周期(时间间隔),启动时为加速度
__IO uint32_t decel_start; // 启动减速位置
__IO int32_t decel_val; // 减速阶段步数
__IO int32_t min_delay; // 最小脉冲周期(最大速度,即匀速段速度)
__IO int32_t accel_count; // 加减速阶段计数值
}P_speedRampData;
extern X_speedRampData X_srd;
extern __IO int32_t X_step_position;
extern __IO uint8_t X_MotionStatus;
extern Y_speedRampData Y_srd;
extern __IO int32_t Y_step_position;
extern __IO uint8_t Y_MotionStatus;
extern P_speedRampData P_srd;
extern __IO int32_t P_step_position;
extern __IO uint8_t P_MotionStatus;
#define STEPMOTOR_TIM_PRESCALER 3 // 步进电机驱动器细分设置为: 32 细分
// 定义定时器周期,输出比较模式周期设置为0xFFFF
#define STEPMOTOR_TIM_PERIOD 0xFFFF
#define FALSE 0
#define TRUE 1
#define CW 0 // 顺时针
#define CCW 1 // 逆时针
#define STOP 0 // 加减速曲线状态:停止
#define ACCEL 1 // 加减速曲线状态:加速阶段
#define DECEL 2 // 加减速曲线状态:减速阶段
#define RUN 3 // 加减速曲线状态:匀速阶段
#define T1_FREQ (SystemCoreClock/(STEPMOTOR_TIM_PRESCALER+1)) // 频率ft值
#define FSPR 200 //步进电机单圈步数
#define MICRO_STEP 32 // 步进电机驱动器细分数
#define SPR (FSPR*MICRO_STEP) // 旋转一圈需要的脉冲数
// 数学常数
#define ALPHA ((float)(2*3.14159/SPR)) // α= 2*pi/spr
#define A_T_x10 ((float)(10*ALPHA*T1_FREQ))
#define T1_FREQ_148 ((float)((T1_FREQ*0.676)/10)) // 0.676为误差修正值
#define A_SQ ((float)(2*100000*ALPHA))
#define A_x200 ((float)(200*ALPHA))
#define X_STEPMOTOR_DIR_FORWARD() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET)
#define X_STEPMOTOR_DIR_REVERSAL() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET)
#define Y_STEPMOTOR_DIR_FORWARD() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET)
#define Y_STEPMOTOR_DIR_REVERSAL() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_RESET)
#define P_STEPMOTOR_DIR_FORWARD() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_SET)
#define P_STEPMOTOR_DIR_REVERSAL() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET)
#define X_STEPMOTOR_OUTPUT_ENABLE(); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET)
#define X_STEPMOTOR_OUTPUT_DISABLE(); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET)
#define Y_STEPMOTOR_OUTPUT_ENABLE(); HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_SET)
#define Y_STEPMOTOR_OUTPUT_DISABLE(); HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET)
#define P_STEPMOTOR_OUTPUT_ENABLE(); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET)
#define P_STEPMOTOR_OUTPUT_DISABLE(); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET)
/*可以被外部使用的函数声明*/
void X_STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed);
void Y_STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed);
void P_STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed);
#endif
3. tim.c中添加使能函数
/* USER CODE BEGIN TIM2_Init 2 */
HAL_TIM_OC_Stop_IT(&htim2,TIM_CHANNEL_3); /*停止定时器2 比较输出通道3*/
TIM_CCxChannelCmd(TIM2,TIM_CHANNEL_3, TIM_CCx_DISABLE); /* 使能定时器2比较输出通道3 */
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_CC3); /* 清除指定的TIM2中断标志3 */
__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_CC3); /* 使能定时器2比较输出3 */
/* Enable the main output */
__HAL_TIM_MOE_ENABLE(&htim2); /* 启用TIM2主输出 */
HAL_TIM_Base_Start(&htim2); /* 使能定时器2 */
/* USER CODE END TIM2_Init 2 */
/* USER CODE BEGIN TIM3_Init 2 */
HAL_TIM_OC_Stop_IT(&htim3,TIM_CHANNEL_1); /*停止定时器3 比较输出通道1*/
HAL_TIM_OC_Stop_IT(&htim3,TIM_CHANNEL_2); /*停止定时器3 比较输出通道2*/
TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_1, TIM_CCx_DISABLE); /* 使能定时器3比较输出通道1 */
TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_2, TIM_CCx_DISABLE); /* 使能定时器3比较输出通道2 */
__HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_CC1); /* 清除指定的TIM3中断标志1 */
__HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_CC2); /* 清除指定的TIM3中断标志2 */
__HAL_TIM_ENABLE_IT(&htim3, TIM_IT_CC1); /* 使能定时器3比较输出1 */
__HAL_TIM_ENABLE_IT(&htim3, TIM_IT_CC2); /* 使能定时器3比较输出2 */
/* Enable the main output */
__HAL_TIM_MOE_ENABLE(&htim3); /* 启用TIM3主输出 */
HAL_TIM_Base_Start(&htim3); /* 使能定时器3 */
/* USER CODE END TIM3_Init 2 */
4. main函数配置
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
* *串口连接:
*******************孔板X轴移动の电机**********************************
PUL--->PA6
DIR--->PB8
ENA--->PB9
OPTO--->3.3V
*******************加液针头Y轴移动の电机****************************************
PUL--->PA7
DIR--->PB7
ENA--->PC7
OPTO--->3.3V
*******************蠕动泵の电机****************************************
PUL+-->5V
PUL--->PA2
DIR--->PC6
ENA--->PB12
******************************************************************************
* 此行为测试VS2022与Keil能否同步开发
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Motor.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t Tx_str1[] = "Wellcome_Gerhart!\r\n";
uint8_t Tx_str2[] = "X1_Forward!\r\n";
uint8_t Tx_str3[] = "X1_Reversal!\r\n";
uint8_t Tx_str4[] = "Stop!\r\n";
uint8_t Tx_str5[] = "Y1_Forward!\r\n";
uint8_t Tx_str6[] = "Y1_Reversal!\r\n";
uint8_t Tx_str7[] = "P1_Forward!\r\n";
uint8_t Tx_str8[] = "P1_Reversal!\r\n";
uint8_t Rx_dat = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart)
{
if (huart->Instance == USART1)//这部分作用是通过串口控制电机
{
if (Rx_dat == 0xa1)//发送A1电机X正转
{
X_STEPMOTOR_AxisMoveRel(1 * 16 * 200, 9, 9, 19);//设置X电机参数(转数,加速度,减速度,峰值速度)
HAL_UART_Transmit(&huart1, Tx_str2, sizeof(Tx_str2), 500);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
}
else if (Rx_dat == 0xa2)//发送A2电机X反转
{
X_STEPMOTOR_AxisMoveRel(1 * 16 * -200, 9, 9, 19);//设置X电机参数(转数,加速度,减速度,峰值速度)
HAL_UART_Transmit(&huart1, Tx_str3, sizeof(Tx_str3), 500);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
}
else if (Rx_dat == 0xa3)//发送A3电机X停止
{
X_Motor_OFF();
HAL_UART_Transmit(&huart1, Tx_str4, sizeof(Tx_str4), 500);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
}
else if (Rx_dat == 0xa4)//发送A4电机Y正转
{
Y_STEPMOTOR_AxisMoveRel(1 * 16 * 200, 9, 9, 19);//设置Y电机参数(转数,加速度,减速度,峰值速度)
HAL_UART_Transmit(&huart1, Tx_str5, sizeof(Tx_str5), 500);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
}
else if (Rx_dat == 0xa5)//发送A5电机Y反转
{
Y_STEPMOTOR_AxisMoveRel(1 * 16 * -200, 9, 9, 19);//设置Y电机参数(转数,加速度,减速度,峰值速度)
HAL_UART_Transmit(&huart1, Tx_str6, sizeof(Tx_str6), 500);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
}
else if (Rx_dat == 0xa6)//发送A6电机Y停止
{
Y_Motor_OFF();
HAL_UART_Transmit(&huart1, Tx_str4, sizeof(Tx_str4), 500);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
}
else if (Rx_dat == 0xa7)//发送A7电机P正转
{
P_STEPMOTOR_AxisMoveRel(1 * 16 * 200, 9, 9, 19);//设置P电机参数(转数,加速度,减速度,峰值速度)
HAL_UART_Transmit(&huart1, Tx_str7, sizeof(Tx_str7), 500);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
}
else if (Rx_dat == 0xa8)//发送A8电机P反转
{
P_STEPMOTOR_AxisMoveRel(1 * 16 * -200, 9, 9, 19);//设置P电机参数(转数,加速度,减速度,峰值速度)
HAL_UART_Transmit(&huart1, Tx_str8, sizeof(Tx_str8), 500);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
}
else if (Rx_dat == 0xa9)//发送A9电机P停止
{
P_Motor_OFF();
HAL_UART_Transmit(&huart1, Tx_str4, sizeof(Tx_str4), 500);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
}
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Transmit(&huart1, Tx_str1, sizeof(Tx_str1), 10000);
HAL_UART_Receive_IT(&huart1, &Rx_dat, 1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// HAL_Delay(1000);
// P_STEPMOTOR_AxisMoveRel(1*16*200, 9, 9 , 19);//设置X电机参数(转数,加速度,减速度,峰值速度)
// HAL_Delay(5000);
// P_STEPMOTOR_AxisMoveRel(1*16*-200, 9, 9 , 19);//设置X电机参数(转数,加速度,减速度,峰值速度)
// HAL_Delay(5000);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */