8 }3 ^6 \% c. G1 f0 _
项目需求 在制作一个使用全向轮的机器人底盘,对于全向轮,电机的精度是影响效果的重要因素。所以使用了步进电机,使用步进电机的优点是可以不使用编码器,开环控制即可达到高精度的效果。 4 C; i% E: `2 ^" i5 B9 G8 ]+ n
调整占空比或者调整周期 众所周知,PWM有两个重要参数,周期与占空比。 步进电机的运动方式是,每收到一个脉冲,就旋转指定的角度。因此影响电机速度的唯一参数就是PWM的频率。以下附图两张来说明调整占空比与调整周期的区别。 9 n* O, s$ C ^3 F2 U0 ?* d$ a
周期固定,调整占空比
' p5 t( s, D7 _2 \
! w7 a+ {+ z O% V4 e上图中有4个PWM,它们的周期是一样的,不同之处是拥有从80%至20%的占空比。可以看出,无论占空比为多少,在1s内,它们产生的高电平的数量是一样的,即无论占空比为多少,PWM的频率都一致。因此也就无法调整步进电机的速度。因为步进电机的速度仅与PWM的频率有关。 ; y' q$ D4 a5 B! J
占空比固定,调整周期
1 U2 t4 F" s" R/ z9 {* ~) r 7 |: R3 P3 D; d* N S# \# R$ ^
上图中有4个PWM,它们的占空比都固定为50%,却拥有不同的周期。可以看出,即使占空比固定,只要动态调整周期,PWM就能在相同时间内产生数量不同的脉冲。因此,固定占空比,动态调整PWM周期,即可达到控制步进电机速度的效果。 * J, C$ ~# Z' K4 v4 O( j
基于STM32的实现 在STM32F1中,定时器具有PWM模式,可以用来产生PWM。相关文章:STM32中PWM的配置与应用详解。但是,STM32的PWM模式,只要确定了时基单元(即确定了PWM周期),改变输出比较寄存器,仅可改变PWM的占空比。 若需要改变PWM周期,需不停地改变定时器的时基单元。但时基单元与硬件相关,不适合频繁变更。因此,步进电机的调速,不适合使用STM32下定时器的PWM模式来控制。 在多方查找资料后,确定了一种利用输出比较精确控制PWM周期的方式。 8 m0 T1 n+ f' U# o+ j
利用输出比较产生频率可变的PWM 利用输出比较产生频率可变的PWM,原理简单介绍如下: 首先配置定时器时基单元,确定脉冲最小长度单位CK。 然后开启定时器的输出比较,设置模式为翻转模式,并开启输出比较中断。 将定时器内计数器CNT当前值,加上脉冲长度X(单位为CK),写入输出比较寄存器。 在X个CK后,将会触发输出比较中断。同时电平翻转。 在中断中再次将当前计数器CNT的值,加上脉冲长度X,写入输出比较寄存器。 在X个CK后,将会触发输出比较中断。同时电平翻转。 在中断中再次将当前计数器CNT的值,加上脉冲长度X,写入输出比较寄存器。 如此往复…… 以此即可得到一个占空比为50%,周期为2X个CK的PWM。
Q$ E! C) [2 {+ I! N
确定最小单位CK,配置时基单元 首先确定一个最小的间隔CK,规定PWM的高电平长度和低电平长度的单位都是CK。 即高电平的长度一定是CK的整数倍。低电平亦然。 然后配置定时器的时基单元,通过CK的长度确定预分频系数。 已知STM32F103的主频为72MHZ,则时基单元中预分频系数为
" `' {$ ]% O' m' b1 L( v
PSC = 72M / (1/CK) 例如,rtz所确定的CK长度为10us(0.00001s),即可得出方程。 ' N" H! X( W, h0 i/ _
& j$ P! e" T, f. B预分频系数确定为720后,由高速晶振产生的72MHZ的时钟信号被720分频,得到100000HZ的时钟信号。即时钟信号每秒变动100000次。每次10us。同时可将重装载值设定为0XFFFF(16位定时器的最大值)。因为本次使用的输出比较模式不使用更新中断,该值可随意设置。
, k4 x) i6 D( X* f1 V1 o: ^- `
TIM_TimeBaseStructure.TIM_Period = 0XFFFF;; z. D/ Y% Z9 e+ |& `9 F, F
TIM_TimeBaseStructure.TIM_Prescaler =720;# Q0 U/ z4 I9 r2 v; [0 t5 E3 n! W* s
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;0 R8 D6 O: P3 M& n
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;1 H: E4 a9 }0 ^; a: ` T( }
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
8 P6 ]* G0 S& f) I& p! @; e开启输出比较通道,设置输出比较模式为翻转模式,并配置NVIC,开启输出比较中断,配置输出比较通道: o- B& P$ ^6 s. e0 `# O9 w. j5 v
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;7 b4 Y! j4 U u* K' J1 ^
TIM_OCInitStructure.TIM_Pulse = 500;
3 N3 N6 i/ {; W5 L6 x/ Q: CTIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
" O8 ?2 u. N. J! f0 H4 D. cTIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
0 a, @% Z' a4 u- \* {0 @ V) QTIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
: S! j) U5 k3 BTIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;/ K: u. ~3 i% l) y- t
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
% s/ g* t! T! m3 G
开启输出比较中断,配置NVIC优先级: TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
8 ?9 k! x/ B2 d4 hNVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
: X6 M. e. x7 f9 \: K- d: t% \2 INVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
1 p4 i! P# m9 y9 mNVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
9 J2 u2 r1 [2 Y1 {2 Y. [" {( D9 uNVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;% W* J: T1 |( f, S
NVIC_Init(&NVIC_InitStructure); 编写中断服务函数
0 C4 r) S% @; @4 M5 B- ]在输出比较中断中,唯一要做的事情就是把当前CNT的值取出,加上脉冲长度X,写入输出比较寄存器。+ X$ J6 x7 x9 t# X
当计数器达到0XFFFF(之前设定的重装载值)后,再加一会自动变为0.$ |; M1 F$ w- ?" i
例如,当前CNT值为0XFFFF,脉冲长度为5,很明显,输出比较寄存器应设置为0X0004才可触发下一次中断,而不是0X10004,这样会造成溢出。
: L4 G6 ^) e, d5 X2 P因此将CNT的值与脉冲长度相加后,需要取0XFFFF的余数后,再写入输出比较寄存器。 int t_m=5;//低电平和高电平的长度 F+ x; g- z" @8 R- x$ C
void TIM2_IRQHandler(void)4 Y+ A6 B! V; e) [0 [ H/ e1 y: H0 c) _
{
' P( N5 K! U" ]' a8 Oif (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) {
7 w' O1 R. ^3 lTIM_SetCompare1(TIM2,(TIM2->CNT+t_m)%0XFFFF);
8 }0 c; N' D& _" K( o" d# j, wTIM_ClearITPendingBit(TIM2, TIM_IT_CC1);% L& \* B6 s$ c; G+ H
}6 x9 Z! M" j9 [4 q$ n
} 动态调整中断服务函数中的变量t_m,即可达到修改PWM频率的效果。
" P, s1 J2 r- B6 W
转载自:infinigo - J1 s2 a F; W7 I$ q
|