【MCU实战经验】+STM32F107的USB使用
基于STM32F103两轮平衡小车设计(开源)
STM32固件库分享,超全系列整理
STM32F107VCT6官方原理图和PCB
【福利】用STM32库的朋友有福了:STM32F10x_StdPeriph_Lib_V3.5.0chm...
小马哥STM32F103开源小四轴RoboFly全部资料大放送
基于STM32F10xx存储器和系统架构经验分享
基于STM32F1的CAN通信之BH1750
基于STM32F1的CAN通信之OLED
基于STM32F1的CAN通信之之串口IAP
/**: Z0 K6 F- u9 L, _. H f
* 函数功能: 定时器中断服务函数
* 输入参数: 无
* 返 回 值: 无$ s" ?0 G2 L9 |6 X
* 说 明: 实现加减速过程
*/# z% G7 V% w( j/ m5 W* A/ m2 `, v
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{
__IO uint16_t tim_count=0;, V4 o I* A" Y' \5 I
// 保存新(下)一个延时周期. l9 E$ e( Z. D
uint16_t new_step_delay=0;
// 加速过程中最后一次延时(脉冲周期).- M9 V; e( d* P
__IO static uint16_t last_accel_delay=0;
// 总移动步数计数器
__IO static uint32_t step_count = 0;
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t i=0;* p( p# E$ R& j: Q5 q6 g5 U
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)
{0 O0 R7 V& {& B
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);/ K0 T4 p' |" J8 a$ Z5 {/ q
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);1 P. @$ |9 M# J2 g j
/ A( d3 b# E8 L* M
i++; // 定时器中断次数计数值
if(i==2) // 2次,说明已经输出一个完整脉冲
{
i=0; // 清零定时器中断次数计数值
switch(srd.run_state) // 加减速曲线阶段% F6 T! H' Q$ I( {
{
case STOP:+ y4 \1 P; d: p0 u* ~
step_count = 0; // 清零步数计数器
rest = 0; // 清零余值& |+ t5 H9 O7 ^! c
// 关闭通道# h n y; c" x' W8 r! ?: p
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE); & F" O+ ~; ~5 @3 C- Q" V7 P
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);8 d+ w Q: J0 h% m
STEPMOTOR_OUTPUT_DISABLE();. v* I1 ~* g9 `# L# [8 Z+ R& P4 M
MotionStatus = 0; // 电机为停止状态
break;
case ACCEL:
step_count++; // 步数加1
if(srd.dir==CW)- x: t7 O5 Q5 c% ~: a
{ - P/ S: b' ]/ c, G5 I9 z
step_position++; // 绝对位置加1
}
else
{" f$ s9 @5 i: _* B- G
step_position--; // 绝对位置减15 H! |$ a/ ]) x7 D. C
}
srd.accel_count++; // 加速计数值加1
new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)/ [7 ^4 D: d2 f+ T! V
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
if(step_count >= srd.decel_start)// 检查是够应该开始减速, G. h! F$ l0 E) v( {9 ?
{& W+ K4 `+ u& g4 \, Z
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度- w! h' z$ t* n1 U
{4 e: L9 I( {4 t( ] @! T/ g6 @
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期). B! k0 F) B" O5 }2 \! o) g
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
rest = 0; // 清零余值
srd.run_state = RUN; // 设置为匀速运行状态' S, L" I2 y7 }. C% ^) S
}
break;
9 u( c- W" l% x
case RUN:
step_count++; // 步数加1
if(srd.dir==CW) K4 D7 e- _3 C# z q
{ $ [9 b8 x0 b' T
step_position++; // 绝对位置加1 y. C. J- T- v) b8 l$ U6 h& E/ U3 W
}
else; N9 H7 m# |* T( H0 Y9 T+ E
{2 y3 f. {7 d$ B. @4 n5 k8 t
step_position--; // 绝对位置减1# z6 O: }1 i8 K+ Y, i8 o8 t: D
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)8 z! w. w+ X6 ]- Y4 o
if(step_count >= srd.decel_start) // 需要开始减速1 H! l) m) E9 c, f* ?- g7 Z) Q+ R
{- U0 d- K1 w; H1 o' @0 r
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
srd.run_state = DECEL; // 状态改变为减速
} U2 p) K6 g. o
break;: r6 o7 s) v% @8 _
case DECEL:
step_count++; // 步数加1* r2 I: ]- B, z
if(srd.dir==CW)
{
step_position++; // 绝对位置加1
}
else
{+ C" n+ s5 }7 S" l
step_position--; // 绝对位置减1
}$ V" q! y r; p" d/ |4 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);// 计算余数,下次计算补上余数,减少误差6 _( Y, T" T7 U$ {2 U
//检查是否为最后一步4 c" K% d# G% l$ U' T# N# O
if(srd.accel_count >= 0)/ h& v3 f5 I5 n+ O3 W- f
{
srd.run_state = STOP;$ Q, B H0 i$ l/ z# h# V. T2 u
}
break;
}
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}
}
}
/**
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).! @. j2 K- q! C( [/ ?* B' A% K* i
accel 加速度,实际值为accel*0.1*rad/sec^2+ M: E4 ^0 t4 j1 r; z; J1 H
decel 减速度,实际值为decel*0.1*rad/sec^27 E" z3 `% x% d' ], n) ^! x% E; K
speed 最大速度,实际值为speed*0.1*rad/sec! B# K' |5 K0 \) @/ O( o
* 返 回 值: 无
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且
* 速度很慢,那还没达到最大速度就要开始减速
*/; G% D3 R3 J* P/ q, Q
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{
__IO uint16_t tim_count;# v8 K* R% W4 j6 v( c1 @% e
// 达到最大速度时的步数
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)$ L/ m* }* x2 F2 v' e- K; y5 @6 \
__IO uint32_t accel_lim;
) e6 `9 W8 I1 m7 f4 S
if(step < 0) // 步数为负数% O, _$ B7 a# p. v/ M
{
srd.dir = CCW; // 逆时针方向旋转, a5 A/ l7 X# f" m5 p; w% ^ q* K
STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值
}
else' I4 ]: W8 d% D, q' ^# D
{4 h8 w% k& z5 z1 q. |* {! L
srd.dir = CW; // 顺时针方向旋转- O; O: j" |% {0 ^) ^+ n* e
STEPMOTOR_DIR_FORWARD();) q9 u& o) }9 F- B6 ^
}/ E4 Y# y5 i1 I) E' R
, e; k8 O @. @$ U3 h
if(step == 1) // 步数为14 u7 F5 ?" G+ d& m: t1 R( Q1 b% }4 Y' i
{# m8 A( {' \3 [& W& N; g& k
srd.accel_count = -1; // 只移动一步
srd.run_state = DECEL; // 减速状态.* C4 O& E6 D, V& t0 H
srd.step_delay = 1000; // 短延时 ' b+ t5 q8 ]! s6 E4 w8 P+ U
}
else if(step != 0) // 如果目标运动步数不为0
{7 ?1 V2 s% s0 x( ~% h
// 我们的驱动器用户手册有详细的计算及推导过程, h l" I" I& S; ]+ T9 j* w: a9 [2 k; M
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。3 r( |. m. `$ D$ V& k7 n
// min_delay = (alpha / tt)/ w# r( H6 n" H, v& t
srd.min_delay = (int32_t)(A_T_x10/speed);
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^27 E" y' @5 o4 [, J8 ?
// step_delay = 1/tt * sqrt(2*alpha/accel)
// step_delay = ( tfreq*0.676/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/100& C+ w; C# h6 t/ H) m* W
srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);
9 _ `- L& q1 {! _" [+ t( ]
// 计算多少步之后达到最大速度的限制: u/ P) `3 x& I$ J/ U& [! z; T2 R
// max_s_lim = speed^2 / (2*alpha*accel). F! R5 l4 `5 Z% m8 k
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));: R z5 Q8 S9 w, @5 A
// 如果达到最大速度小于0.5步,我们将四舍五入为0+ d' j' o" Q/ \( W
// 但实际我们必须移动至少一步才能达到想要的速度
if(max_s_lim == 0){
max_s_lim = 1;
}/ ^8 R7 V4 I3 t% S" S& d
// n1 = (n1+n2)decel / (accel + decel)$ A' n5 I; }/ K
accel_lim = (uint32_t)(step*decel/(accel+decel));, ?( M: z) c5 L+ V" t5 Q. z
// 我们必须加速至少1步才能才能开始减速.. C T/ u) ]) O2 o4 y: d; T0 K
if(accel_lim == 0){
accel_lim = 1;, E7 d5 K4 I, Q9 _: B& h
}
9 x4 h' E. G# C- v J. j
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){& M L! E* @( A
srd.decel_val = accel_lim - step;7 C' ?0 [* Y$ B- c
}
else{; B Z# J% @. p2 s9 y3 r
srd.decel_val = -(max_s_lim*accel/decel);
}
// 当只剩下一步我们必须减速+ `/ b7 s( X( }$ F) _' s C0 Q
if(srd.decel_val == 0){
srd.decel_val = -1;: s; ~. X: ?3 Z' I0 U! S3 Y
}+ h! _: w( }6 x- ^5 E
7 S8 S" ]4 ~# j9 @7 T1 W
// 计算开始减速时的步数, V2 k) C* V3 S4 B& O- ^
srd.decel_start = step + srd.decel_val;
! r3 L; H5 r: \" O
// 如果最大速度很慢,我们就不需要进行加速运动% P8 g1 G% a9 ]
if(srd.step_delay <= srd.min_delay){$ ?4 m& J' `( u$ V5 H
srd.step_delay = srd.min_delay;3 x; C) u! G: `; c
srd.run_state = RUN;8 A, M1 e$ \$ |
}2 E Y, x4 P. L+ j J* U5 r
else{
srd.run_state = ACCEL;
} # e) n; t$ q4 ~0 l2 ^3 \
// 复位加速度计数值
srd.accel_count = 0;
}1 i! b! h p7 d, z" ~; V9 n$ k
MotionStatus = 1; // 电机为运动状态
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);3 E$ \8 |" N2 o: t7 \( `
__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); // 使能定时器通道 : [/ A/ D: p6 d
STEPMOTOR_OUTPUT_ENABLE();/ N2 b$ N3 E" H0 |2 ^9 z
}# x2 a7 q! x" r, y. X
1、机器人和工业驱动器1 _9 O- G) ` v0 Q& j" G" |6 ^
2、纺织、缝纫机2 E4 h4 f2 W5 p
3、包装机械
4、工厂和实验室自动化) K' h( K2 j# E. V9 L
5、高速 3D 打印机0 S/ M8 c, a* P. e
6、液体处理
7、医疗
8、办公自动化
9、有线闭路电视
10、自动取款机、现金回收3 I$ l6 @) L! b+ X6 W1 ]9 i" W
11、泵和阀门
电机驱动主芯片采用TMC2160
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);* Z9 R! L. P5 u3 u
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;
# a8 L. U8 O2 A# T
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)
' \: P1 T# H3 P% ]# T: K9 l
拨码开关ON:设置为高电平1,反之低电平0
细分设置:CFG1、CFG0
CFG1、CFG0:
11:64细分0 u9 m8 z9 U; [: h: ? H; d7 r
10:32细分; _' a3 M+ J! e1 R
01:16细分
00:8细分7 V& J/ V2 f, m. L
运行电流设置:CFG4、CFG3、CFG2& m, {5 e2 y% t2 b, L) [
CFG4、CFG3、CFG2:
111:IRUN=31' o% V* _) b8 c! l/ c
110:IRUN=282 p$ @$ t e, u- g# j( ^% ]0 q0 @
101:IRUN=26
100:IRUN=24; ^& ], t- r" e- ~, A
011:IRUN=22$ v$ x3 W- K3 e. {* s$ B
010:IRUN=204 }" `# [7 E# O% B. V
001:IRUN=18
000:IRUN=167 s% P2 ~6 W5 l# j( P( u2 u
Irms=Vfs/(IRUN/32)/(Rsense*1.414); 3 n, d6 H+ g# `& B! `, c$ j0 r
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
CFG5:
1:SpreadCyle模式,低速、低平稳运行模式$ ?5 h! u3 z9 O' n% ~" p
0:SpreadCyle模式,高速、高运动稳定模式
保持电流设置:CFG6" K/ G$ R: M' V' w: [
CFG6:# `' Z! d) z) W. x% U3 B
1:保持电流=运行电流/2
0:保持电流=运行电流1 ?/ `) O* W$ B3 f' p" L
DIR+STEP接口模式位置控制(无需SPI接口)
COM端:接24V或12V或5V: _9 {* V3 T$ U" h4 c
DRV_ENN、STER、DIR:接集电极开路输出
为测试方便:
COM端:接3.3V
DRV_ENN:使能,接PB14
DIR:方向, PB15# c. U, m6 I$ f6 u. B- Y j6 \2 w
STEP:脉冲,PA8