小马哥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
/**, s! j. ^9 a/ r% u
* 函数功能: 定时器中断服务函数
* 输入参数: 无
* 返 回 值: 无
* 说 明: 实现加减速过程# w; I4 ~$ R& ~' k
*/# u7 ^! \; |3 A' X
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{
__IO uint16_t tim_count=0;: X( {9 Q* y0 f9 }3 M% Z3 C
// 保存新(下)一个延时周期$ j8 H2 y3 C2 L, u3 [
uint16_t new_step_delay=0;7 i6 Z( G( ~& U! `6 g& @
// 加速过程中最后一次延时(脉冲周期).
__IO static uint16_t last_accel_delay=0;+ X" a1 q* ^4 ?4 P7 ~& B; B/ y
// 总移动步数计数器) C5 r3 W9 A/ G
__IO static uint32_t step_count = 0;4 w3 W! b! J% A+ T2 u8 \! b/ u* X
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;7 }) G: B/ L" m v
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲; J' e$ C n2 ~7 ]- h Q0 r @
__IO static uint8_t i=0;
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET). o7 |: v Q, v% `
{
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);$ r! U! A1 g6 @) S7 Y" l4 x+ k
// 设置比较值' w; K( t5 d2 O z1 c9 f
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);
5 V$ Q, i: p5 y1 V+ X
i++; // 定时器中断次数计数值
if(i==2) // 2次,说明已经输出一个完整脉冲
{9 ?2 U. d' L8 K- ]; ^
i=0; // 清零定时器中断次数计数值% E/ Y5 B( P" G( H3 |
switch(srd.run_state) // 加减速曲线阶段
{& u. w& p+ X2 Q% P1 ^. ]
case STOP:2 B4 E% G z6 v F
step_count = 0; // 清零步数计数器
rest = 0; // 清零余值
// 关闭通道% n3 M# T2 \' h( H$ h; ]
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE); 1 l* Y. B s. h: j5 v) k
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);4 V# q- f% B( W$ r8 k2 Y
STEPMOTOR_OUTPUT_DISABLE();: L& u( ?; t' W# x
MotionStatus = 0; // 电机为停止状态
break;' m( a" Q7 \0 R4 w3 q0 z
case ACCEL:
step_count++; // 步数加1/ p, G/ O. d+ ~6 B2 E+ [. w2 ]
if(srd.dir==CW)" _: _" K" T3 E. _
{ 9 K! k% T$ l8 f Y
step_position++; // 绝对位置加1
}
else
{; F' f8 {9 Z6 z9 `/ Y/ y
step_position--; // 绝对位置减19 Y1 b: v2 W4 }' t+ ~$ P% u7 g, h
}; e) u& |4 N' f* n e5 W
srd.accel_count++; // 加速计数值加1
new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)5 n& @" x0 O& E: n- y
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
if(step_count >= srd.decel_start)// 检查是够应该开始减速6 p( q+ Q+ J+ N7 [8 t; H8 Q
{: H: S( C' \5 `+ H9 g" b
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值5 O5 s5 ~# w7 R* H1 q% U
srd.run_state = DECEL; // 下个脉冲进入减速阶段3 |: S. K+ J: o7 P
}( K3 v9 O3 F9 P% f
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)- x( @' P2 j% e8 t9 d; D0 w
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)9 F$ ~$ |2 p/ ]; s
rest = 0; // 清零余值
srd.run_state = RUN; // 设置为匀速运行状态5 x8 k9 m. |0 s( U) W( f4 G% o
}2 @& w# ]' ?, r- \0 y
break;
case RUN:
step_count++; // 步数加15 A2 P/ Q! a' L7 P# M6 s( g
if(srd.dir==CW)0 N5 ]% J* X8 H/ h. }% H: h: \
{ - ?3 e; f* Q& S% } K
step_position++; // 绝对位置加1: H0 ?- K. X, E4 I; I
}% h9 R/ ~8 @: U: o, _5 U* X2 G. `
else
{
step_position--; // 绝对位置减1
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)+ u2 q6 P9 K" ~0 x) u/ L7 J
if(step_count >= srd.decel_start) // 需要开始减速% ?, `& `4 u. h
{' H. T: I6 G4 Y
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
srd.run_state = DECEL; // 状态改变为减速
}
break;# m. j; r; a; f+ h
case DECEL:! h: F8 w) N' Q9 W1 L% y% i
step_count++; // 步数加1' E. j5 J! }; s4 M1 u. i% J* o/ m8 |
if(srd.dir==CW)
{
step_position++; // 绝对位置加1+ r. i: F) d8 w' ?, M
}, D0 p6 y1 M* w: O3 Z% J
else$ X) C' f; ~1 N- @
{
step_position--; // 绝对位置减17 v7 G/ _; f& h1 ^; X' K
}
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);// 计算余数,下次计算补上余数,减少误差3 Y# j# Q* B* c) H$ J
//检查是否为最后一步% [, f4 A5 h8 Y( h
if(srd.accel_count >= 0)
{7 h& Z+ K# A i, |# P8 I
srd.run_state = STOP;9 E, r1 w2 B6 }0 q9 m
}
break;
} & g5 K# o+ E# q9 @3 i9 n
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}
}0 k8 v9 r3 |" O: G, j4 {
}. X' s+ V0 M0 f: f; n! r* S
/**
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).* b& e1 e; p4 V! Y9 l: `* \7 g6 w; F
accel 加速度,实际值为accel*0.1*rad/sec^2, Y. ~+ i- w! }1 p ?( @
decel 减速度,实际值为decel*0.1*rad/sec^2$ ^) r/ g3 H2 C, E
speed 最大速度,实际值为speed*0.1*rad/sec9 h1 P8 m5 W+ p( ~2 q; j) g
* 返 回 值: 无
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且/ H' y( v& o2 I8 x/ Z
* 速度很慢,那还没达到最大速度就要开始减速1 B# \. C3 ?2 u, X/ M/ o
*/2 ]2 o' i" x, z
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)+ ^4 W3 A) Y1 L$ R* m0 Z
{
__IO uint16_t tim_count;
// 达到最大速度时的步数
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t accel_lim;' p! `/ ~% [1 Q' X) m
" \1 i% o3 T- V
if(step < 0) // 步数为负数
{% b* k! S, G: ?* {: q; s
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值
}2 |: j- Z8 t2 C& ^
else
{
srd.dir = CW; // 顺时针方向旋转
STEPMOTOR_DIR_FORWARD();
}$ k; q4 e. e: b; I
if(step == 1) // 步数为1! c. x. x4 i1 F/ {
{$ d' U' a. f1 \, a5 k+ V9 k; r
srd.accel_count = -1; // 只移动一步
srd.run_state = DECEL; // 减速状态.3 U0 S6 Y) Q& ^4 y' J) Q
srd.step_delay = 1000; // 短延时
}# p; Y; P0 U) p; x, }" s4 e
else if(step != 0) // 如果目标运动步数不为05 ?4 d# m6 l5 l6 @5 |, T/ ?: d7 m
{
// 我们的驱动器用户手册有详细的计算及推导过程$ K J( A. K3 ~5 K3 E0 s2 }
- N2 g5 r$ {+ G$ ], c
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。; L& ^: F' v( P7 G' N! r4 C
// min_delay = (alpha / tt)/ w7 V: O; d9 h) `2 k; g! _
srd.min_delay = (int32_t)(A_T_x10/speed);
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^2, N# X; R% s4 o6 o
// step_delay = 1/tt * sqrt(2*alpha/accel)/ |1 h; h4 {8 h, x, T3 z
// step_delay = ( tfreq*0.676/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/1005 ^/ @$ X% Y1 t% y
srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);! W! }, \; n4 u' o3 b) w* T
7 \; o% s/ `; M! ^5 O+ Z* j
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度( P+ V8 N6 k* g( h7 f! y& ]! ]9 G
if(max_s_lim == 0){
max_s_lim = 1;( C( F) M( u7 |0 f6 g* e" S
}
// n1 = (n1+n2)decel / (accel + decel)+ {3 W& k! N+ k% l) y3 |
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.: ]# o8 O; y$ Q4 _
if(accel_lim == 0){9 F! `, B- \ |: U, ~; M, d
accel_lim = 1;
}! b" P, d* U: m
( J# Z& n5 M: O0 H
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){
srd.decel_val = accel_lim - step;+ M* L6 y' u4 l; M! v* U
}
else{
srd.decel_val = -(max_s_lim*accel/decel);
}/ n% G* l) A/ }, T$ p
// 当只剩下一步我们必须减速
if(srd.decel_val == 0){& }% X- x) x2 G; @: f
srd.decel_val = -1;
}
// 计算开始减速时的步数2 Q4 U) N* L$ J4 q% i- e
srd.decel_start = step + srd.decel_val;
// 如果最大速度很慢,我们就不需要进行加速运动. a/ j/ H. E+ \9 \$ j
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;
srd.run_state = RUN;! L# f% L$ a7 h# t6 h" l3 W3 X
}1 e. {7 x+ F' e. [; Q" I; w
else{
srd.run_state = ACCEL;! e. _: V$ `8 f% C. W( L- S7 I$ v
}
// 复位加速度计数值
srd.accel_count = 0;
}
MotionStatus = 1; // 电机为运动状态+ f9 B" {' a4 ` A( d6 a& u, S
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();- F1 [; L0 n0 b% j* l( _. ?3 X. k6 f' Z
}
1、机器人和工业驱动器7 V. F8 ?, s2 U4 y1 ?
2、纺织、缝纫机" K6 [% a- P( P+ b: R. C
3、包装机械
4、工厂和实验室自动化$ O2 o1 G* Z0 ~% k
5、高速 3D 打印机
6、液体处理; w ?. S; T- K# P
7、医疗$ k/ E ?3 \$ Z$ k G, u
8、办公自动化
9、有线闭路电视
10、自动取款机、现金回收
11、泵和阀门
电机驱动主芯片采用TMC2160
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);" K+ {) w: _) c6 {
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)! g5 o7 c) ~0 ^) R2 E: e8 n
拨码开关ON:设置为高电平1,反之低电平0: m# z% }5 m# A b! s
细分设置:CFG1、CFG0
CFG1、CFG0:
11:64细分" s C. @4 t( A u9 y0 i1 O, {
10:32细分
01:16细分7 {$ p5 q8 w0 P, C. D3 {! D
00:8细分
运行电流设置:CFG4、CFG3、CFG2( b1 J7 [9 _& v% ?6 N( L& P
CFG4、CFG3、CFG2:
111:IRUN=317 V* B' n9 E2 g* Q8 a: h* M% |
110:IRUN=28
101:IRUN=26
100:IRUN=24- {& t% @* M: Z$ k
011:IRUN=22
010:IRUN=20) r8 Z9 N, B% p8 z
001:IRUN=18* x' n* O- p, K/ c
000:IRUN=16
Irms=Vfs/(IRUN/32)/(Rsense*1.414); ; v( U& V1 c8 Q9 _
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;0 y" H1 l: B9 w& T
CFG5:) }% q/ N) }+ f6 {
1:SpreadCyle模式,低速、低平稳运行模式
0:SpreadCyle模式,高速、高运动稳定模式3 U( B3 e. i/ X2 x5 s
保持电流设置:CFG6$ O, J; W4 |& W4 h2 p _ U
CFG6:
1:保持电流=运行电流/2
0:保持电流=运行电流8 c: C: ]5 j. _; E) X
DIR+STEP接口模式位置控制(无需SPI接口)
COM端:接24V或12V或5V7 ]2 e$ r4 E, r, t% w
DRV_ENN、STER、DIR:接集电极开路输出
为测试方便:: f/ ~% m. ?" w+ x0 k/ |% ]2 h
COM端:接3.3V
DRV_ENN:使能,接PB149 H5 M6 t9 @6 F
DIR:方向, PB159 p1 I. c. C8 m% q Z6 q
STEP:脉冲,PA8/ D6 ~2 u; U; p3 l: p