小马哥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
/**
* 函数功能: 定时器中断服务函数
* 输入参数: 无
* 返 回 值: 无
* 说 明: 实现加减速过程; `0 A/ I8 r9 `5 F9 M5 N2 P* A. K
*/) g+ A# a* Y! X+ _6 M: J
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理7 Q, J2 B, c1 i2 S
{ , m9 d" ]5 x( `( I! L5 X0 C
__IO uint16_t tim_count=0;- N3 d% G4 I2 U) N+ v, `1 J
// 保存新(下)一个延时周期
uint16_t new_step_delay=0;/ J, S- U& C1 V3 }4 A
// 加速过程中最后一次延时(脉冲周期).
__IO static uint16_t last_accel_delay=0;8 f7 n; K& W* f4 w
// 总移动步数计数器" h/ F. v. f; }7 y# U
__IO static uint32_t step_count = 0;: L. o4 b) z4 E5 L* j+ V4 j; f2 o5 I% A
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;5 Q1 |1 y: R; g r
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t i=0;7 U; z0 Y7 ~% g7 I5 @0 a
5 n4 y( |6 ~9 W) r6 `
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET); i* |! w$ o* }6 j) J+ ?! E
{ |+ o0 ]. o/ H
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);# H/ T/ J1 \) y0 f; z- ~ t% `! u( I
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);& N4 `8 C f% Z% G6 V- H+ z
i++; // 定时器中断次数计数值
if(i==2) // 2次,说明已经输出一个完整脉冲
{
i=0; // 清零定时器中断次数计数值( Y: @5 `8 F7 }9 t( U9 K
switch(srd.run_state) // 加减速曲线阶段
{; U9 X+ i$ ~- j* C( ~9 z
case STOP:
step_count = 0; // 清零步数计数器 K: y& F# ]& Y$ X: \2 I' M3 ]5 r
rest = 0; // 清零余值
// 关闭通道% X( J# w1 F; }* o% U/ m) _% w. O
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;
case ACCEL:
step_count++; // 步数加1
if(srd.dir==CW)* j# u- U( J1 R! ?1 U( x
{
step_position++; // 绝对位置加18 M/ {1 B% h( f" M4 m) G
}8 |# X% L# g5 W, U' I B
else
{
step_position--; // 绝对位置减15 _+ C0 U/ w& Y: k
}
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);// 计算余数,下次计算补上余数,减少误差4 z% f0 |" x/ t6 T9 \
if(step_count >= srd.decel_start)// 检查是够应该开始减速; E/ ?8 _: q9 v' d
{
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}8 h" l! H" Z. }7 M
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{7 q$ ^" c% m% ?0 f* u
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期), w% O$ n+ V4 r2 d! Q
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
rest = 0; // 清零余值) {" K p& U3 K% Z
srd.run_state = RUN; // 设置为匀速运行状态
}- e+ P: V& s* }+ f8 S
break;
8 ?) t$ G0 s# c/ O
case RUN:/ S* X( P. }3 ^
step_count++; // 步数加18 {% O6 m9 l2 m
if(srd.dir==CW)
{ 2 v5 ]+ h S7 |7 F# ?
step_position++; // 绝对位置加1) Z) D( _ n% w
}0 a; ]; Z" f0 ~ J
else
{
step_position--; // 绝对位置减11 W* i5 {8 l/ y" P: l
}& K; V' X& S$ H6 H+ I# l) t3 ]3 J
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
if(step_count >= srd.decel_start) // 需要开始减速- e$ {' }9 z% J, q% n! F% u
{0 l3 F2 h6 {0 H
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值: d# E( i4 i2 r: z
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)+ @$ p0 y4 X3 R7 u# |9 H4 @+ j
srd.run_state = DECEL; // 状态改变为减速
}
break;
: g. [. E$ [4 [1 j
case DECEL:
step_count++; // 步数加1
if(srd.dir==CW), f+ R9 ^8 C" S2 S+ h! f5 ]
{ . L9 w& I+ M0 w2 c$ _5 k g
step_position++; // 绝对位置加1; V# l+ a4 p8 H% j& M3 }5 ~
}
else
{, Z! F' K0 [9 m
step_position--; // 绝对位置减1
}
srd.accel_count++;
new_step_delay = srd.step_delay - (((2 * srd.step_delay) + rest)/(4 * srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔)& {; l& L5 c* Z+ r. z
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差; z9 X, Y7 F% T1 i) l
//检查是否为最后一步' T8 V0 V/ h2 w3 v
if(srd.accel_count >= 0)' S! N. E- g6 P0 |% D( A- G
{# [4 ^- a* n& o2 a5 E- @- @' C; q: s9 @
srd.run_state = STOP;
}2 {, p, b U, w: g9 O( i
break;
}
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}' e! U+ ^5 S) u7 O
}
}( i* X) e; l* m: [# d
/**) a, I" X6 R% ~: P
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).7 o& G2 J$ g& |2 t
accel 加速度,实际值为accel*0.1*rad/sec^25 U2 E; K |% U1 @, \( H
decel 减速度,实际值为decel*0.1*rad/sec^29 @$ X$ e1 L. A& s1 g& z
speed 最大速度,实际值为speed*0.1*rad/sec5 X8 q0 P; c! W
* 返 回 值: 无
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且
* 速度很慢,那还没达到最大速度就要开始减速
*/; p5 }0 n( M8 [( S9 Z8 N+ ^/ e
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)4 T) i2 s" G7 K" S
{ 8 y/ H( s E% m: I( C) `$ b0 g
__IO uint16_t tim_count;
// 达到最大速度时的步数
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t accel_lim;
if(step < 0) // 步数为负数) { C+ D/ c S5 ^8 |
{& l* W3 J. d& S0 p0 p+ P
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();, F* {6 s1 b; e# r5 D: c& m+ R6 ^
step =-step; // 获取步数绝对值
}
else
{8 ]/ ~+ T+ L, M5 h8 @) G& i) n
srd.dir = CW; // 顺时针方向旋转
STEPMOTOR_DIR_FORWARD();
}
if(step == 1) // 步数为1
{9 B; C+ W& X5 u* l
srd.accel_count = -1; // 只移动一步$ n9 `. q7 M+ C/ S: ?! z6 d
srd.run_state = DECEL; // 减速状态.1 p) V, v+ Z, {# Y6 @& O* A# m, P
srd.step_delay = 1000; // 短延时 3 d7 a5 l8 F+ m5 u, W! ~' _
}! p' Z3 \; F" q; `) k9 z( X8 N9 \
else if(step != 0) // 如果目标运动步数不为0
{" ]+ c. W" c9 O+ x6 `
// 我们的驱动器用户手册有详细的计算及推导过程0 d" W3 c* P7 U2 e
t/ w2 w& X- U' _" [
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。: I V. f$ ]5 J+ q8 D! H; ^) f$ K
// min_delay = (alpha / tt)/ w
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) )/1004 b! p- B9 L2 x t% N: G& K0 A
srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);
$ W: m& i) t$ \# k- R
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));+ L" R1 f% X S
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度
if(max_s_lim == 0){# M# f, D0 W0 ^
max_s_lim = 1;
}
// n1 = (n1+n2)decel / (accel + decel)$ V, |( [+ M" a- L9 \$ |
accel_lim = (uint32_t)(step*decel/(accel+decel));* D- M c1 J8 i0 b9 W1 r8 g# ?6 q
// 我们必须加速至少1步才能才能开始减速.
if(accel_lim == 0){
accel_lim = 1;, k: H3 z- k: o6 C- G# a
}: B5 B c; Y' Z' J
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){ V) A2 g; z& g8 i) r
srd.decel_val = accel_lim - step;2 u* V3 }( B# E: @4 h3 k
}
else{
srd.decel_val = -(max_s_lim*accel/decel);
}- ~3 [, S5 R2 p% A1 T
// 当只剩下一步我们必须减速: [5 v; G4 b2 R, k& l4 V
if(srd.decel_val == 0){" }6 E4 ]) t& a' M: p
srd.decel_val = -1;
}/ k, e2 Y6 A2 P, a
" A7 X- O& d5 q P; |4 s+ {; E
// 计算开始减速时的步数1 w5 b+ J* F+ \
srd.decel_start = step + srd.decel_val;) |" M) Z; k$ O2 j8 u! b' X
// 如果最大速度很慢,我们就不需要进行加速运动! a6 q' n0 }- V; e5 R
if(srd.step_delay <= srd.min_delay){( {* s! g6 [7 g6 m0 o
srd.step_delay = srd.min_delay;
srd.run_state = RUN;
}
else{
srd.run_state = ACCEL;
} 7 @) Q2 a' f# c1 \0 k1 p( s$ `
// 复位加速度计数值( m& O. R/ N+ h6 K' Q( w
srd.accel_count = 0;
}
MotionStatus = 1; // 电机为运动状态+ C% Z8 ^% ]4 Z) ?+ @9 Y5 H# r
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__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();
}
1、机器人和工业驱动器7 P9 v: z+ K/ k# e# \* _( k) y& ]
2、纺织、缝纫机+ Z8 m2 [: ]( O
3、包装机械& P/ s& _3 r b8 t
4、工厂和实验室自动化4 l( E9 { I: V3 Q- J! Z
5、高速 3D 打印机
6、液体处理
7、医疗2 U I7 q) R& h" Y$ i. u
8、办公自动化+ b2 ^8 u6 S* k1 l* J) {% G- b
9、有线闭路电视
10、自动取款机、现金回收
11、泵和阀门
电机驱动主芯片采用TMC2160
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;
2 F$ F4 t, s/ y. q- m q
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)# H. e; z5 X6 b7 e
拨码开关ON:设置为高电平1,反之低电平0+ \' P& l5 B/ ^! N
细分设置:CFG1、CFG0
CFG1、CFG0:% o' v" u: [2 o5 r. `
11:64细分' x2 e# m2 g% l
10:32细分0 w& Z7 E% x8 D+ X. l5 l
01:16细分
00:8细分- J0 j, c' O5 n9 ^* { {7 F9 e0 w
运行电流设置:CFG4、CFG3、CFG2 X1 U7 m& r* I' I$ R ^
CFG4、CFG3、CFG2:
111:IRUN=31
110:IRUN=28
101:IRUN=26
100:IRUN=24/ _, x0 W/ M5 _# P2 Q! {, S
011:IRUN=22
010:IRUN=20& ~3 S4 u+ u" y% z. U5 G6 z
001:IRUN=18
000:IRUN=16. ^, S- [4 }% p! a: X
Irms=Vfs/(IRUN/32)/(Rsense*1.414); ! ?; o+ N# y) |
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
CFG5:
1:SpreadCyle模式,低速、低平稳运行模式( E1 L7 }9 d8 r# t% {8 K
0:SpreadCyle模式,高速、高运动稳定模式8 t- m" V) {0 F: \+ A
保持电流设置:CFG6
CFG6:
1:保持电流=运行电流/29 a# b6 x9 j: B
0:保持电流=运行电流3 s' H/ ~4 v0 y; U6 ~; E
DIR+STEP接口模式位置控制(无需SPI接口), _7 A( K$ V) }) x
COM端:接24V或12V或5V
DRV_ENN、STER、DIR:接集电极开路输出6 P( q b0 R) ^* G5 A1 x
为测试方便:- j8 l& N' U. b( t. \$ ?
COM端:接3.3V
DRV_ENN:使能,接PB14
DIR:方向, PB15
STEP:脉冲,PA82 |; P G. V- p* {& u# u