你的浏览器版本过低,可能导致网站不能正常访问!为了你能正常使用网站功能,请使用这些浏览器。
cpsrd570 发表于 2020-5-9 18:22. C1 K4 p( F- t3 E; L& O 电机相对运动的函数和中断函数看着像硬石开发板里面的代码。
小马哥STM32F103开源小四轴RoboFly全部资料大放送
【MCU实战经验】+STM32F103的uCOSII详细移植
STM32中BOOT的作用
STM32如何分配原理图IO
STM32的I2S外设
STM32电路知识学习
基于STM32F1的CAN通信之DMA
STM32怎么选型
简单分析STM32和51的区别
简单聊聊STM32的SPI外设
/* Initialize all configured peripherals */$ K1 f' c+ i4 Y* e3 e+ a. U! ]
MX_GPIO_Init();
MX_USART2_UART_Init();; ^" m0 L( c: Z) U
MX_TIM1_Init();
STEPMOTOR_TIMx_Init(); /定时器输出初始化
/* USER CODE BEGIN 2 */& L+ {) h4 n1 @ Q; y) g& W
STEPMOTOR_OUTPUT_DISABLE(); //TMC2160禁止使能
/* USER CODE END 2 */. s0 _! d; f: ]6 T% E
/* Infinite loop */1 r! K& Q2 v1 _4 }# X H* J3 l
/* USER CODE BEGIN WHILE */6 U' D4 s h: K( p c
while (1)- @% a% S+ H5 {% c9 q8 t# C+ x5 v
{
/* USER CODE END WHILE */
STEPMOTOR_AxisMoveRel(6400*-2, 5000 , 5000 , 1200); //控制TMC2160驱动步进电机反转2圈(32细分,1.8度则一圈需要6400个脉冲)# }- G2 @( w9 v% t5 H
LedOnOff(); //LED闪烁处理" l% p5 j) N# n: \" Y K! ^" ?
STEPMOTOR_AxisMoveRel(6400*2, 5000 , 5000 , 1200); //控制TMC2160驱动步进电机反转2圈(32细分,1.8度则一圈需要6400个脉冲)
LedOnOff(); //LED闪烁处理
/* USER CODE BEGIN 3 */3 t+ Z% S9 W/ i5 C% m' K. l; j$ b
}
/**
* 函数功能: 相对位置运动:运动给定的步数% H2 d: }5 x( ?/ z- ?& L3 T
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).8 F; R+ G7 `9 j& a
accel 加速度,实际值为accel*0.1*rad/sec^2+ O8 `& ]' R; T: G
decel 减速度,实际值为decel*0.1*rad/sec^22 W" x, M0 `& X. Y
speed 最大速度,实际值为speed*0.1*rad/sec
* 返 回 值: 无
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且
* 速度很慢,那还没达到最大速度就要开始减速/ k/ \( g9 @3 R7 L/ C
*/- d3 j% f$ @1 S. I* x
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{
__IO uint16_t tim_count;
// 达到最大速度时的步数& ~% @+ y& e( `, H1 \5 F& u
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t accel_lim;1 S- `9 P- U J
, {( w3 G& s7 L2 x9 P) {8 ~
if(step < 0) // 步数为负数% G! X' G( x9 H3 L0 R2 k7 ?
{) F( Q4 @& l: O6 C1 j
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();8 s6 S/ j' q q$ Q ?
step =-step; // 获取步数绝对值. e' M$ ^" _! n5 ~' ]' f C. ~4 \2 \
}
else3 U5 }0 U ~. r& C
{/ L! M% t: G4 o2 M
srd.dir = CW; // 顺时针方向旋转
STEPMOTOR_DIR_FORWARD();! r6 |: S! f8 b8 X
} ?: h! Q/ i& C4 }/ `) S7 ?0 W5 r
- i$ N. @. D2 _3 }: ^
if(step == 1) // 步数为1
{
srd.accel_count = -1; // 只移动一步" O- `- g# K/ q) L
srd.run_state = DECEL; // 减速状态.) v5 ~6 ~* k# r* w6 l) J
srd.step_delay = 1000; // 短延时
}6 x4 r b& x% m3 n" S m
else if(step != 0) // 如果目标运动步数不为0+ c$ D6 b8 S0 [! L
{
// 我们的驱动器用户手册有详细的计算及推导过程5 u8 N* `, {" Y% U( }8 Y4 j
" R0 t5 Y; v L4 |+ f1 i# ]# v
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。. d2 L3 h2 r; _; J! E0 a/ C4 a
// min_delay = (alpha / tt)/ w
srd.min_delay = (int32_t)(A_T_x10/speed);
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^21 X* M9 m! S5 l; A8 }+ a* \# }' Y
// step_delay = 1/tt * sqrt(2*alpha/accel)9 [' R9 n9 H- v# e/ q* d
// step_delay = ( tfreq*0.676/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/100: ?( N+ E; D7 E+ [
srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);
4 ?+ ?2 D, f1 \* h* ]
// 计算多少步之后达到最大速度的限制 `0 D1 s' t) f
// max_s_lim = speed^2 / (2*alpha*accel)# r: R; w- t. t
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));4 P- T0 h1 Y# b3 d; u
// 如果达到最大速度小于0.5步,我们将四舍五入为06 n h9 [% _' ?, t* } Q$ a! ~
// 但实际我们必须移动至少一步才能达到想要的速度
if(max_s_lim == 0){% ~3 f% S$ V1 g7 b" q2 Z6 X
max_s_lim = 1;
}# s: m7 n' p& w" g
// n1 = (n1+n2)decel / (accel + decel)
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.- w0 L# Q- O# `# P6 p- F4 p; c
if(accel_lim == 0){# d k( o1 h3 J# I! r( z2 `& q
accel_lim = 1;# o$ l: M# h: x7 _0 h4 q
}1 |, R0 s7 k. A9 o3 c& q$ x
( e$ F& Q' l! j0 r1 h0 u4 l
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){
srd.decel_val = accel_lim - step;# a: U% w0 Y6 C1 Y: g- e
}2 ~9 |# s4 S6 N) ~
else{
srd.decel_val = -(max_s_lim*accel/decel);
}
// 当只剩下一步我们必须减速5 ~4 l) S7 u3 J6 u3 K+ }
if(srd.decel_val == 0){* n" y' u0 H: H' T1 k8 r
srd.decel_val = -1;5 `) ?& c5 \ D# ^9 @: @
}- C" c, |3 h' r( v- |
" Q1 C; B4 ]$ w: o
// 计算开始减速时的步数
srd.decel_start = step + srd.decel_val;
$ Q' @" }- h5 u7 l U3 |
// 如果最大速度很慢,我们就不需要进行加速运动% W: ?* {2 L1 H1 o
if(srd.step_delay <= srd.min_delay){7 c, Q1 Y5 O3 r9 b
srd.step_delay = srd.min_delay;# Z8 x' a- H" q) m
srd.run_state = RUN;: d/ C; Y4 U5 f2 `! R
}& e' P. m- V' {0 X
else{
srd.run_state = ACCEL;: T9 U$ W* E# j6 h/ x4 i
}
// 复位加速度计数值* g2 F; m9 G, U$ p
srd.accel_count = 0;
}# j( `, V/ `! T& v2 }; J0 ~6 t
MotionStatus = 1; // 电机为运动状态
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay); // 设置定时器比较值3 Y: y! f* [# a# L1 l* a+ K9 k
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_ENABLE); // 使能定时器通道
STEPMOTOR_OUTPUT_ENABLE();5 x0 _5 x' `% T: L* u
}0 Q, a! C/ s% a2 Q9 Q) v+ m6 w
/**
* 函数功能: 定时器中断服务函数
* 输入参数: 无8 [9 z' q; q/ I) U d, n7 E
* 返 回 值: 无7 b9 ^* Z5 ]# ?! Y! w* ?
* 说 明: 实现加减速过程
*/
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{ & w- c( g; w' S, W* R2 L
__IO uint16_t tim_count=0;
// 保存新(下)一个延时周期/ O' x" m( c; ^7 B9 R
uint16_t new_step_delay=0;
// 加速过程中最后一次延时(脉冲周期). M: C) I* K) B. k9 z
__IO static uint16_t last_accel_delay=0;
// 总移动步数计数器
__IO static uint32_t step_count = 0;
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲( a9 v/ @) K. A2 ]
__IO static uint8_t i=0;
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)# V2 P! U4 R' n5 C; u/ S* \
{
// 清楚定时器中断# A, I2 k% R/ e. ], R0 d
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);1 S0 u9 Y/ e' B# s8 b) j z2 R
& @0 h' r5 n) y
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);
i++; // 定时器中断次数计数值2 P' h# X2 f! N$ d ?
if(i==2) // 2次,说明已经输出一个完整脉冲7 ^5 v6 k- Q- H
{
i=0; // 清零定时器中断次数计数值
switch(srd.run_state) // 加减速曲线阶段; i# L5 L4 R a$ l# J
{- S3 n x7 D3 ?; D
case STOP:2 Z" [, S7 q! G/ K8 M6 D
step_count = 0; // 清零步数计数器
rest = 0; // 清零余值
// 关闭通道
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE); - ]+ x, F$ ~9 p
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);
STEPMOTOR_OUTPUT_DISABLE();! t1 r8 l4 C# X+ H
MotionStatus = 0; // 电机为停止状态 % e1 d6 n$ L0 Z! G
break;
1 e( G$ D6 H2 P) V3 r8 p
case ACCEL:
step_count++; // 步数加15 N0 S; z! G0 O( z$ T
if(srd.dir==CW) D$ h& a& m! I# i7 r& [
{ & b, Q" k. ]7 n2 t) V2 j
step_position++; // 绝对位置加1* W; k5 N5 ]" s) H- [- H6 D- o. q* W
}% C; d7 f. I4 n! f2 N O5 ~0 h$ i
else
{
step_position--; // 绝对位置减1
}
srd.accel_count++; // 加速计数值加12 E+ h1 C" f3 T6 |3 |: j9 |4 A
new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
if(step_count >= srd.decel_start)// 检查是够应该开始减速
{
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值 j6 e2 L2 e( _/ A6 ^" U
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{ M. ]3 D' f: e+ X
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期): I0 V1 ^2 N) v5 G
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)6 X5 N1 X7 ]5 y7 G7 G
rest = 0; // 清零余值
srd.run_state = RUN; // 设置为匀速运行状态$ i- ]5 T5 a3 w q1 v6 R
}
break;. P7 v6 L$ ^4 a/ L
' V' S; y& f3 g
case RUN:2 b- U( Y3 S5 O2 `
step_count++; // 步数加1
if(srd.dir==CW)
{ 8 k$ ~" N5 C: Z8 j
step_position++; // 绝对位置加1+ H( D+ V% C$ S& o$ [) n- w
}# O" J( R: U$ \, Z% y
else
{
step_position--; // 绝对位置减1
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
if(step_count >= srd.decel_start) // 需要开始减速. G, q4 o% |9 R& ^) M
{
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
srd.run_state = DECEL; // 状态改变为减速) k+ F! T, Z% P6 W
}
break;, ?6 b6 A7 }: l: Z
1 o; b3 {; q9 B0 K7 P! E. C9 g5 @2 e
case DECEL:
step_count++; // 步数加14 C2 Y8 B" d% c6 D) [* Y
if(srd.dir==CW)1 E/ _- l9 D+ k
{
step_position++; // 绝对位置加1# `2 w8 T+ b+ o! f3 l% U
}2 t! g6 X P* f: q
else2 D( q' I, k% ?! F
{
step_position--; // 绝对位置减1" L/ q! c5 ^( t6 A& q) T8 M! l
}# ]4 ]/ R# N! j
srd.accel_count++;' T/ X/ a% I9 B, ?: o
new_step_delay = srd.step_delay - (((2 * srd.step_delay) + rest)/(4 * srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔)' x5 }# V6 I6 \% c( P5 I
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
//检查是否为最后一步
if(srd.accel_count >= 0)9 x. z0 \/ F& H- A& S+ F8 ^0 o
{0 y( D* C t' ~
srd.run_state = STOP;+ M( k+ B, _- x9 F) L
}4 y/ O8 E4 q7 n
break;
} ! B: e+ C; {* W4 O3 [: p6 S
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值0 H8 j6 }, |$ S1 |. q* @
}
}" ~8 x! A1 Q6 G6 K/ a
}- ~# R9 t; c1 ^0 ~. K R. F
如果确实需要原理图和PCB的用户,请联系我们的客服或管理员私下索取谢谢!
+ R+ v0 I2 ^+ U d [/ T0 M
技术群:171897584
公众号:游名开源
是的,参考他们的,有说明:写着参考硬石的