
STM32ADC过采样及几种ADC采样的处理方法
STM32的启动模式配置与应用
小马哥STM32F103开源小四轴RoboFly全部资料大放送
STM32固件库分享,超全系列整理
STM32F10xxx 正交编码器接口应用笔记 及源代码
分享一个STM32F103的硬件IIC代码库,完美解决IIC问题!
OpenBLT移植到STM32F103战舰开发板上适用于所有STM32F103系列的Bootloader
MultiButton移植到STM32F103战舰开发板
UDS诊断服务
使用Nano板验证驱动SPI串口屏的颜色显示
/**
* 函数功能: 定时器中断服务函数
* 输入参数: 无. K% E# i4 \4 h; v5 Y9 Z
* 返 回 值: 无
* 说 明: 实现加减速过程
*/
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{ . ?, b3 u& F' K6 O
__IO uint16_t tim_count=0;! i* V% f; q k/ X, v- N c! V. x8 X
// 保存新(下)一个延时周期" X+ F. b( w5 _- A' l6 u2 l( S
uint16_t new_step_delay=0;
// 加速过程中最后一次延时(脉冲周期).
__IO static uint16_t last_accel_delay=0;
// 总移动步数计数器
__IO static uint32_t step_count = 0;
// 记录new_step_delay中的余数,提高下一步计算的精度% }( i7 J; X" S0 S; l' g
__IO static int32_t rest = 0;. k! T F; z0 e
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲5 \% a. {* I( k: D/ r
__IO static uint8_t i=0;: u o% F( m6 ?6 A9 f
; L3 I$ ?- Y" H" A, }4 c6 G+ q
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)+ p p0 A4 K& h4 z
{
// 清楚定时器中断; p" n( [& ^8 x- |+ c
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);- J% \ X z2 B! q P: n s. ]- F" M
' ~+ x" M5 J0 h
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);' D J! c+ B) i. v5 W
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);
i++; // 定时器中断次数计数值
if(i==2) // 2次,说明已经输出一个完整脉冲6 T0 t* O: P0 } }( z. _0 H
{! b) L6 W( D1 g# D' L
i=0; // 清零定时器中断次数计数值' L4 [# b6 A6 R+ ?- m+ N. X
switch(srd.run_state) // 加减速曲线阶段! s, T* `6 R+ O% m; s
{
case STOP:1 `. c; E3 Y% ^3 ~) F6 d/ `
step_count = 0; // 清零步数计数器; h, s- h2 [- Y
rest = 0; // 清零余值
// 关闭通道( r* [$ _) N2 k, H% E
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE); 6 n" `% s( @- }* b
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);
STEPMOTOR_OUTPUT_DISABLE();' [* W/ U# |- ?) x# S2 t
MotionStatus = 0; // 电机为停止状态
break;
case ACCEL:
step_count++; // 步数加1
if(srd.dir==CW)
{ 1 w9 K( ~1 u5 u9 s0 s6 Q
step_position++; // 绝对位置加1; i3 J5 k3 p1 k. R6 Y& l
}$ F. }' _5 p2 g. _* j
else
{* S$ l+ x: d/ j+ w* B
step_position--; // 绝对位置减1
}
srd.accel_count++; // 加速计数值加1
new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)1 t; Q: c' q2 n7 [
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
if(step_count >= srd.decel_start)// 检查是够应该开始减速% {, G7 ~# w; z% `* Z5 Q8 G$ Z
{& S9 @9 \ I4 N' b( ~9 W1 A6 p/ I6 H
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值- H6 d% V5 f- P; h5 o
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}5 N/ x- H$ h) [' o" z% P0 [' q
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{5 V6 ^- n! } c' e% _' G
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)! N4 K: n; W# B( I# m- r
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
rest = 0; // 清零余值% x- m% d3 `1 x, V( n
srd.run_state = RUN; // 设置为匀速运行状态, ], b2 K, f1 m* F% a1 M
}
break;/ s; h* X M* j( L" A# t" i6 [
8 J2 B' v9 w" y: j3 p
case RUN: P: F; j# `8 K% v0 q. z
step_count++; // 步数加1% ]* J7 W$ A7 `5 `. ~
if(srd.dir==CW)/ E6 _2 |3 l' ^9 A
{
step_position++; // 绝对位置加1
}; j ~) p3 s1 N1 X
else8 S& A% g" G$ E- C9 R; d: V
{
step_position--; // 绝对位置减1
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)$ ?+ b. ~9 g( y* \2 x8 A* F' E) [
if(step_count >= srd.decel_start) // 需要开始减速7 N3 B' H w w: k
{2 }) b, g W0 K4 g+ V* X# }- n x
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值) @+ Q; P$ C3 E7 m% m8 {7 R
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
srd.run_state = DECEL; // 状态改变为减速
}
break;
case DECEL:% o! k+ U1 V6 \ M4 X
step_count++; // 步数加1
if(srd.dir==CW) ^" \) D1 L7 a$ l \+ D
{
step_position++; // 绝对位置加12 R+ _; B! [9 D: c
}3 I5 \; @! }+ O" P( |
else
{; S+ q- E; b J( K5 O z
step_position--; // 绝对位置减1
}
srd.accel_count++;6 m, ~6 P- f p8 D& l+ J
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);// 计算余数,下次计算补上余数,减少误差
! ?4 B( ]8 ~6 Q. q& ~+ ~
//检查是否为最后一步 p1 ]( E5 ^) `" Q/ e2 c' e
if(srd.accel_count >= 0)
{- p; p+ \5 M2 q, f: y% p
srd.run_state = STOP;
}4 G& {/ T( z: h; `' B
break;
} 1 P& e& q; L& {6 C: D
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}
}
}
/**+ [6 U2 j9 U$ C8 u6 W$ k( _
* 函数功能: 相对位置运动:运动给定的步数0 @( E+ Y, U4 ?/ H t7 P
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).
accel 加速度,实际值为accel*0.1*rad/sec^2
decel 减速度,实际值为decel*0.1*rad/sec^2
speed 最大速度,实际值为speed*0.1*rad/sec
* 返 回 值: 无
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始. r9 N1 l4 }4 S8 X. ?$ J
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且% d1 S k& ^( c4 Z9 i- y
* 速度很慢,那还没达到最大速度就要开始减速' [5 f3 y- p% t
*/
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)4 W* f! \8 ~* v% [+ o1 m4 m$ a2 o# ~
{
__IO uint16_t tim_count;; {" J, J5 _' U/ {0 V& d
// 达到最大速度时的步数4 H; L- U8 s& {0 X) {
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)9 M# ~8 N7 B' m$ E, f& F0 v" |' i
__IO uint32_t accel_lim;0 T, [7 [0 T1 U, j9 N3 P
if(step < 0) // 步数为负数- Y; P2 P' A( s/ {" V( ?$ b
{
srd.dir = CCW; // 逆时针方向旋转: C9 T# Q" A& G9 O. T* L( `/ F
STEPMOTOR_DIR_REVERSAL();, t+ \% `: h( E* n/ D5 M
step =-step; // 获取步数绝对值7 i( F9 o. `1 }% P
}/ M7 M5 W' `9 h7 ?
else
{" I3 L1 N) L! H8 m5 z3 [
srd.dir = CW; // 顺时针方向旋转5 ]) ^5 J1 u5 t+ A% b C
STEPMOTOR_DIR_FORWARD();
}8 p# P* D$ i% [+ m6 k, ?! m
! O0 A A0 y4 j8 t0 [; P2 Y
if(step == 1) // 步数为1
{
srd.accel_count = -1; // 只移动一步, p5 z8 |3 g+ s+ t0 ]2 e
srd.run_state = DECEL; // 减速状态.
srd.step_delay = 1000; // 短延时 $ T! l2 C& N0 s) K$ m n
}2 R$ Z1 S0 N& A0 G1 }, D" g
else if(step != 0) // 如果目标运动步数不为0; j' w5 X* F7 x- r- ]
{
// 我们的驱动器用户手册有详细的计算及推导过程: p! I6 C. ?9 R& U9 [
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w
srd.min_delay = (int32_t)(A_T_x10/speed);
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^2
// step_delay = 1/tt * sqrt(2*alpha/accel)) l! d/ Q! m' Y) _- x
// 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);% x2 r' n) v( M6 Q" P( Q
// 计算多少步之后达到最大速度的限制( m; z' {! r) y2 G4 m! j
// max_s_lim = speed^2 / (2*alpha*accel)
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));* F" q$ S, Q+ u* B! e7 \+ q" Z
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度7 U q! g& m t5 Q' z/ }2 l
if(max_s_lim == 0){
max_s_lim = 1;
}4 d$ ~) v1 @# e# G. u) T: z
// n1 = (n1+n2)decel / (accel + decel)
accel_lim = (uint32_t)(step*decel/(accel+decel));, Z) Q& u% J+ ~. @7 r! _
// 我们必须加速至少1步才能才能开始减速.
if(accel_lim == 0){
accel_lim = 1;9 c( E" g1 q D
}
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){
srd.decel_val = accel_lim - step;
}
else{
srd.decel_val = -(max_s_lim*accel/decel);
}: F0 v! M8 h5 a% n
// 当只剩下一步我们必须减速1 t L8 Q2 l6 f% W% w
if(srd.decel_val == 0){
srd.decel_val = -1;
}: e3 S8 c) C. ^1 B, u1 B
// 计算开始减速时的步数
srd.decel_start = step + srd.decel_val;5 o, u% l8 ^# C& z& K ~
// 如果最大速度很慢,我们就不需要进行加速运动 `' I) |! T" y3 ~/ O) h/ H! N M; C
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;! }2 _6 Q. P+ _/ `5 r
srd.run_state = RUN;
}
else{$ w+ Q7 x! T* V; @; R5 V
srd.run_state = ACCEL;
} / G! b2 m* |3 U! X! w+ R
// 复位加速度计数值
srd.accel_count = 0;, i: ^' _4 c7 [/ X/ e7 u
}0 Q1 p* \) x3 @5 a H; R/ q7 u
MotionStatus = 1; // 电机为运动状态; }! Y( h) |& Z
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();% {0 r' j. @4 g- d, q+ {
}
1、机器人和工业驱动器
2、纺织、缝纫机
3、包装机械! |& z- A9 w( c- K: e
4、工厂和实验室自动化) l; i9 V& S! a1 q+ ~
5、高速 3D 打印机
6、液体处理
7、医疗1 Q7 V& ^2 H4 n* l' o; ]4 h
8、办公自动化" @9 T d2 S. C8 G* V% I4 W7 U7 x1 A
9、有线闭路电视; b! Q5 O6 T* S0 V0 t2 @3 o
10、自动取款机、现金回收
11、泵和阀门
电机驱动主芯片采用TMC2160
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);: D0 P4 ]8 I8 Q' J
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;
& Q$ b, y7 A& e3 ^: }; y' r
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)( f ^. p- X: q% s
9 J* t. [- q0 J) G3 D( h
拨码开关ON:设置为高电平1,反之低电平06 i) ]2 u1 E6 \7 @1 e" m
细分设置:CFG1、CFG0
CFG1、CFG0:) ]7 X5 v0 T6 S' |3 k% @- b. J
11:64细分; H x( _! G' e# Y, t2 s3 B
10:32细分; J6 B1 G; ]5 b: ~, t
01:16细分* ]+ w6 ~- d0 z' m, g4 ~ j
00:8细分* J' f: T5 o/ p
运行电流设置:CFG4、CFG3、CFG2% F& M* D5 P+ b4 a7 f8 T
CFG4、CFG3、CFG2:# e! f1 e1 u. A c# s" t
111:IRUN=318 e! p/ I7 S, Y/ @+ n c
110:IRUN=28, a9 ~7 F8 D: h( V
101:IRUN=26, W- K8 O9 E8 n' V0 v4 _$ U3 o( A
100:IRUN=246 k( `6 A& Z; `1 t0 W
011:IRUN=22
010:IRUN=20- ?. Q+ E( ]$ g0 H
001:IRUN=18' c2 J0 z7 M0 B) S1 s6 G
000:IRUN=16, }; w: c) p1 q2 k4 k& ^" P
Irms=Vfs/(IRUN/32)/(Rsense*1.414);
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
CFG5: F: }- T& D: J- k) u2 j4 M# }, `
1:SpreadCyle模式,低速、低平稳运行模式4 k' V0 f' \9 g7 c# ~" Q8 l" J
0:SpreadCyle模式,高速、高运动稳定模式3 H1 F, C6 D4 w( E# w% K( s
保持电流设置:CFG6
CFG6:- E( X$ y; q7 x# y5 s$ B( E
1:保持电流=运行电流/2
0:保持电流=运行电流
DIR+STEP接口模式位置控制(无需SPI接口)* A$ z! c8 G: z
COM端:接24V或12V或5V
DRV_ENN、STER、DIR:接集电极开路输出6 R; T4 \% D, F- g) T2 a! H
为测试方便:
COM端:接3.3V! P4 r# ?' O+ }1 l$ ~# K0 e- z
DRV_ENN:使能,接PB14
DIR:方向, PB15! I# i4 }6 C: ^
STEP:脉冲,PA8