STM32F103移植LittlevGUI代码
使用STM32F103制作的无线下载器
【MCU实战经验】+自制MP3使用STM32F103ZET6和ch375读取u盘,vs1003解码,音质超棒
串口通信波特率异常的解决办法
小马哥STM32F103开源小四轴RoboFly全部资料大放送
【MCU实战经验】+STM32F103的uCOSII详细移植
在高容量 STM32F103xx 微控制器中实现 ADPCM 算法
STM32F103标准库开发---SPI实验---读写 W25Q128 外部 Flash
RT-Thread在STM32F103RC上移植
STM32固件库分享,超全系列整理
/**
* 函数功能: 定时器中断服务函数3 u7 {" e, z3 ^
* 输入参数: 无
* 返 回 值: 无
* 说 明: 实现加减速过程# Z4 a3 w! s1 X( c
*/
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理 T6 @4 c+ W" @
{
__IO uint16_t tim_count=0;0 i# }9 O0 ~0 n" g |, N+ Q2 u! Z; J
// 保存新(下)一个延时周期! I8 y: }( X6 d8 \; e0 w- m. E/ t
uint16_t new_step_delay=0;
// 加速过程中最后一次延时(脉冲周期).
__IO static uint16_t last_accel_delay=0;, g: V) } T4 O- O; ?+ c5 a
// 总移动步数计数器, h) S1 f; q3 L5 u0 V* k
__IO static uint32_t step_count = 0;+ M& E/ O) }# ]# z+ a2 `% F
// 记录new_step_delay中的余数,提高下一步计算的精度% x4 F, f/ x/ J% V; E+ T$ |+ T# {% ~
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t i=0;
' N, }. Q4 L. y5 p* W5 ]) T
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)- r6 j+ I. p+ l9 v8 o
{
// 清楚定时器中断3 A6 b* A3 z/ {; D7 Q
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
( f6 i- H$ _; F' t2 U1 ?8 H
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);
+ o* z% A6 C8 G( m# n
i++; // 定时器中断次数计数值
if(i==2) // 2次,说明已经输出一个完整脉冲; A6 m# z$ b* |5 @' ~' ?6 b
{
i=0; // 清零定时器中断次数计数值
switch(srd.run_state) // 加减速曲线阶段
{/ I, Y2 N( @) ]/ Z) z: W
case STOP:: l' k8 ^7 x1 Q& \+ m& D0 B
step_count = 0; // 清零步数计数器: p: W9 D$ B8 Y2 k1 b' m
rest = 0; // 清零余值
// 关闭通道
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE); " h+ }5 ?5 c1 e# N" n
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);0 g) M( \1 ]3 {8 G- q$ A9 R8 X' [" V
STEPMOTOR_OUTPUT_DISABLE();& r+ M, k, w) l6 d; n5 @
MotionStatus = 0; // 电机为停止状态 ! o/ M6 N7 J2 N& V: h. K
break;. _# j# k, b' m: y
case ACCEL:
step_count++; // 步数加11 w" f. J. \9 ], p( u. z9 _
if(srd.dir==CW)' m' F ?. m: L6 Q5 s! q
{ $ ^ n( Y7 `4 R# K1 t
step_position++; // 绝对位置加1
}
else- t7 D% C) ^" h: f7 D& `
{
step_position--; // 绝对位置减1
}3 S: f0 Y0 N2 o# a$ [* }3 Z
srd.accel_count++; // 加速计数值加1
new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)8 p3 N9 t' P! [) ], W5 I4 O8 ?* C1 a
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差5 C9 [$ A$ Y% S
if(step_count >= srd.decel_start)// 检查是够应该开始减速& d$ P" {! y( t" i5 }4 l& Q4 Z1 Y
{# W8 F# A( |+ _" P$ ^$ U- e
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值
srd.run_state = DECEL; // 下个脉冲进入减速阶段/ U) h6 l+ S9 C7 A2 o
}' k( V4 L; u/ H5 d3 P4 O
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{9 p+ c0 l7 v. w, S3 r/ H
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)# M4 a6 _: L: Y/ B9 T8 V% u
rest = 0; // 清零余值
srd.run_state = RUN; // 设置为匀速运行状态+ _2 s9 ?; y- j4 @, w- G) M& P7 c
}' c# J& j3 t6 l9 }# M# M& K
break;' A- f7 y% r! u/ U; v9 \
case RUN:
step_count++; // 步数加1
if(srd.dir==CW) T' y9 F' X! ?6 ]5 L8 o/ q
{ 4 [6 P7 x) C* k
step_position++; // 绝对位置加1, D" z" r- }6 P) z: H+ b. ?
}
else( G, E* M+ d( z. q0 }
{
step_position--; // 绝对位置减13 m8 G- c: y; P9 O* N/ Q7 M3 j/ j! W
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
if(step_count >= srd.decel_start) // 需要开始减速/ u( @, Y" X2 K" O& ]; p7 A6 l# e0 @0 D
{
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
srd.run_state = DECEL; // 状态改变为减速
}9 W( ~5 L4 r. ~- G8 s+ T
break;
- @( v! y# F" l' o% x
case DECEL:
step_count++; // 步数加14 J8 p B2 h% \, {0 v7 d- C
if(srd.dir==CW)# S- t' S0 u* k2 ~$ M$ z: \
{
step_position++; // 绝对位置加15 E* t* c$ @4 b" U" a6 `
}4 q; X' _8 ?8 T0 G) R
else
{4 S; S' M5 j7 |. ?
step_position--; // 绝对位置减1
}7 G5 P7 D, G. |, T6 T3 N% s; h
srd.accel_count++;, W' y# R& |, _4 v
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 G% J0 q* S6 i% f; M
//检查是否为最后一步1 e4 A5 W8 o: C1 p
if(srd.accel_count >= 0)! m% ?1 B. T/ ] o# e: K2 U( ]
{! T- Z& B3 E u( i% k
srd.run_state = STOP;
}, h) R% y( n$ \3 n2 o! D- L3 d
break;# z; q( Y5 G- u" o/ g! f
} ! G. S8 y9 \9 s+ B
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值* M, v! i( i; G5 A% K1 w" @
}
}) F7 A# c7 Y8 _2 E
}1 k' |8 D1 f7 E* {% q0 B6 {$ F7 b8 h
/**
* 函数功能: 相对位置运动:运动给定的步数( H) u# d) u3 i# X1 [" y5 M' s. a" \
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).
accel 加速度,实际值为accel*0.1*rad/sec^2
decel 减速度,实际值为decel*0.1*rad/sec^2! s+ e. }. X _3 n+ V+ ?" h) f% r
speed 最大速度,实际值为speed*0.1*rad/sec! k- j- P4 `* c# ~0 `
* 返 回 值: 无 W+ L9 a ]- Q+ D, d# H6 x! r$ K
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且0 o- d5 h+ Y1 K% P
* 速度很慢,那还没达到最大速度就要开始减速
*/' s! X/ V) ?7 B! K* i b
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{ 9 r% q: T. k8 Z
__IO uint16_t tim_count;6 _" m2 j! C3 I+ b1 G( \
// 达到最大速度时的步数
__IO uint32_t max_s_lim;9 a- o( {) C- o) V+ p [* ?
// 必须要开始减速的步数(如果加速没有达到最大速度)6 ^9 v: }/ z* M' v: U
__IO uint32_t accel_lim;
if(step < 0) // 步数为负数
{2 ]3 u/ v, h' g9 I" M
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();' [3 e% M3 N7 S; K, b
step =-step; // 获取步数绝对值% r1 K5 o+ h) a: j( i
}: | ?. O, [3 [& V; }! h a
else) m: `2 B. b T" j& q' E7 o
{
srd.dir = CW; // 顺时针方向旋转8 d$ N/ [: B8 ~7 {# [
STEPMOTOR_DIR_FORWARD();
}
if(step == 1) // 步数为1, \9 ]4 \! S+ ~6 Q
{: p; _3 a9 Q/ C4 U( C
srd.accel_count = -1; // 只移动一步& X: v$ l! n a5 j3 @, G
srd.run_state = DECEL; // 减速状态.0 t2 d) \1 \" B$ \0 ]" F
srd.step_delay = 1000; // 短延时
}
else if(step != 0) // 如果目标运动步数不为0
{
// 我们的驱动器用户手册有详细的计算及推导过程/ `. A1 T. l Q; @, _# w1 {
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w
srd.min_delay = (int32_t)(A_T_x10/speed);
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^21 U, M. m) m) N+ F7 K# m
// 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);' H6 \+ b3 B( H; Q8 A
// 计算多少步之后达到最大速度的限制2 L7 @+ T# Z4 p4 n9 O
// max_s_lim = speed^2 / (2*alpha*accel); C# R$ ?5 t2 A& R; M! K
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为0) Z9 T) D1 ?1 q2 v) {8 ~6 O
// 但实际我们必须移动至少一步才能达到想要的速度
if(max_s_lim == 0){
max_s_lim = 1;
}
// n1 = (n1+n2)decel / (accel + decel); E* t% D0 A& e! G
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.
if(accel_lim == 0){4 m) f3 g* H$ J" I
accel_lim = 1;$ U( B# M" m4 B, |' O3 p8 ]
} t3 S" V0 f0 g3 k0 x
// 使用限制条件我们可以计算出减速阶段步数5 Z- r5 K3 }' `+ Z
if(accel_lim <= max_s_lim){0 m* Q$ `) f" a0 T& ^" t
srd.decel_val = accel_lim - step;
}: Z0 y2 O6 m, e5 v8 T
else{
srd.decel_val = -(max_s_lim*accel/decel);0 ]' P' c) u* `1 b! J, \
}
// 当只剩下一步我们必须减速: \+ x. X) a" j
if(srd.decel_val == 0){
srd.decel_val = -1;+ c2 l9 B, @, Y6 i) _
}
$ a4 m3 W6 M+ B! y, [
// 计算开始减速时的步数
srd.decel_start = step + srd.decel_val; J. J. ^( p4 G/ b2 C0 V$ u& s
% g( v+ Z5 h. h" W# }
// 如果最大速度很慢,我们就不需要进行加速运动
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;) ?# D' ~3 w* e& v& O" _
srd.run_state = RUN;
}
else{' [! D. ~' f) Z, t8 T
srd.run_state = ACCEL;* t4 K) [: W4 y( A7 e$ C) y
}
// 复位加速度计数值
srd.accel_count = 0;5 V7 n3 y$ U7 @4 y. x
}7 y. y; F* _3 M
MotionStatus = 1; // 电机为运动状态
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);1 o w0 F# d/ i4 s9 w+ j8 |
__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 P5 h2 H7 W" Y/ y3 f
}: k$ ^1 F- L6 F7 a3 y7 }) \2 m
1、机器人和工业驱动器/ p w1 Q }0 o4 x
2、纺织、缝纫机
3、包装机械; D2 }: p! l' x
4、工厂和实验室自动化3 S1 j& O& M: Y. |! r
5、高速 3D 打印机
6、液体处理
7、医疗' U1 P( P% I' A* ?+ h
8、办公自动化7 {9 A. R K; ~( j; A5 ]
9、有线闭路电视
10、自动取款机、现金回收4 w, Q) P) o% w
11、泵和阀门
电机驱动主芯片采用TMC2160
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;; S1 s: {9 ~1 q
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)" N- A" F8 F9 F8 W
0 B1 h/ t& V! Y/ F, B3 U% z
拨码开关ON:设置为高电平1,反之低电平0
细分设置:CFG1、CFG0$ e! b% c" ^, n3 f
CFG1、CFG0:
11:64细分
10:32细分4 H0 r: ^! S% G2 w$ B
01:16细分5 P0 Z0 [1 G: ?! L
00:8细分# v x6 u0 S8 N4 B3 O
运行电流设置:CFG4、CFG3、CFG23 D) ^: F. {$ ^& ?! K
CFG4、CFG3、CFG2:
111:IRUN=319 X$ t: e) Y4 U$ p. t# T
110:IRUN=28
101:IRUN=26
100:IRUN=24
011:IRUN=22
010:IRUN=20
001:IRUN=18
000:IRUN=16
Irms=Vfs/(IRUN/32)/(Rsense*1.414);
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
CFG5:, a& _/ c0 Y H& r
1:SpreadCyle模式,低速、低平稳运行模式% Z9 ?; u0 F+ J7 A' Q& Y3 o b
0:SpreadCyle模式,高速、高运动稳定模式
保持电流设置:CFG6
CFG6:
1:保持电流=运行电流/2
0:保持电流=运行电流
DIR+STEP接口模式位置控制(无需SPI接口)9 }. e" e" I6 Z& A& L
COM端:接24V或12V或5V
DRV_ENN、STER、DIR:接集电极开路输出0 G: f' }7 u, H" q
为测试方便:4 X' _$ C0 l. V7 q# R
COM端:接3.3V4 i3 H4 s9 u! N4 M* Y: x* c
DRV_ENN:使能,接PB146 F8 R: ^) W, s2 W
DIR:方向, PB15; O1 n' T$ k; E2 p5 b I7 n
STEP:脉冲,PA8