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
/* Initialize all configured peripherals */5 D+ O& B7 o, V' }
MX_GPIO_Init();
MX_USART2_UART_Init();1 H+ d# x- x& x" @" K) K
MX_TIM1_Init();
STEPMOTOR_TIMx_Init(); /定时器输出初始化, ^: {, `5 V7 d y; h
/* USER CODE BEGIN 2 */
STEPMOTOR_OUTPUT_DISABLE(); //TMC2160禁止使能$ F3 j6 t. u, K) j
/* USER CODE END 2 */. T' b- g; v+ q" R9 T4 Y, M5 H* s
/* Infinite loop */4 S) B5 A" A% r2 l! p- k
/* USER CODE BEGIN WHILE */
while (1)# D: U+ X# g$ d& L# i9 u* r5 o/ ^' i
{
/* USER CODE END WHILE */( Z0 h3 \# [+ k5 V7 J
STEPMOTOR_AxisMoveRel(6400*-2, 5000 , 5000 , 1200); //控制TMC2160驱动步进电机反转2圈(32细分,1.8度则一圈需要6400个脉冲)
LedOnOff(); //LED闪烁处理# v2 g; L( j- [
STEPMOTOR_AxisMoveRel(6400*2, 5000 , 5000 , 1200); //控制TMC2160驱动步进电机反转2圈(32细分,1.8度则一圈需要6400个脉冲)
LedOnOff(); //LED闪烁处理, V8 H9 n; d6 m) P, O
/* USER CODE BEGIN 3 */
}
/**
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).
accel 加速度,实际值为accel*0.1*rad/sec^2
decel 减速度,实际值为decel*0.1*rad/sec^23 v+ s7 V' w X+ [
speed 最大速度,实际值为speed*0.1*rad/sec
* 返 回 值: 无
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且/ h4 M) u0 }1 @6 R! l+ m" m& j
* 速度很慢,那还没达到最大速度就要开始减速- b: B' k A3 V7 G, g3 a
*/
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)" g; J3 _9 v1 H
{
__IO uint16_t tim_count;* k d" l( T* \8 ]3 s
// 达到最大速度时的步数
__IO uint32_t max_s_lim;' f$ R$ g/ m0 X4 f7 h6 Y. G
// 必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t accel_lim;
if(step < 0) // 步数为负数1 N' a" W0 H" b) W9 B
{" q& a, ]& G2 |: [, A2 N! A2 K
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值 U- D0 D# k( G
}2 r% v# i8 {9 x* \
else4 i- [1 e+ S3 Q& p
{
srd.dir = CW; // 顺时针方向旋转
STEPMOTOR_DIR_FORWARD();+ B! B7 u" A) Y7 c5 N
}- Z4 Q5 W- q/ z+ `- t
9 g. x- R& T8 f; n2 |, Z; V2 X( ]
if(step == 1) // 步数为1
{& T# E7 \3 ~, c5 l; [4 \
srd.accel_count = -1; // 只移动一步
srd.run_state = DECEL; // 减速状态.8 X; Q9 e. L A
srd.step_delay = 1000; // 短延时 , K% Y- q; u& n, }: Q. Y
}, Z0 \! N+ V% ]* { s/ V8 b1 L* y
else if(step != 0) // 如果目标运动步数不为06 f% P! q6 H& h% b
{
// 我们的驱动器用户手册有详细的计算及推导过程
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。( N$ {& D, q( I" d; w* c, i
// min_delay = (alpha / tt)/ w% m; R3 r0 H' t
srd.min_delay = (int32_t)(A_T_x10/speed);
$ S: ^, L# E. A9 ?* {$ c
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^24 Y/ G: |* N5 Y
// step_delay = 1/tt * sqrt(2*alpha/accel): J! T5 {( K% H
// step_delay = ( tfreq*0.676/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/100: I7 C' X4 W; b: P& _0 z0 A3 B
srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);- J% m/ Y5 E* o) v. Y
+ g5 E2 M4 x7 U# u# {; L
// 计算多少步之后达到最大速度的限制5 g& ^: C3 @# e7 N5 p! S9 s
// max_s_lim = speed^2 / (2*alpha*accel); ^$ g- x; M3 q5 H) }8 n8 D
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度0 L/ I7 }" Q7 u# E
if(max_s_lim == 0){8 U4 o& c8 z5 q! [7 Z5 Y& R
max_s_lim = 1;
}& O: V% [& L: e y! {5 x. U
// n1 = (n1+n2)decel / (accel + decel)6 U/ E1 N7 g$ g1 F% b; R/ L$ z7 t
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.: `, V- q2 b3 A9 Y# q s3 g4 |
if(accel_lim == 0){
accel_lim = 1;% ?" X6 d# @) ~, `0 ?: ~8 d5 b9 v! d
}. h& m" D# K# A9 f. L
7 w0 C# x9 D4 E @# A. i
// 使用限制条件我们可以计算出减速阶段步数" K' z I6 y! z; X# M& s
if(accel_lim <= max_s_lim){
srd.decel_val = accel_lim - step;
}
else{
srd.decel_val = -(max_s_lim*accel/decel);" M0 s6 Z1 Q: r! D
}" x2 }- }- L' b8 b" n
// 当只剩下一步我们必须减速
if(srd.decel_val == 0){! U% `4 t, w3 ~. E4 Z
srd.decel_val = -1;
}! M2 ]0 h4 y8 o- w. L+ P" |
// 计算开始减速时的步数3 r/ Q$ y) y0 n7 B5 E
srd.decel_start = step + srd.decel_val;- k6 `/ r, }( Y7 s6 @" y H
// 如果最大速度很慢,我们就不需要进行加速运动
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;
srd.run_state = RUN; R) o: T' Q. C" S) {6 s- o4 i1 u
}1 P" o' W" X/ e- S4 R& i
else{0 p5 v6 {2 P# H- v
srd.run_state = ACCEL;6 i0 v7 E6 t6 i: y: e7 p& ]
} 2 N8 Q5 v/ e: H2 u
// 复位加速度计数值
srd.accel_count = 0;
}
MotionStatus = 1; // 电机为运动状态1 o0 D' O# h! d( K. }! l
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);. u$ q8 c& l2 s) d, V' A
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay); // 设置定时器比较值: Z: i7 s8 N% D2 G S. ]$ B! S" _: ?
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_ENABLE); // 使能定时器通道 " p T2 M; q, w/ H
STEPMOTOR_OUTPUT_ENABLE();
}
/**% u; W# s1 |. s; X8 G
* 函数功能: 定时器中断服务函数
* 输入参数: 无' ?3 j7 f% B; z+ A' a1 k$ t" {2 Q
* 返 回 值: 无1 V* }! a- E, W I, m
* 说 明: 实现加减速过程+ C W1 E% I$ d, K# P
*/0 G; z# i c: ^+ g; O
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理& l6 F% S+ q- C
{
__IO uint16_t tim_count=0;* @$ R7 y$ T3 @2 N5 Y
// 保存新(下)一个延时周期3 s: L6 v% g+ z& {9 y8 ?) X3 D" c( E
uint16_t new_step_delay=0;
// 加速过程中最后一次延时(脉冲周期)., Z4 b; H& Q. I" s! o1 J
__IO static uint16_t last_accel_delay=0;1 ^0 c. U1 ^7 u) j' @/ C7 f! ]7 O
// 总移动步数计数器
__IO static uint32_t step_count = 0;
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t i=0;0 y$ \% X6 i4 W6 s
5 T4 W* H5 r2 k% K
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)
{4 n4 s7 ~3 ~0 W4 x
// 清楚定时器中断& K+ l) X* m" F5 J! g% Y
__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);
* g% ]2 ^7 R6 F8 H9 G* Z
i++; // 定时器中断次数计数值
if(i==2) // 2次,说明已经输出一个完整脉冲
{
i=0; // 清零定时器中断次数计数值
switch(srd.run_state) // 加减速曲线阶段: l# _7 v4 S8 C
{7 `( i- x/ U7 C- F% M1 ~
case STOP:1 q' ^" I M$ o# Y
step_count = 0; // 清零步数计数器
rest = 0; // 清零余值
// 关闭通道7 n- n; A+ w( p% _+ B# \
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);% p; Z0 k6 L3 A2 l' x
STEPMOTOR_OUTPUT_DISABLE();
MotionStatus = 0; // 电机为停止状态 % S0 M% `: m* h. `5 e4 Q
break;
: \/ s, U0 }/ _& e* i' r6 E
case ACCEL:2 c( t% W4 h& ]/ V
step_count++; // 步数加14 |6 o* z8 }2 g. U: E; ^
if(srd.dir==CW)
{ 7 [% H- ^6 V* Q& D
step_position++; // 绝对位置加1* T( n1 B/ I* d. z, }: T/ d4 w
}7 L' D" d+ q; A2 H
else2 U7 j% R) r% l+ v9 v
{
step_position--; // 绝对位置减1; Q* o: T! l, H* y; Q) }5 n+ ~
}
srd.accel_count++; // 加速计数值加1. i8 c2 |' j" I7 R; o1 G+ E
new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)% ^' T- D) Q8 X
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
if(step_count >= srd.decel_start)// 检查是够应该开始减速$ M% W0 G+ }* D
{
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值2 P4 W4 u1 @) s- i; }0 U
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}. l) a% [/ m) j$ N0 n
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{( I- i$ t: L% ~3 s: E5 g; [( S8 l
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
rest = 0; // 清零余值7 `% ?1 i" ?6 k _6 W
srd.run_state = RUN; // 设置为匀速运行状态, E0 u; E9 W* T+ e! C5 R: k
}
break;
; c8 C/ L: R7 t9 {
case RUN:6 W, Q. p' W; u) y8 s
step_count++; // 步数加1
if(srd.dir==CW)
{
step_position++; // 绝对位置加1" E- ?/ ?. C3 S6 g1 O% H
}
else
{. \+ l1 D/ J/ }: n6 ~. O
step_position--; // 绝对位置减1% X* _! E1 J1 s3 Q6 a
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
if(step_count >= srd.decel_start) // 需要开始减速
{
srd.accel_count = srd.decel_val; // 减速步数做为加速计数值0 F5 x8 ^8 r2 p6 s2 G+ v
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
srd.run_state = DECEL; // 状态改变为减速# V. A7 O( \; ? V/ I) d: m( W7 G
}
break;
case DECEL:2 x2 y# u7 W9 K/ o0 U, p' O' }
step_count++; // 步数加1
if(srd.dir==CW)
{
step_position++; // 绝对位置加1
}! ?. ^6 t: k N e3 V' y6 T; ]
else
{! B4 E+ [+ v- P4 h; b3 F) ^+ X W
step_position--; // 绝对位置减1! d5 I9 G8 M, g; ~' A9 E2 R" c. e
}
srd.accel_count++;! H# u4 y4 ?5 ^3 q( J" g# A) g* o
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);// 计算余数,下次计算补上余数,减少误差& n: y4 b4 k9 U# f
: X1 P. _5 r% Z C
//检查是否为最后一步
if(srd.accel_count >= 0)
{
srd.run_state = STOP;, T) y& J# ^8 H. W
}
break;4 h' H# g$ K: T1 s3 U* V$ k
} B" U! F7 s B) \. }
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}
}
}
如果确实需要原理图和PCB的用户,请联系我们的客服或管理员私下索取谢谢!+ f9 z2 Z- }$ r Z
技术群:171897584
公众号:游名开源
是的,参考他们的,有说明:写着参考硬石的