小马哥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
/**
* 函数功能: 定时器中断服务函数; {$ m+ `; D3 K
* 输入参数: 无
* 返 回 值: 无
* 说 明: 实现加减速过程 j5 b _# C9 |" @* N; L
*/
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理2 y T- H# [/ N) Z( W+ f
{ : R+ ]1 c2 t0 b7 Z
__IO uint16_t tim_count=0;
// 保存新(下)一个延时周期" k& E5 B0 y0 B1 i1 i7 H( A: t
uint16_t new_step_delay=0;
// 加速过程中最后一次延时(脉冲周期). C% g B; G6 a0 P* o$ R( T
__IO static uint16_t last_accel_delay=0;0 s1 ~& a& c9 ?; }% ~7 e$ w/ N+ _
// 总移动步数计数器. E* {! A' g6 r! E
__IO static uint32_t step_count = 0;7 ]( L7 l3 {+ y& R2 u
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;6 f- r% X( ]. [' |" [5 L
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲' L$ c. L& C f7 Q* n& w
__IO static uint8_t i=0;
1 P. t8 _6 e: V$ q% ^) q0 \) r7 h
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)$ a+ |+ W3 m/ k) C. m
{
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
+ M8 R# ^" J8 Z$ R7 O
// 设置比较值1 E+ [" g7 y8 S* Y4 w7 {
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);9 F4 v' W4 B6 B) R3 Z, X/ U
i++; // 定时器中断次数计数值/ D, U' j5 g, Q* R9 g* D6 ]+ `# r( X
if(i==2) // 2次,说明已经输出一个完整脉冲, I# \& X7 g$ W( K0 W( K
{
i=0; // 清零定时器中断次数计数值- R$ K& s$ ~8 T8 l
switch(srd.run_state) // 加减速曲线阶段
{- M6 l6 r) Z* A W
case STOP:
step_count = 0; // 清零步数计数器) V, x8 a0 h4 Z$ ]7 l
rest = 0; // 清零余值
// 关闭通道
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);4 T9 b) O) m& [1 D, C+ L8 O& F
STEPMOTOR_OUTPUT_DISABLE();" _% a) D0 F+ B/ H$ l
MotionStatus = 0; // 电机为停止状态 , i9 m/ v, `- G+ Z) t
break;
$ W3 a$ h K/ o' D4 r0 N* E9 \
case ACCEL:
step_count++; // 步数加1: d( j8 T* z6 }3 \+ f4 v- H
if(srd.dir==CW)& _9 Z; I( f/ ], ^# P
{
step_position++; // 绝对位置加1
}$ W$ i9 k1 ]# _# Z+ B
else* S' [* {! X6 A
{
step_position--; // 绝对位置减1
}& M J6 A7 J4 g; t
srd.accel_count++; // 加速计数值加1, [0 Q5 E# @, S8 m7 ^% E5 Z
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);// 计算余数,下次计算补上余数,减少误差1 E( F4 N2 M @( k9 J* j$ ?
if(step_count >= srd.decel_start)// 检查是够应该开始减速
{
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值
srd.run_state = DECEL; // 下个脉冲进入减速阶段% v: d c" k1 u4 D
}* y+ ^% q. P3 V1 w! c0 D
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)2 L9 z3 }/ O- x# ^
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
rest = 0; // 清零余值
srd.run_state = RUN; // 设置为匀速运行状态
}
break;
case RUN:
step_count++; // 步数加16 `5 b2 V& M J- N
if(srd.dir==CW)9 B6 }5 r8 H5 h3 S6 F
{
step_position++; // 绝对位置加1
}
else
{) G1 B& `/ z" a! N( G" v. e
step_position--; // 绝对位置减1
}0 n6 K8 O" u7 H) y$ w9 G ^/ L
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)# W* P/ ^1 ?8 j
if(step_count >= srd.decel_start) // 需要开始减速3 j% r3 K# Q) V( q p7 F/ A
{
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值% E: B% L8 M* e
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)2 x$ q! z* d1 ?. n# p3 z* w2 b5 P
srd.run_state = DECEL; // 状态改变为减速
}
break;- R3 r1 \! n7 J! G3 n
' }2 b! r* D Z/ j0 A1 l# w
case DECEL:
step_count++; // 步数加1
if(srd.dir==CW)5 j6 e" X. `# K6 I* F
{
step_position++; // 绝对位置加1
}
else
{
step_position--; // 绝对位置减1
}1 S7 ]9 r, B. A2 g3 I; F
srd.accel_count++;/ ], _2 Q# b) p/ p7 B0 p
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);// 计算余数,下次计算补上余数,减少误差
- l8 W6 ~6 p* i; X; |1 T+ F
//检查是否为最后一步, ^9 i O b1 [4 M! G
if(srd.accel_count >= 0)
{
srd.run_state = STOP;
}
break;
}
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}* g2 h% O: K( D
}
}7 X t$ Z$ O! A$ C4 p: ~! |1 o
/**' ?) j) m& |0 `7 P
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).
accel 加速度,实际值为accel*0.1*rad/sec^2
decel 减速度,实际值为decel*0.1*rad/sec^21 z3 P' m+ J& |# i% O8 c
speed 最大速度,实际值为speed*0.1*rad/sec
* 返 回 值: 无% E# I( `9 {1 [9 I% Y& X0 ^( z
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且
* 速度很慢,那还没达到最大速度就要开始减速 W; c3 U8 l1 ]; v8 T
*/
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed) P/ K5 y( }5 C2 a3 \8 O+ v
{ % C( i- Z, v6 z# |6 u7 L, M: m
__IO uint16_t tim_count;
// 达到最大速度时的步数3 i8 c# O8 i1 F7 f _7 Z7 J H, F
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)$ I2 h1 w* D/ V% z' Q2 k
__IO uint32_t accel_lim;2 b4 O! }5 M; e9 h
& x, ~" f( B. k# i" [$ k' F
if(step < 0) // 步数为负数
{
srd.dir = CCW; // 逆时针方向旋转2 M$ o# m9 r- `1 Q
STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值1 s8 u8 }1 u/ ^# n0 d/ A+ Q% M% P: s( B
}
else% x5 f; n! K+ D# |
{, \' J& ?2 F, @/ X5 r( R
srd.dir = CW; // 顺时针方向旋转6 N0 z. Y4 p1 {2 s; r
STEPMOTOR_DIR_FORWARD();
}
) a9 F; F1 q4 t0 u
if(step == 1) // 步数为18 g% G! b' B$ z) _1 s0 F& n1 T
{& Y7 e4 c+ {2 T% Z* Y0 Z' V
srd.accel_count = -1; // 只移动一步2 j* z- ] \7 P* t
srd.run_state = DECEL; // 减速状态.
srd.step_delay = 1000; // 短延时 , l, |5 R/ h- O# H
}4 W4 C. U) \* I* y! z/ h4 i( C
else if(step != 0) // 如果目标运动步数不为0
{
// 我们的驱动器用户手册有详细的计算及推导过程
! F$ I5 E4 ~' Q( n# b7 L) \
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w
srd.min_delay = (int32_t)(A_T_x10/speed);
1 e. d9 l* d7 g& V x) W
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^2" }, R3 k9 q* q% |8 C
// 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);
: L: i+ X8 V% f' q
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)% j/ O8 R3 Y8 y! @* B
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度% [' x& b. r& o2 w q$ Y5 F+ T+ i+ D
if(max_s_lim == 0){- K' y. K5 Y& R& w: |% o/ e
max_s_lim = 1;
}
// n1 = (n1+n2)decel / (accel + decel)3 N( ?6 H% D" g% H
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.
if(accel_lim == 0){
accel_lim = 1;
}, D6 T6 G! O( ]3 d1 B3 r( Z' ~$ K$ Z: Q
// 使用限制条件我们可以计算出减速阶段步数. {- \/ o! s6 I
if(accel_lim <= max_s_lim){! _" r/ ?) A; s9 d3 t V
srd.decel_val = accel_lim - step;
}
else{
srd.decel_val = -(max_s_lim*accel/decel);
}# |* z) a7 m" f- Y3 d' f7 Y
// 当只剩下一步我们必须减速0 a, p, S3 ~2 K# p. b7 K
if(srd.decel_val == 0){
srd.decel_val = -1;# C. _" F: R3 q+ L( u) b: d
}
// 计算开始减速时的步数& Z$ V/ U5 L, F" ]
srd.decel_start = step + srd.decel_val;5 |9 e" o. n1 q( e( }+ E4 U7 z S4 D
. h% E# k! T# J9 |& V2 T
// 如果最大速度很慢,我们就不需要进行加速运动$ E* F* z& K7 G9 {; {
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;
srd.run_state = RUN;
}
else{
srd.run_state = ACCEL;
} - T( N s, G5 y
// 复位加速度计数值
srd.accel_count = 0;
}
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); // 设置定时器比较值
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_ENABLE); // 使能定时器通道
STEPMOTOR_OUTPUT_ENABLE();
}
1、机器人和工业驱动器" r( T' n0 R! \8 N9 |, Z4 p
2、纺织、缝纫机6 {6 I }/ z8 z/ R& Q
3、包装机械
4、工厂和实验室自动化
5、高速 3D 打印机
6、液体处理; J8 J% s2 D9 |8 Z/ H; J
7、医疗
8、办公自动化
9、有线闭路电视& b1 U( b8 e2 F& t5 t# ?$ T8 f5 D7 N
10、自动取款机、现金回收
11、泵和阀门
电机驱动主芯片采用TMC21602 B6 A- I: K2 |% e: J! f
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);, b0 q/ e6 r- Z5 J# `* Z5 q _: e
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;: \( C G5 p; E3 ~3 D
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14): p, w# a# Q0 [; T# f4 e
拨码开关ON:设置为高电平1,反之低电平0
细分设置:CFG1、CFG0
CFG1、CFG0: |* x; s% L K5 `
11:64细分
10:32细分* A+ i1 Z! y2 o j' r* V! h
01:16细分
00:8细分
运行电流设置:CFG4、CFG3、CFG2
CFG4、CFG3、CFG2:
111:IRUN=31; U, b6 ^6 y" h+ i6 m
110:IRUN=28
101:IRUN=26
100:IRUN=24
011:IRUN=222 K1 D5 d4 W* z8 y1 E
010:IRUN=20
001:IRUN=18
000:IRUN=16
Irms=Vfs/(IRUN/32)/(Rsense*1.414); ; s. C4 S; K5 j
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
CFG5:
1:SpreadCyle模式,低速、低平稳运行模式. z! c* Y3 S* [2 q" R$ y4 B% L
0:SpreadCyle模式,高速、高运动稳定模式
保持电流设置:CFG6
CFG6:
1:保持电流=运行电流/2
0:保持电流=运行电流
DIR+STEP接口模式位置控制(无需SPI接口)7 u/ s5 a9 p) J9 y
COM端:接24V或12V或5V3 E2 [* j: G0 x7 ^; O
DRV_ENN、STER、DIR:接集电极开路输出
为测试方便:5 H0 K8 _. l+ J; {" g) e2 k
COM端:接3.3V* Q; ]( ?- j# o% g1 y5 m
DRV_ENN:使能,接PB14' Q8 w$ _' v# r2 B. q
DIR:方向, PB15) R0 G' ~0 j4 M, X) ]; D
STEP:脉冲,PA8" U9 N: m4 ]( a; V; p1 b