STM32固件库分享,超全系列整理
小马哥STM32F103开源小四轴RoboFly全部资料大放送
【MCU实战经验】+STM32F107的USB使用
基于STM32F103两轮平衡小车设计(开源)
STM32F107VCT6官方原理图和PCB
【福利】用STM32库的朋友有福了:STM32F10x_StdPeriph_Lib_V3.5.0chm...
基于STM32F10xx存储器和系统架构经验分享
基于STM32F1的CAN通信之BH1750
基于STM32F1的CAN通信之OLED
基于STM32F1的CAN通信之之串口IAP
/**/ V' o1 M! d' \; {0 t% Q* k
* 函数功能: 定时器中断服务函数9 ?. A7 m/ ~+ ]( j& n
* 输入参数: 无' p5 n* g4 r% t, [
* 返 回 值: 无: Y+ M0 f$ R. Z; s3 z# ^/ W
* 说 明: 实现加减速过程& D0 n) D) q- g; u% ]; T
*/: A @+ A0 O7 R; B1 Z
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{ , w O3 [6 F& i9 r b G o1 C/ T
__IO uint16_t tim_count=0;
// 保存新(下)一个延时周期
uint16_t new_step_delay=0;
// 加速过程中最后一次延时(脉冲周期).
__IO static uint16_t last_accel_delay=0;
// 总移动步数计数器) L d/ v# W8 m1 T9 z! Y7 e$ h
__IO static uint32_t step_count = 0;* f2 [! J$ ?( [$ r6 v) ?
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t i=0;$ X! ~, T, D1 y9 r! X0 _& w7 \
4 |! n+ G7 t4 C, J+ {% w
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET), z. m+ N- B" P
{
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
& b5 q% _5 w! a& B: k+ h2 J$ V
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR); d% F3 k6 y# ?% @; t
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);
' ~* e* K @2 e/ ? p( D' {
i++; // 定时器中断次数计数值/ {" q9 ^' P- t- N- n$ K, J
if(i==2) // 2次,说明已经输出一个完整脉冲
{
i=0; // 清零定时器中断次数计数值
switch(srd.run_state) // 加减速曲线阶段
{
case STOP:( w2 I3 L+ c2 m1 s. O6 M
step_count = 0; // 清零步数计数器
rest = 0; // 清零余值
// 关闭通道$ [: K D" u4 w8 P( E! y
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE); 7 s+ `% e0 L. n1 O' I5 ^1 S0 {
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);
STEPMOTOR_OUTPUT_DISABLE();
MotionStatus = 0; // 电机为停止状态
break;
case ACCEL:
step_count++; // 步数加1! T2 R9 P' f Y, n5 l
if(srd.dir==CW)
{
step_position++; // 绝对位置加19 Z( h! s% G! { x9 g
}
else% h" \1 U/ h6 f4 d
{
step_position--; // 绝对位置减1. m Q: d# B2 e1 ?4 j
}. y! }5 q7 ^2 k* h/ t5 f7 C& D
srd.accel_count++; // 加速计数值加17 [9 ?( J' T: ^; O7 D, i& {
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);// 计算余数,下次计算补上余数,减少误差& i8 {6 }1 u# \$ N: f& ]' V r
if(step_count >= srd.decel_start)// 检查是够应该开始减速
{
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值- j# ~# Z: b' A) ~3 P- X
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)2 b9 H6 L3 _3 o3 n1 g
rest = 0; // 清零余值" ?+ f& t9 |5 [" X" I
srd.run_state = RUN; // 设置为匀速运行状态" t; _0 a E: @2 j4 K# J( \8 E- Y
}* l; U9 r; l, b1 ~1 n# ?8 x' D' r
break;
( N& B6 K- q% y X2 [
case RUN:
step_count++; // 步数加1( h: I2 ]/ i e- N) @
if(srd.dir==CW)( d, `% W* g% |
{ , S1 S1 i$ T0 {* b: j3 y2 F5 N
step_position++; // 绝对位置加1/ \) B9 z: ?4 v# x. l2 ?; h
}+ i- ]/ g" Q' u# |/ k
else
{
step_position--; // 绝对位置减1 z! ~1 T% A( ^4 |6 K& e
}+ ~1 ` a9 G( H& p5 M
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
if(step_count >= srd.decel_start) // 需要开始减速
{* `1 |1 A, @& u0 k. h) n8 S
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值0 \2 L3 x; W" O j6 }) Y' A& [
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)9 z9 f- O. i4 g9 E# e. ?
srd.run_state = DECEL; // 状态改变为减速6 e" m/ g0 `: b1 L3 U) S
}. Y8 G, t/ L- R' {5 u, q1 X
break;
/ e" q/ x( V% t+ _
case DECEL:7 q3 H+ @) f& \: E
step_count++; // 步数加1
if(srd.dir==CW)' f) g% A1 ^; P+ M' _/ O" A2 J' B
{
step_position++; // 绝对位置加1
}
else( y; D0 p* B, ~6 P t! R
{
step_position--; // 绝对位置减1: ]% x1 U C3 M5 j% e% {
}. b6 x, o0 H4 }# `
srd.accel_count++;/ a/ b, p) H. O1 g& m% R8 v
new_step_delay = srd.step_delay - (((2 * srd.step_delay) + rest)/(4 * srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔)3 y0 u# h7 U7 c$ r
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
, @+ K) i( w+ f$ z. i" u1 C+ S
//检查是否为最后一步
if(srd.accel_count >= 0)
{
srd.run_state = STOP;" \/ F# o" x6 i- M3 y
}
break;
}
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}- M8 Q5 q$ c3 x: X
}
}
/**0 S [5 [" C o
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).
accel 加速度,实际值为accel*0.1*rad/sec^2, I; r6 r& @( B* Q* J) R7 e4 ]
decel 减速度,实际值为decel*0.1*rad/sec^2
speed 最大速度,实际值为speed*0.1*rad/sec
* 返 回 值: 无8 a' D1 \5 ~: ?) p0 {
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且* G6 k) N" [" s$ E, T6 l8 J8 Q
* 速度很慢,那还没达到最大速度就要开始减速
*/
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)/ `4 D+ H8 H4 z
{
__IO uint16_t tim_count;$ k3 }' J1 @! i9 R
// 达到最大速度时的步数& A/ j9 ^: {8 H4 x
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t accel_lim;
if(step < 0) // 步数为负数$ V" S/ ~5 Y6 M( L# D
{
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值
}
else# r6 M( I% Z. D( v/ r
{5 e; {- P$ f L; M
srd.dir = CW; // 顺时针方向旋转5 _. c$ w6 w+ g* ~; B& J' o
STEPMOTOR_DIR_FORWARD();
}, ~0 H+ P3 _1 V. q/ \8 I7 C
$ T s4 a: I0 ^5 Q* ]. J: h
if(step == 1) // 步数为1
{! Z0 F. P0 a. C' \/ W# J/ j
srd.accel_count = -1; // 只移动一步
srd.run_state = DECEL; // 减速状态.: Z- P. C- v7 e7 l% P
srd.step_delay = 1000; // 短延时
}
else if(step != 0) // 如果目标运动步数不为0
{
// 我们的驱动器用户手册有详细的计算及推导过程
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。- \6 r+ x- |) L7 F* e* }' G
// min_delay = (alpha / tt)/ w
srd.min_delay = (int32_t)(A_T_x10/speed);0 E- n3 L: ~. d: p
; A$ W5 J0 y+ |" f3 a, Q2 V
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^2
// step_delay = 1/tt * sqrt(2*alpha/accel)' I$ m( u- h4 H: m1 a2 F
// 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);) V& {; Z, Y0 u. ?. [' B
// 计算多少步之后达到最大速度的限制, M, l0 P8 r& c) V
// max_s_lim = speed^2 / (2*alpha*accel)0 S4 m9 a9 b" s5 w8 q
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));% |% g7 @; q: H, W, D: a, s8 s
// 如果达到最大速度小于0.5步,我们将四舍五入为0 V* o3 g; A" p. z X4 w$ b
// 但实际我们必须移动至少一步才能达到想要的速度( R0 ]6 R5 F0 k
if(max_s_lim == 0){
max_s_lim = 1;
}
// n1 = (n1+n2)decel / (accel + decel)
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.
if(accel_lim == 0){
accel_lim = 1;
}
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){- ~! J% _/ O0 m0 Y
srd.decel_val = accel_lim - step;9 d; e4 z* l$ J
}, I9 M6 H/ H# o
else{
srd.decel_val = -(max_s_lim*accel/decel);
}
// 当只剩下一步我们必须减速) L" a4 ]. s* N, [/ [4 a! p1 v
if(srd.decel_val == 0){! T1 M0 g8 v+ X( z4 }8 f
srd.decel_val = -1;
}5 B! H& p0 a; _: d% w6 n5 i
) p; z! W% s Z& d3 B* V
// 计算开始减速时的步数, Q& f% B, Z5 I0 ~; `( ]* q
srd.decel_start = step + srd.decel_val; k$ ]. \* q; Z
8 M- w! C# n o
// 如果最大速度很慢,我们就不需要进行加速运动
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;: |% ?% X' i( u }1 Y; L1 p9 U
srd.run_state = RUN;1 d& Z) v$ W; }
}& l8 s" W' t2 }; j, ? W/ c# Y' q( Q
else{
srd.run_state = ACCEL;
} - x2 ]; O) h3 X. ~
// 复位加速度计数值
srd.accel_count = 0;
}$ [9 ^. |: {5 y/ u) u7 n& 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); // 设置定时器比较值% w4 g! k/ f1 F; z" V
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_ENABLE); // 使能定时器通道 1 |& F$ D% E- c& v, B
STEPMOTOR_OUTPUT_ENABLE();# g* k/ W8 ?8 q3 ~) h4 ]
}3 k' H) H* @, ^3 i7 F
1、机器人和工业驱动器1 F2 v2 U0 a, ]; y# Q5 {! g; P3 G
2、纺织、缝纫机8 v. z+ n5 N! |% {0 o& L! s8 k
3、包装机械$ X# P( `& Y6 a
4、工厂和实验室自动化
5、高速 3D 打印机% s0 Q; b" i: j7 }& {: g/ X
6、液体处理
7、医疗( `! F5 q* B- B
8、办公自动化/ Z1 m9 f/ |4 l4 B+ D7 Y& i! }
9、有线闭路电视! ], j4 `$ g, i6 ^8 q4 M
10、自动取款机、现金回收
11、泵和阀门
电机驱动主芯片采用TMC21602 C( B0 X E0 I! U' W
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;
4 g+ w: j3 q. {1 J3 m" t
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)1 g# X' x; g* n9 `) S. k
拨码开关ON:设置为高电平1,反之低电平0
细分设置:CFG1、CFG0
CFG1、CFG0:
11:64细分 Q; I2 b& i+ V) F
10:32细分, @: R4 E9 I/ [! r/ w
01:16细分
00:8细分9 @, Q5 s* U0 ~' Z' `: {4 r
运行电流设置:CFG4、CFG3、CFG2# E- R3 L$ N" U& S/ y, h; H0 Y
CFG4、CFG3、CFG2:
111:IRUN=31
110:IRUN=28
101:IRUN=260 P7 l# h4 k. G! ~+ J* {# W
100:IRUN=24' J b8 q# e4 T0 y, C6 c% N
011:IRUN=22& |3 k( L$ [* Z
010:IRUN=20) e( G5 w* @# i) U3 b
001:IRUN=18( M8 U8 V2 b, b
000:IRUN=16
Irms=Vfs/(IRUN/32)/(Rsense*1.414); - {& F! P" P3 P/ z1 s: i
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
CFG5:9 G$ N. |( J+ P2 d. }4 m
1:SpreadCyle模式,低速、低平稳运行模式2 X8 o y6 H: G/ h- l- [% ]
0:SpreadCyle模式,高速、高运动稳定模式
保持电流设置:CFG6
CFG6:
1:保持电流=运行电流/2# T" F" ^& s4 H/ ?; L
0:保持电流=运行电流5 L/ z5 {0 B3 `9 M9 J
DIR+STEP接口模式位置控制(无需SPI接口)& [ c$ a6 p0 w% ^9 ?! D6 s$ E
COM端:接24V或12V或5V
DRV_ENN、STER、DIR:接集电极开路输出
为测试方便:
COM端:接3.3V/ c; g; h/ L' l# ~6 J
DRV_ENN:使能,接PB14
DIR:方向, PB159 `' U- t! n, p& a1 O) e
STEP:脉冲,PA8( Z$ E; L3 q% I8 Q; l7 q