DMA 原理从 0 到 1:为什么它能解放 CPU?一文讲透 DMA 的工作流程
【福利三:雨露均沾·逢7狂欢】之五:STM32系统时钟PLL故障排除1例
【福利三:雨露均沾·逢7狂欢】之三:AI帮我查BUG
福利三:雨露均沾·逢7狂欢】之二:STM32F407VG串口通信乱码故障的排除
基于STM32F103的I2C主从机通信
OpenBLT移植到STM32F103战舰开发板上适用于所有STM32F103系列的Bootloader
TFT LCD 与 FSMC 的硬件连接大容量 STM32F10xxx FSMC 接口
单片机:初学者该了解的STM32F103基础知识
2025软件工具兔哥知道
STM32之继电器模块
微信公众号
手机版
/* Initialize all configured peripherals */
MX_GPIO_Init();% V+ t$ \" M- l/ l% x! ~
MX_USART2_UART_Init();; M* O0 u$ S! m+ @
MX_TIM1_Init();9 l O$ `: W7 e' g
STEPMOTOR_TIMx_Init(); /定时器输出初始化$ o& C5 c/ @- E* W
/* USER CODE BEGIN 2 */
STEPMOTOR_OUTPUT_DISABLE(); //TMC2160禁止使能
/* USER CODE END 2 */ k% G6 t4 q9 A, F/ ~7 u$ n% V7 f
/* Infinite loop */" q2 \7 S" f2 Z% }1 V3 w% u& ^
/* USER CODE BEGIN WHILE */0 `7 Y4 Q F, ]- o6 Y& w
while (1)" h \& s! _1 M- Q$ G0 F) @
{
/* USER CODE END WHILE */: ^5 g! v6 q8 ]
STEPMOTOR_AxisMoveRel(6400*-2, 5000 , 5000 , 1200); //控制TMC2160驱动步进电机反转2圈(32细分,1.8度则一圈需要6400个脉冲)( l! H$ Y1 m S* {' D7 M e
LedOnOff(); //LED闪烁处理4 ]7 k, r% r4 v# O3 i
STEPMOTOR_AxisMoveRel(6400*2, 5000 , 5000 , 1200); //控制TMC2160驱动步进电机反转2圈(32细分,1.8度则一圈需要6400个脉冲)
LedOnOff(); //LED闪烁处理8 U0 l) R0 p) U
/* USER CODE BEGIN 3 */3 ~8 C7 E+ l5 L) d
}
/** _; h& ?! M' R* _0 C
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).$ t/ M" K% }, P+ G4 V- S5 }
accel 加速度,实际值为accel*0.1*rad/sec^2
decel 减速度,实际值为decel*0.1*rad/sec^2, h- _$ f3 E7 d4 D
speed 最大速度,实际值为speed*0.1*rad/sec! y7 n$ r! Q7 u3 U0 E
* 返 回 值: 无! h7 i; E6 V; |, @9 @
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且# d$ ^% l3 t$ ^4 N5 u9 Z% ?
* 速度很慢,那还没达到最大速度就要开始减速
*/
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{
__IO uint16_t tim_count;
// 达到最大速度时的步数
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)) a. V7 M1 c- \
__IO uint32_t accel_lim;/ i. |7 t. b7 \1 V7 X
if(step < 0) // 步数为负数3 _ u, W" u: k0 c3 \
{
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();% k8 U9 ]$ Z# g- M/ s* {, S$ M
step =-step; // 获取步数绝对值
}
else* O. A7 E( B. c6 k
{
srd.dir = CW; // 顺时针方向旋转# s4 ?( ?/ U3 Q- u
STEPMOTOR_DIR_FORWARD();
}
' d% P. e1 H, C0 Y, b/ f$ @
if(step == 1) // 步数为1
{* k7 ^$ r+ Y8 v$ m$ Z) q
srd.accel_count = -1; // 只移动一步
srd.run_state = DECEL; // 减速状态.
srd.step_delay = 1000; // 短延时 % g" Y s3 D4 a u5 |) u& d
}$ }' a: i* o/ c9 R- d
else if(step != 0) // 如果目标运动步数不为0# {+ D4 M7 N+ O$ F4 H
{" O% S( ]' M3 g" ]
// 我们的驱动器用户手册有详细的计算及推导过程
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w* _7 X5 q* S) o- `9 a& `
srd.min_delay = (int32_t)(A_T_x10/speed);
9 f7 t @0 ~0 z P
// 通过计算第一个(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" h- r7 z( w& b* @2 z
srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);# [' J, H3 _1 H% {6 v6 ?
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)0 k$ t( c3 U2 T6 ?2 j
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));* V" S) M4 x+ l' W: p
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度0 O3 ]# V, g$ Y3 W) z+ p
if(max_s_lim == 0){
max_s_lim = 1;
}4 B3 g, q; K* B
// n1 = (n1+n2)decel / (accel + decel)" ]5 }8 M0 B2 a% x) W5 L' I6 M f# U
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.$ w2 L W' p& r3 ]$ P) L7 C' t
if(accel_lim == 0){& G/ n1 V/ \' ^3 Y' ~8 I
accel_lim = 1;) X5 B. [( `1 h4 D$ ?6 c
}; S2 |, D4 |$ b+ T& S3 C
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){; m+ G$ V1 \3 f% v! e
srd.decel_val = accel_lim - step;
}; c& y) Z0 X- n
else{ a2 @. E% h3 `- N8 z4 S6 W1 [
srd.decel_val = -(max_s_lim*accel/decel);
}! ?. D. w' V: C; ?: l
// 当只剩下一步我们必须减速/ u1 N$ {; T" ~; K
if(srd.decel_val == 0){. M; o' l9 p* O1 ]! J9 j- V
srd.decel_val = -1;0 q" L3 W9 Y0 c) M% F% d5 P
}
// 计算开始减速时的步数
srd.decel_start = step + srd.decel_val;
// 如果最大速度很慢,我们就不需要进行加速运动
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;, A9 c4 t% `5 j# |: m+ ]
srd.run_state = RUN;& S# m8 J* W* D9 r b* [2 x( _
}/ ~7 S3 X0 T' e n0 \- \3 K5 [; e
else{: r7 \. a9 c; { X/ u% k% _0 P
srd.run_state = ACCEL;3 F7 ]4 j7 ~' m) \$ Z
} 8 t7 Y6 O% S4 ^
// 复位加速度计数值/ k8 a r) j( P% h2 r
srd.accel_count = 0;" ^! J/ g3 ?. _( M) ~" Z% F
}
MotionStatus = 1; // 电机为运动状态
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);1 ^; p6 M; r, o5 q0 c/ L
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay); // 设置定时器比较值
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_ENABLE); // 使能定时器通道 8 B- r% z4 ~' y) r5 d% g
STEPMOTOR_OUTPUT_ENABLE();: ^$ s) h$ {6 F" _1 Z
}( F* V: _& W4 ~: c) C1 p; c
/**( N0 u$ I' l' w
* 函数功能: 定时器中断服务函数. d! q. V t3 V {8 y+ l
* 输入参数: 无# g: W% B+ k9 @7 \
* 返 回 值: 无
* 说 明: 实现加减速过程: i/ e- e _% z$ G' t
*/
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理, T7 |" @, {: F4 [. |
{
__IO uint16_t tim_count=0;" b" b) f( {3 N# V: ?) p8 `! f
// 保存新(下)一个延时周期
uint16_t new_step_delay=0;* \3 f( A- U+ o
// 加速过程中最后一次延时(脉冲周期).& y2 ^% Z# V, r# J9 o
__IO static uint16_t last_accel_delay=0;1 e3 q0 r4 X' `9 u
// 总移动步数计数器
__IO static uint32_t step_count = 0;
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲* U: D" c- d: n( U5 R3 E. B9 O
__IO static uint8_t i=0;
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)( z+ ^5 g+ @ F0 E( ~9 v( A$ j
{$ Z( _( Z& F( ]
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);+ Q: a% X/ Q4 c- a' Z1 P5 d& c$ R
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);5 N/ U/ b& ?5 R3 I( A" h
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);
; M$ H! }5 u, R, E0 u
i++; // 定时器中断次数计数值
if(i==2) // 2次,说明已经输出一个完整脉冲
{$ p9 h: E" q2 {
i=0; // 清零定时器中断次数计数值
switch(srd.run_state) // 加减速曲线阶段- p$ j7 U; g' [* z) H4 W" f
{& O* \3 ^0 }; T4 k/ v0 [
case STOP:
step_count = 0; // 清零步数计数器
rest = 0; // 清零余值
// 关闭通道# Y( }) Z0 u G& V
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE); " i9 N- e+ C3 q: q
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);0 A; r6 X# y+ P; h
STEPMOTOR_OUTPUT_DISABLE();
MotionStatus = 0; // 电机为停止状态
break;
: c* |8 i- t7 Z3 X4 L
case ACCEL:: S8 M( I+ i' N" l: V
step_count++; // 步数加10 E# F8 L( ], {0 ^) b
if(srd.dir==CW); R0 \4 k+ |8 Z0 u* `! ~% v% C
{ * d& P; Z, s; }1 a
step_position++; // 绝对位置加1# ^1 j& @: K% [: l4 w! G
}& g; [6 v# R3 {8 i) v# N' `9 P, P
else
{
step_position--; // 绝对位置减1, P5 [! G+ J; P& j) u
}! n, u7 n$ d1 E- n
srd.accel_count++; // 加速计数值加1
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)// 检查是够应该开始减速
{* L; v# W/ j$ |! B, c
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}' l6 ]" q" {0 P. k7 R
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{5 L* w( w- {, Y$ y( p
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)2 m" D2 {, n: o9 J X% \4 E. o; x
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
rest = 0; // 清零余值1 H# W3 F/ U8 V& t0 o6 I6 D
srd.run_state = RUN; // 设置为匀速运行状态9 y& B: ?4 H! v3 U
}" s& x; i/ L2 R
break;1 Z: i9 h8 Y5 F5 O6 x L
case RUN:( B2 O3 @7 s2 k
step_count++; // 步数加1% \4 O% i {9 J# H
if(srd.dir==CW)) Z2 s [, `5 Q! o/ N
{ - J. v7 A. Y7 F- k3 Z! F. A9 c
step_position++; // 绝对位置加1# a/ N" s+ V* r" T! g
}
else
{
step_position--; // 绝对位置减1
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
if(step_count >= srd.decel_start) // 需要开始减速
{
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)6 @4 ^ K9 Q8 e8 T& ~6 R; B8 Q
srd.run_state = DECEL; // 状态改变为减速0 x& u+ u9 D2 X0 O K
}
break;
case DECEL:
step_count++; // 步数加1
if(srd.dir==CW)
{
step_position++; // 绝对位置加1" M# c# }: K9 N7 @$ ?
}! a) C4 t5 Z6 d0 Z, \' v
else
{4 c4 r( A; u; b' T8 V( ~% c
step_position--; // 绝对位置减1! I. N* j8 y v5 R
}9 D% w" q# f! [, d
srd.accel_count++;' t! ~# R& y3 y3 A8 ?6 v. F: M2 H
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);// 计算余数,下次计算补上余数,减少误差! z4 F, y& E* c- n' S# I
/ @( m, i! ?* \! V K) a) y5 W
//检查是否为最后一步
if(srd.accel_count >= 0)5 U/ I- w. b9 ~7 J8 w8 H: {
{& Z( L+ Y( B- r. ~' s+ ]. r
srd.run_state = STOP;
}
break;( Z. x! e6 e3 h4 ~0 ?" T' |, |
}
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值8 ~, L/ `7 B# r/ h0 r6 E
}
}
}
如果确实需要原理图和PCB的用户,请联系我们的客服或管理员私下索取谢谢!& Z% J- X9 A' V6 N
技术群:171897584. a% w+ ~; F8 {) Z8 Z; ?) p8 i
公众号:游名开源
是的,参考他们的,有说明:写着参考硬石的