小马哥STM32F103开源小四轴RoboFly全部资料大放送
STM32固件库分享,超全系列整理
【MCU实战经验】+STM32F107的USB使用
基于STM32F103两轮平衡小车设计(开源)
STM32F107VCT6官方原理图和PCB
【福利】用STM32库的朋友有福了:STM32F10x_StdPeriph_Lib_V3.5.0chm...
基于STM32F10xx存储器和系统架构经验分享
基于STM32F1的CAN通信之BH1750
基于STM32F1的CAN通信之OLED
基于STM32F1的CAN通信之之串口IAP
/**6 E- r% k. f! b/ w% m& {8 e
* 函数功能: 定时器中断服务函数& _6 ^4 P; U! y8 ^7 H
* 输入参数: 无8 @. y# \% V! b% Q$ g, f1 z* t
* 返 回 值: 无
* 说 明: 实现加减速过程
*/+ \5 ]7 ~: f' e2 \& o
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{ 8 I# z) \6 f, d; T7 u! U5 k1 ~! A
__IO uint16_t tim_count=0;
// 保存新(下)一个延时周期
uint16_t new_step_delay=0;0 k" E2 b: o& `# `: k# h; S2 r
// 加速过程中最后一次延时(脉冲周期).
__IO static uint16_t last_accel_delay=0;
// 总移动步数计数器0 f# r$ {3 g% q; G5 l
__IO static uint32_t step_count = 0;
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲) u- A+ I" u! z2 B
__IO static uint8_t i=0;
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET). M. s# a* K* P; j" }
{6 V) t* F l7 q2 ?" X# _+ Z# Q
// 清楚定时器中断) L5 ]) y8 X8 D6 i8 x. t# B; |& o2 [+ w9 o
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);6 X! w" g; m* d* c
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);
5 e- R' Z9 {9 _3 d3 ]
i++; // 定时器中断次数计数值
if(i==2) // 2次,说明已经输出一个完整脉冲
{' G8 U1 |) i1 A. I4 ]2 l
i=0; // 清零定时器中断次数计数值7 m: ]8 f8 P* K% ?4 d; {
switch(srd.run_state) // 加减速曲线阶段
{
case STOP:
step_count = 0; // 清零步数计数器: K; A& D3 F9 @! e/ r( j1 M
rest = 0; // 清零余值
// 关闭通道
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);
STEPMOTOR_OUTPUT_DISABLE();
MotionStatus = 0; // 电机为停止状态
break;" U, V! D" M( M
case ACCEL:
step_count++; // 步数加1/ B. g8 [8 Z; `5 Q; a
if(srd.dir==CW)* G3 Y. N, m2 u( {
{ * Q. D! I2 Z {$ R+ J+ A
step_position++; // 绝对位置加1
}
else
{- Y: i6 w) e5 z) r: X p! O3 n
step_position--; // 绝对位置减1
}
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)// 检查是够应该开始减速& M- ~9 N9 b5 [; G% k- ]4 |1 d/ w
{% e; ~7 u% W" G2 `3 T+ L) G: Y8 o5 a
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值. L) O% V( | U8 g( w/ k% n/ o
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}1 `; `: J6 G( U! R3 M" m" v
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度* n# D! z/ t r4 ^
{
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)4 x1 S0 G1 w% z. A; g4 H. d8 U
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
rest = 0; // 清零余值$ U* z( ^2 Y/ }# c- q' O
srd.run_state = RUN; // 设置为匀速运行状态
}) ^/ D+ |: D1 Q* [* Y
break;
case RUN:0 w' O% A2 ^- r6 E( Y; g
step_count++; // 步数加10 v; D& B/ m6 m! ~
if(srd.dir==CW)
{
step_position++; // 绝对位置加1
}
else9 V& w! ^: l0 {) j: _
{
step_position--; // 绝对位置减1
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed); m2 i3 A( _9 x
if(step_count >= srd.decel_start) // 需要开始减速
{
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值5 g$ E0 e6 e4 u" M# X! N
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
srd.run_state = DECEL; // 状态改变为减速/ x- d# Q8 ~, f3 Z) W
}1 ~& w; M7 i1 ?9 H* K, y$ R
break;: G9 _! F3 l- [
case DECEL:
step_count++; // 步数加1( t9 T4 [. B# E. r: J7 D# V
if(srd.dir==CW)- f. b) x+ ^4 v' \( E
{ & ?, |3 A/ Y/ X; L& g
step_position++; // 绝对位置加1
}( X" u: V! I# x. ~" ?0 R9 \$ }
else7 h& v" |8 m4 {! O1 `' a, ^
{/ M0 w1 ^8 A. `9 n! D+ W- L6 [$ D
step_position--; // 绝对位置减1
}
srd.accel_count++;
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);// 计算余数,下次计算补上余数,减少误差/ V0 l; }& t& x$ s; P
; \: W4 Q! x/ b7 c% @
//检查是否为最后一步& p. ~- \, C: R* P7 O7 \$ b; H
if(srd.accel_count >= 0)
{- @5 u- X1 \4 e! \% C, e! \5 n8 c
srd.run_state = STOP;
}; ?/ X- h0 r3 |* {2 P
break;2 P' ]7 O: _/ Y) K+ H
}
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
} @) t3 N% a8 Q+ O. _) @
}& k+ A5 Y8 t% E$ w0 \+ T/ u1 U( Z
}
/**
* 函数功能: 相对位置运动:运动给定的步数5 O2 X: R4 l4 ]+ S8 {
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).% i( O& }% l1 c; ]5 i
accel 加速度,实际值为accel*0.1*rad/sec^25 K# E& g( L) n% E# Y8 X
decel 减速度,实际值为decel*0.1*rad/sec^2
speed 最大速度,实际值为speed*0.1*rad/sec
* 返 回 值: 无; e8 O1 B, c" k2 @& u1 Y
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始7 P+ e- h% v" N6 `) W
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且
* 速度很慢,那还没达到最大速度就要开始减速0 H% N }4 ]* g3 r0 d0 K
*/" |0 F$ O, R4 Q4 M8 U& H
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{
__IO uint16_t tim_count;
// 达到最大速度时的步数+ h2 j: N. X' ]% h: a, E/ x
__IO uint32_t max_s_lim;- v) I! M! _5 B m
// 必须要开始减速的步数(如果加速没有达到最大速度)5 M4 {: }- k2 y3 b3 q
__IO uint32_t accel_lim;7 d5 g' K3 C% g' H- }$ o7 z
if(step < 0) // 步数为负数+ ~ P* e, y% i8 o! X
{5 n8 ]1 S4 r+ ~* M
srd.dir = CCW; // 逆时针方向旋转/ |1 L* v. q5 H$ F# V
STEPMOTOR_DIR_REVERSAL();( j: y9 V: w+ j7 k0 ?4 v0 ` f: Q6 |
step =-step; // 获取步数绝对值% H. q7 C" H5 y5 ~( h- Q
}% B" d/ J, L( U; b& v8 _
else- X7 ^% k r0 N+ D" }! N' b
{
srd.dir = CW; // 顺时针方向旋转2 W9 [- `/ f/ K, [
STEPMOTOR_DIR_FORWARD();# K+ I# I% c1 q# y+ H, C
}' D" I6 W- Q" ~/ f4 f
2 r" S& _/ Z! ^
if(step == 1) // 步数为1$ u3 R* ]4 \" {3 @* ]1 B; I, M0 R
{+ j4 ~) Z9 O3 y. A. I7 I; h; W1 h
srd.accel_count = -1; // 只移动一步 {3 ]" i D3 F+ O. K7 r" r
srd.run_state = DECEL; // 减速状态.. B* n) t( R: e/ g
srd.step_delay = 1000; // 短延时 S. P! X1 z% q1 Q& ]& T$ |* M
}
else if(step != 0) // 如果目标运动步数不为0
{
// 我们的驱动器用户手册有详细的计算及推导过程. z3 E4 X7 q- A" j+ Q
# e( |# z) K8 ?7 H+ A* t. w# e' Z1 p
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w
srd.min_delay = (int32_t)(A_T_x10/speed);7 |! G% d/ l: Q% C" _" Y1 \% b
// 通过计算第一个(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
srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);$ `+ K0 S5 ]2 Y5 ~4 E
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为02 ]/ _, _- {. e1 l$ A9 T
// 但实际我们必须移动至少一步才能达到想要的速度
if(max_s_lim == 0){' `' C: G4 p+ u
max_s_lim = 1;; B5 ?% |# m8 d. O
}, O* a. t6 i6 i! e2 ~5 h( O, v8 q
// n1 = (n1+n2)decel / (accel + decel)
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.9 x0 }" I+ {9 @8 l+ j- {6 \/ B
if(accel_lim == 0){1 o. `) J8 s: Z0 R! S; R* s& h
accel_lim = 1;
}
// 使用限制条件我们可以计算出减速阶段步数+ f; m2 M' g& l5 D# k
if(accel_lim <= max_s_lim){4 _( q# i& _/ `& b. B) q' K
srd.decel_val = accel_lim - step;# z0 D$ y7 f& R+ |5 K
}9 l7 u0 H! T( u
else{% p$ a) W8 {1 S0 M: g
srd.decel_val = -(max_s_lim*accel/decel);
}5 z' D( K* X; X
// 当只剩下一步我们必须减速
if(srd.decel_val == 0){
srd.decel_val = -1;& z* ^, x3 \, y& a
} J8 K2 I9 M J5 T; F& h, `
! C r2 x% s5 L7 Y
// 计算开始减速时的步数
srd.decel_start = step + srd.decel_val;
// 如果最大速度很慢,我们就不需要进行加速运动
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;
srd.run_state = RUN;; z, b a* x0 k; t4 b8 d
}
else{
srd.run_state = ACCEL;1 v1 n8 b0 w: J" }4 W0 ^$ ~
}
// 复位加速度计数值/ j7 U [/ Z: M2 p/ g1 S
srd.accel_count = 0;& T2 e- C4 B1 @$ n r
}5 L& ]1 _; O& Q8 O% I4 o# e2 i
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); // 设置定时器比较值4 G( }9 \6 P% p5 P2 I6 ]
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_ENABLE); // 使能定时器通道 , |0 Z, e- H3 i, ^
STEPMOTOR_OUTPUT_ENABLE();
}
1、机器人和工业驱动器
2、纺织、缝纫机
3、包装机械
4、工厂和实验室自动化
5、高速 3D 打印机
6、液体处理; {5 x9 e2 e$ L; w+ X! H4 n" _
7、医疗& j6 @# N1 n! w: A
8、办公自动化
9、有线闭路电视
10、自动取款机、现金回收) h/ N, n5 y$ z
11、泵和阀门
电机驱动主芯片采用TMC2160
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;2 Z0 p6 v1 x! f6 Q. o5 @" w
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)
拨码开关ON:设置为高电平1,反之低电平0
细分设置:CFG1、CFG0
CFG1、CFG0:0 t, m3 w: S4 U5 V# F8 g
11:64细分! J/ i+ Q- T; ]7 g
10:32细分
01:16细分6 H: P/ @/ i! x" w0 m
00:8细分9 n- v: B+ T! f u* Y3 t% l, i+ c
运行电流设置:CFG4、CFG3、CFG2' a: O/ b7 |" t4 V+ H1 V0 G9 m
CFG4、CFG3、CFG2:% O$ _" h. D' J" n
111:IRUN=31
110:IRUN=28% ^+ ^% q( v/ v7 e; X% a- k k
101:IRUN=26" k0 i* a$ N& S3 y- Q# Y
100:IRUN=24
011:IRUN=22! M& s8 ~( O+ E$ b
010:IRUN=20
001:IRUN=18
000:IRUN=165 w+ R9 r8 s. r% i
Irms=Vfs/(IRUN/32)/(Rsense*1.414); 7 }! s9 `& w: v4 O
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
CFG5:
1:SpreadCyle模式,低速、低平稳运行模式
0:SpreadCyle模式,高速、高运动稳定模式$ K" S2 y3 ~' r$ _1 L4 h
保持电流设置:CFG69 |# N6 d+ F7 l/ ~
CFG6:
1:保持电流=运行电流/2
0:保持电流=运行电流
DIR+STEP接口模式位置控制(无需SPI接口)3 c% u6 `6 G+ o1 t! E
COM端:接24V或12V或5V
DRV_ENN、STER、DIR:接集电极开路输出( |, l8 Q7 Z3 l) ?
为测试方便:
COM端:接3.3V
DRV_ENN:使能,接PB14. I3 \5 l. \7 T, J
DIR:方向, PB15
STEP:脉冲,PA89 H/ L4 ?+ e X* F3 w4 e3 v7 l- ?