小马哥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
/**# g, a5 Z6 u0 D* \3 U& D
* 函数功能: 定时器中断服务函数
* 输入参数: 无4 M+ O0 [+ k$ s5 x4 I" s T4 i
* 返 回 值: 无
* 说 明: 实现加减速过程- p* t& o5 `7 z; y: e
*/5 @/ `; t( p# E$ I9 V
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{ 9 N0 d2 i0 b# u2 O, d: b% U
__IO uint16_t tim_count=0;
// 保存新(下)一个延时周期
uint16_t new_step_delay=0;3 r4 T- q9 n$ t. O
// 加速过程中最后一次延时(脉冲周期).
__IO static uint16_t last_accel_delay=0; r8 G6 ]# U6 L/ R1 [) N0 |
// 总移动步数计数器/ D1 H, l" v( v& Z/ U/ f
__IO static uint32_t step_count = 0;5 k% v! k& w3 N6 j: L
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t i=0;+ ?6 _% {; ?6 ~$ P' d3 D
. Y: c2 x; U6 [8 L1 A; g; m
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)/ U) g1 T0 r8 V. i/ [5 c
{
// 清楚定时器中断# q" r u, P9 Z$ ]; N( ~
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
0 V2 v* @. M$ P* h8 u7 }$ ]8 M: z* Z
// 设置比较值6 Z* {' N% j: V- c
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);1 I" g% M8 M; R- r2 h6 Q0 }
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);
i++; // 定时器中断次数计数值4 w/ F- ~; ?) ^ @
if(i==2) // 2次,说明已经输出一个完整脉冲
{0 _+ {2 p) `: n* k& {6 Q) ^! T- u
i=0; // 清零定时器中断次数计数值8 ~+ @$ p' s% p! a5 h
switch(srd.run_state) // 加减速曲线阶段
{4 t* j1 z! d4 L) W" e
case STOP:5 S e, J& |8 L
step_count = 0; // 清零步数计数器
rest = 0; // 清零余值5 q/ G" A. X, B* }2 |( a
// 关闭通道' d+ o" k; X$ X* }9 |) B3 V
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE); 2 t) v# t: z) `
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);' A7 N2 I1 I; x# w
STEPMOTOR_OUTPUT_DISABLE();: ~5 i" ~" \4 K( Y9 |) {
MotionStatus = 0; // 电机为停止状态
break;
case ACCEL:, v: S6 Z& Q+ h3 J6 m$ n
step_count++; // 步数加14 G- E- g3 o( d, }7 W
if(srd.dir==CW)7 M4 D& L4 v6 w9 `5 d- \
{ $ R% H8 n, x4 E5 N
step_position++; // 绝对位置加1' ^5 a: m9 O! c' n
}! F# q" e; j# B$ K- S8 \7 L
else
{
step_position--; // 绝对位置减1* m# F; t# ?7 r; Q. h2 x
}# s' O8 W3 r' E- l* [( U8 }/ M) o
srd.accel_count++; // 加速计数值加1' e9 H6 T; c. y: o3 f+ @
new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)- e a2 {3 V @2 }
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差* u: ?4 t- N. J! P$ D
if(step_count >= srd.decel_start)// 检查是够应该开始减速
{
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值- X# ~6 t# {1 z% r+ k7 V+ w
srd.run_state = DECEL; // 下个脉冲进入减速阶段0 R6 ~; w9 c1 m; Y+ v* P, O
}$ @: w) G% q% j% h! v8 w
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)/ u4 i. i- b- u1 B) J
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
rest = 0; // 清零余值
srd.run_state = RUN; // 设置为匀速运行状态5 O: S" K7 X7 d: T5 u; p
}
break;
case RUN:
step_count++; // 步数加1
if(srd.dir==CW)
{ ; Y" ~: c0 ] e5 @' D/ G
step_position++; // 绝对位置加1
}
else3 {0 c, P% i' B; Y& b" N* X
{ I( E" j- ]; n, y2 B# d7 d9 x2 S) [
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;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期): q5 _; P* y* o3 X& S* d. g4 G9 t
srd.run_state = DECEL; // 状态改变为减速
}4 ^- u" E) U$ W4 e% J4 w
break;$ F, S' v) C# w' w* R
l( k h d* ~8 Z& q) m- o4 H
case DECEL:
step_count++; // 步数加1
if(srd.dir==CW)1 _, d8 N$ [; `/ X* g2 o
{
step_position++; // 绝对位置加1
}' l% V& x, q' g7 U
else0 N4 g7 ]: y' e% ^- d0 Y$ @
{
step_position--; // 绝对位置减1
}- U$ G% z4 k8 c7 i9 J
srd.accel_count++;
new_step_delay = srd.step_delay - (((2 * srd.step_delay) + rest)/(4 * srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔)1 ^! o, `# m$ Y4 D; @! e
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
//检查是否为最后一步# y; x7 p5 A' q [- A" y: N. H" m
if(srd.accel_count >= 0)
{. d- `- {5 r: o4 A- V) o
srd.run_state = STOP;
}; _( T [0 r# Z' K9 H, R
break;2 s! Q! s% G* z+ z& V% y
}
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}1 J6 S/ o e/ ^, S4 j$ m, I, c
}
}
/**
* 函数功能: 相对位置运动:运动给定的步数' y r0 E. v4 U% D1 ]( O2 s5 ?& B
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针). b$ m4 \0 k7 O; a6 o2 n z" F9 P
accel 加速度,实际值为accel*0.1*rad/sec^2
decel 减速度,实际值为decel*0.1*rad/sec^2
speed 最大速度,实际值为speed*0.1*rad/sec( P: [ ]; G" R _8 P5 N) @
* 返 回 值: 无. m! |& ?% ~" l$ C3 H
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始0 J; ]& e2 a W
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且
* 速度很慢,那还没达到最大速度就要开始减速7 Y# g0 u# s6 n' G5 S
*/+ @0 q1 O( f- }, b6 L# X
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{ c" F$ }; K4 h3 r6 q
__IO uint16_t tim_count;
// 达到最大速度时的步数
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)9 |# K1 a8 j, C
__IO uint32_t accel_lim; ]. I( i/ ^% M
# r% i1 U6 d$ ]8 }) p4 F5 A
if(step < 0) // 步数为负数
{: }% d8 v# s7 |* _
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值0 Z6 m. T' p; K3 y
}
else
{1 T; T& k$ T/ J9 m4 y; x2 O# B
srd.dir = CW; // 顺时针方向旋转+ V* e# Q. I4 K, m- p# m" m
STEPMOTOR_DIR_FORWARD();
}
if(step == 1) // 步数为18 ~) Z1 R9 H6 A. q4 j
{ q% d( a6 w" B, W5 g, j
srd.accel_count = -1; // 只移动一步
srd.run_state = DECEL; // 减速状态.
srd.step_delay = 1000; // 短延时
}
else if(step != 0) // 如果目标运动步数不为0
{5 F8 W/ k+ q+ y
// 我们的驱动器用户手册有详细的计算及推导过程
% Q: M+ }1 B+ N- C% \( e: O1 d6 r
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。# l* v) f$ q. {# y% x" A+ y
// min_delay = (alpha / tt)/ w1 |" p# f6 F6 Z7 m
srd.min_delay = (int32_t)(A_T_x10/speed);
]$ q' ]! H9 t' c L6 ^8 l9 F
// 通过计算第一个(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);0 [' Y( b! W0 E
// 计算多少步之后达到最大速度的限制; d' |5 U) f' q( A$ c% M R' J8 d
// max_s_lim = speed^2 / (2*alpha*accel)2 a( K9 Y0 `7 H1 ^: u; D: ^! q
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));0 z! G7 g8 O% w, t: C
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度
if(max_s_lim == 0){0 F1 u" Y$ D6 U# F7 b: J0 d0 [
max_s_lim = 1;6 P$ l. X1 w, F
}
// n1 = (n1+n2)decel / (accel + decel)9 ^% E2 L$ @8 n4 z1 d1 D4 h* T
accel_lim = (uint32_t)(step*decel/(accel+decel));" K' {* q: z6 S
// 我们必须加速至少1步才能才能开始减速./ K( V! }& R$ _' H" a
if(accel_lim == 0){
accel_lim = 1;1 i9 P, D! Y9 D8 D. K
}! q6 u& h! J3 {: Z# ~- F+ t& @
+ w- z/ ]/ G0 x1 u. y& c. U
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){
srd.decel_val = accel_lim - step;
}9 i* R, E. E. E5 l6 {( B: r, o
else{
srd.decel_val = -(max_s_lim*accel/decel);; z# a' F$ E7 W2 H6 ]$ b
} t( @' h+ S% r& M4 v
// 当只剩下一步我们必须减速0 E7 Y) Z a* S$ s
if(srd.decel_val == 0){0 @, \ D' J$ B+ G$ _( q
srd.decel_val = -1;
}
* k1 G, N( Z. t- P! T$ z& D) b
// 计算开始减速时的步数
srd.decel_start = step + srd.decel_val;7 T8 H& ]8 T/ [( h* W" C" M
% W7 V( v2 N F$ h" Q
// 如果最大速度很慢,我们就不需要进行加速运动
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;- V5 I' x- k) Q! p; l( ]
srd.run_state = RUN;6 l# o, j& ?8 z: G) c
}; t0 v" n! P# T1 L7 ]' c/ b3 G9 Z0 j
else{3 O2 A& A; H. R( m* a7 ^& e+ H* j
srd.run_state = ACCEL;4 c+ f4 o1 c5 k9 X
} 2 b/ I. ^; B8 t2 }. C
// 复位加速度计数值
srd.accel_count = 0;
}0 }, p% e" U+ J U: F! K
MotionStatus = 1; // 电机为运动状态* _7 A5 ~, @2 ?0 l% b$ Z) Z
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);" n1 y7 b' n) ?# {. _: `
__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); // 使能定时器通道
STEPMOTOR_OUTPUT_ENABLE();
} G4 N6 @; b$ X* D3 H
1、机器人和工业驱动器
2、纺织、缝纫机
3、包装机械
4、工厂和实验室自动化
5、高速 3D 打印机7 a) r3 u( M5 q
6、液体处理
7、医疗
8、办公自动化
9、有线闭路电视5 D+ q9 P8 ]1 A4 x$ A; m
10、自动取款机、现金回收$ l! l; W% i9 Z v+ @. V
11、泵和阀门
电机驱动主芯片采用TMC2160( T0 U4 h; X5 A& J5 O0 [
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);& U _: Y/ U! `% }4 v, O( `* z
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)
拨码开关ON:设置为高电平1,反之低电平0
细分设置:CFG1、CFG01 o" S( ]0 c7 F: T1 q% v% H9 K
CFG1、CFG0:8 O# ~' g9 {' v
11:64细分
10:32细分
01:16细分
00:8细分* ?) ]0 ^8 y7 n- W% M9 U7 `& P0 I) x
运行电流设置:CFG4、CFG3、CFG2% p* ^9 b4 u8 b# D. J2 S
CFG4、CFG3、CFG2:, C" W H' l3 b9 N
111:IRUN=31
110:IRUN=287 D2 g( w/ |: F5 E, n, ?, {0 a
101:IRUN=26
100:IRUN=242 q/ n( l: o0 z( t8 w' f
011:IRUN=22' J4 z4 W+ a/ L3 [! \$ v3 Z: B
010:IRUN=20
001:IRUN=18
000:IRUN=162 X% [- P- d" W- p7 P5 v
Irms=Vfs/(IRUN/32)/(Rsense*1.414); % T( ]6 j: o9 I( N% }/ G& W v
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
CFG5:% w3 l2 l: f+ ^
1:SpreadCyle模式,低速、低平稳运行模式
0:SpreadCyle模式,高速、高运动稳定模式
保持电流设置:CFG6+ @& j6 ~" s: y. t9 z# l3 W. Q
CFG6:0 q j1 Y8 S0 V
1:保持电流=运行电流/2$ }. H( D8 B% P* q" n$ O+ i) H
0:保持电流=运行电流
DIR+STEP接口模式位置控制(无需SPI接口)7 T' ]3 @+ g+ X3 d
COM端:接24V或12V或5V
DRV_ENN、STER、DIR:接集电极开路输出 h/ B3 V0 [( P0 Y! n S
为测试方便:
COM端:接3.3V; U% F' H7 B z" j
DRV_ENN:使能,接PB141 _5 [9 A* M8 H; R/ G
DIR:方向, PB15- k7 @3 g# X6 Y
STEP:脉冲,PA8: Y* f4 W2 V* q" ]