小马哥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
/**
* 函数功能: 定时器中断服务函数
* 输入参数: 无/ |6 G: G ?% ^; i% n- _
* 返 回 值: 无: p/ ]5 E( H, _, e9 S8 S
* 说 明: 实现加减速过程( x1 N3 q. `7 `! t8 ?9 ?
*/4 |! C( \1 R8 R. s- r
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{ 5 \6 V0 D+ Z: R8 g- r& L
__IO uint16_t tim_count=0;/ }; {7 T' J$ J9 l- T9 @
// 保存新(下)一个延时周期+ `9 S3 E. v$ W$ u& `
uint16_t new_step_delay=0; I0 B& U2 N5 b
// 加速过程中最后一次延时(脉冲周期)./ u6 a/ T$ N% i3 L8 c1 F
__IO static uint16_t last_accel_delay=0;
// 总移动步数计数器
__IO static uint32_t step_count = 0;
// 记录new_step_delay中的余数,提高下一步计算的精度. E3 p# r! t* W6 y0 b a2 f9 ^
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t i=0;* A8 u. T( e; T0 r) l
5 r4 F) @; |/ Y/ f. u
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)/ V% P" U: v/ i+ v: ?" F" G& Z
{
// 清楚定时器中断0 X1 ~' W) E% c! p! U8 m, c
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);2 d/ T3 J( J2 e# `- {
i++; // 定时器中断次数计数值 C' H1 x5 m' \+ \% _! B1 v3 x
if(i==2) // 2次,说明已经输出一个完整脉冲/ [7 A+ G5 ?% N
{
i=0; // 清零定时器中断次数计数值. G9 w( x$ i" A* s0 l5 O
switch(srd.run_state) // 加减速曲线阶段
{
case STOP:
step_count = 0; // 清零步数计数器
rest = 0; // 清零余值, X V' ~' m) H! H4 k U! ~
// 关闭通道
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE); * b4 L, l' q6 ^
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);
STEPMOTOR_OUTPUT_DISABLE();
MotionStatus = 0; // 电机为停止状态
break;+ h% h2 z+ ~$ U* F
; `. d2 p4 N- I# U
case ACCEL:5 ]3 P R& V7 w: r
step_count++; // 步数加1# Y% O q0 K+ Y' P
if(srd.dir==CW)* D8 w1 C. c% n
{ $ d3 w% C' R c1 T
step_position++; // 绝对位置加1' r+ f7 @& Q7 U4 a$ D. G
}3 A8 k% T, R J2 A' R, B# N% w
else6 H: v! h4 }- k
{
step_position--; // 绝对位置减1
} Z9 S5 E! T8 ?* B9 r6 W
srd.accel_count++; // 加速计数值加1, X, e9 l* t& d" l
new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)( x( _- `5 Q% K1 a
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差6 ^* H6 Y; a, i/ T4 C
if(step_count >= srd.decel_start)// 检查是够应该开始减速
{. ~( R4 L3 k: m9 n9 J8 E3 ?1 `
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值$ e1 y: F1 p7 O \0 f
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}* v! O( F: Z& g/ ~6 _6 U
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度- N D" ?& p- X# n! |
{
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)" Y$ w* K V1 }
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)* ?# @4 e; D7 @( y, z2 Z/ Z
rest = 0; // 清零余值, a5 @4 [6 {& n7 s
srd.run_state = RUN; // 设置为匀速运行状态0 v2 J" k- d$ x8 ~- @2 ^' }
}! N$ B) w; @2 _) ^+ c
break;
case RUN:- F4 A$ c' S: |4 W
step_count++; // 步数加1
if(srd.dir==CW)# S ^8 w0 F- }( t4 K1 s8 ~& C
{
step_position++; // 绝对位置加1. p$ K& ]- H4 ~& ^5 u
}5 F" j/ t' s2 Z) F/ R' P
else
{
step_position--; // 绝对位置减1
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
if(step_count >= srd.decel_start) // 需要开始减速
{
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值% d4 K& f9 J6 B5 y- ?% D
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)5 e9 R8 H! F3 e" o* [% F- T2 @
srd.run_state = DECEL; // 状态改变为减速: i$ C f$ Z2 ]
}9 I1 D- ?* U; O2 u5 J
break;
: h, O5 x2 T* h
case DECEL:% v# F: {% t4 T1 e V
step_count++; // 步数加1$ {% H( n( P: @* z# v& c5 j3 }
if(srd.dir==CW)% _/ R: i: g( V
{
step_position++; // 绝对位置加1
}
else
{5 d# J8 W4 O! x& C3 z# X' D
step_position--; // 绝对位置减1, ]+ J% A3 A O& l1 E" C+ e3 g
}" u/ O+ @; z8 C# @" \! M
srd.accel_count++; x( J4 M2 ? ?! A
new_step_delay = srd.step_delay - (((2 * srd.step_delay) + rest)/(4 * srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔): ^$ U( a. x" ]7 f% |5 d! T
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差$ T& n# ?+ l5 V
//检查是否为最后一步
if(srd.accel_count >= 0)
{1 h/ b* q- @# `2 ]: \( I
srd.run_state = STOP;
}8 G5 ^6 C$ X" i0 {) u. L, c
break;9 D5 b" @" Y& i8 N# N
}
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值% N- _& K2 x+ e# B5 k, C, f
}
}
}) Q/ q! _3 y6 C3 b6 I
/**
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).
accel 加速度,实际值为accel*0.1*rad/sec^2
decel 减速度,实际值为decel*0.1*rad/sec^23 s6 _( I' i; J( z4 \4 F
speed 最大速度,实际值为speed*0.1*rad/sec
* 返 回 值: 无6 P7 U' _: j7 E( V+ C
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且6 S/ \' [- z- s8 Q
* 速度很慢,那还没达到最大速度就要开始减速
*/' J0 I1 h. ?( _; g: `# x
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{
__IO uint16_t tim_count;
// 达到最大速度时的步数
__IO uint32_t max_s_lim;( p% J( {& L7 T4 H4 o6 m* o8 @5 F
// 必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t accel_lim;9 s: `; Q2 I5 c& @
5 l4 [. ]7 h3 l' V& n7 z
if(step < 0) // 步数为负数
{
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值
}9 [3 A6 w d2 X _
else' K+ \0 y" ~7 S' `% i7 m( `
{7 e& Y! k& \3 ]
srd.dir = CW; // 顺时针方向旋转9 g" k- E# K" j; | A$ R5 Y1 k
STEPMOTOR_DIR_FORWARD();) w$ n# f2 M! g3 i( |' T
}7 a N9 q& O1 Z) D
if(step == 1) // 步数为11 s' p& W/ F' Z3 g7 H7 q0 I9 E M
{7 }5 Z% Q: l7 [. a! M
srd.accel_count = -1; // 只移动一步& y) r, S- j2 k. o3 G
srd.run_state = DECEL; // 减速状态.# i9 r% A( g7 j: K9 v1 H$ D: g
srd.step_delay = 1000; // 短延时
}5 R7 q! [+ I& S9 p2 h; K8 M; g
else if(step != 0) // 如果目标运动步数不为08 S6 t [% V7 e8 x
{ m, [# I* Y6 _/ i) o# ]
// 我们的驱动器用户手册有详细的计算及推导过程
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w9 r4 t, i& ?. q, b
srd.min_delay = (int32_t)(A_T_x10/speed);' V2 S; s6 @ L7 X! F) J
# }: G1 u' K' B f6 Y9 }
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^20 R! L& z3 C/ K9 q2 E
// 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);9 j6 c5 z. y$ u5 N2 n
6 A5 O' U4 O1 q
// 计算多少步之后达到最大速度的限制* r" b" S) B0 r$ E9 C
// max_s_lim = speed^2 / (2*alpha*accel)# v8 T% \- W" l# Y6 W7 U
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为01 w) }) V! Z3 {. ~3 X$ w t& Y
// 但实际我们必须移动至少一步才能达到想要的速度1 \% z, Q* O# x' p5 \
if(max_s_lim == 0){
max_s_lim = 1;. M5 ]! B* d, n7 P6 Y" i+ _9 i$ r
}
// n1 = (n1+n2)decel / (accel + decel). j0 q% P& ^' t$ r, I( k
accel_lim = (uint32_t)(step*decel/(accel+decel));; V6 b$ M$ r1 e$ Q; \) B5 K* d5 H. `* L
// 我们必须加速至少1步才能才能开始减速.
if(accel_lim == 0){* k5 R$ g2 I. o7 L ^
accel_lim = 1;$ S2 }5 Y" ]0 u6 C+ d
}
, Q$ A: y6 X& O6 \
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){
srd.decel_val = accel_lim - step;/ R: ]) p2 P5 O; ^3 q3 v( g3 B
}3 @; K! R' Y, c* F" q/ f$ Y |: b- V
else{
srd.decel_val = -(max_s_lim*accel/decel);+ q& q8 i% \- e3 c( Z3 e: f! {
}; p" E7 u0 s' j2 o x8 F6 h9 C+ U1 |" \
// 当只剩下一步我们必须减速
if(srd.decel_val == 0){
srd.decel_val = -1;
}
: D' O7 h: F, H+ G
// 计算开始减速时的步数1 r8 K) s: C# ?$ W, L- N! c
srd.decel_start = step + srd.decel_val;0 i' N: f6 `* y: @% y/ D+ [
// 如果最大速度很慢,我们就不需要进行加速运动
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;- f4 T U6 P; j ^
srd.run_state = RUN;2 K, t7 G! U7 I7 D* o; u# k4 i
}
else{
srd.run_state = ACCEL;8 h/ X, }& j2 u; k& Y4 j6 j; E
} j+ ~. p! A- k. h1 [
// 复位加速度计数值
srd.accel_count = 0;! _! V0 D9 M" j7 q" Z ?( w A/ M
}# O% n' o2 D" r$ S7 p
MotionStatus = 1; // 电机为运动状态9 J; o1 b$ Q( H# @
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);' P& V3 x* [: ]8 x
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay); // 设置定时器比较值& d* V- U8 g/ X9 _* n
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_ENABLE); // 使能定时器通道
STEPMOTOR_OUTPUT_ENABLE();
}+ {, ^& y8 u8 A) ]3 `
1、机器人和工业驱动器* ]8 f, @% H( P/ m2 I# a/ t
2、纺织、缝纫机
3、包装机械7 b5 E' R3 r0 H: T% |
4、工厂和实验室自动化
5、高速 3D 打印机
6、液体处理' r; y0 {6 P0 e" U& I% |" s7 C
7、医疗4 V" d: U4 R4 O% m4 M
8、办公自动化9 U: j* K1 q% n6 r6 [9 f
9、有线闭路电视
10、自动取款机、现金回收
11、泵和阀门
电机驱动主芯片采用TMC2160, m3 y: n. Z( B: M2 ?* r5 b2 F
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;5 ?" _4 }( d$ Y0 I' q; \8 l; t6 G0 N
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)0 h) t* [; u7 ^# w7 ?
, U& a5 ^7 K. Y+ j# V3 T* e, m
拨码开关ON:设置为高电平1,反之低电平0( ^) |) I2 O8 }! F4 E
细分设置:CFG1、CFG06 L& l) M- y j
CFG1、CFG0:
11:64细分: h2 @# p4 T. V. f
10:32细分: b/ K- W1 `1 N" @ F7 G; Z
01:16细分4 a% L- a7 n ?
00:8细分1 _: o! B! S& }, _3 @/ `
运行电流设置:CFG4、CFG3、CFG2/ _+ t2 M3 h8 y9 W) ^
CFG4、CFG3、CFG2:, V3 P# z% \7 c6 q6 w
111:IRUN=31
110:IRUN=28
101:IRUN=26
100:IRUN=24
011:IRUN=228 Y' B" J K3 |0 x# e" g
010:IRUN=20
001:IRUN=18, x3 ^. U% Q5 B% t) J
000:IRUN=16# m l0 u7 M0 l
Irms=Vfs/(IRUN/32)/(Rsense*1.414);
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
CFG5:
1:SpreadCyle模式,低速、低平稳运行模式0 R* ~4 |* h6 ?8 ?% s
0:SpreadCyle模式,高速、高运动稳定模式
保持电流设置:CFG6
CFG6:) N, `' _ J3 n2 K4 P$ [
1:保持电流=运行电流/26 s* [2 B# d5 [7 W/ O
0:保持电流=运行电流
DIR+STEP接口模式位置控制(无需SPI接口)) a- P3 `0 k5 I9 U. s
COM端:接24V或12V或5V
DRV_ENN、STER、DIR:接集电极开路输出 \# S% l: V$ L4 A q
为测试方便:
COM端:接3.3V
DRV_ENN:使能,接PB14, N% S y* P! P l( |, r
DIR:方向, PB15
STEP:脉冲,PA86 N; i9 _+ t: } B* } V4 a