一.储备知识
; o% U, k1 L) ~) s3 W& s通过STM32的定时器编码器接口模式对编码器进行四倍频,并使用M法测速得到小车电机的速度信息。
1 G# W$ n7 I, B1 I0 s z' f编码器的相关知识之前介绍过:编码器s
& p: X1 H0 E* }) I: pM法测速:读取每10ms的脉冲数,以脉冲数的多少代表速度的快慢。$ ?1 e, L ^+ Q1 Z0 f+ r" R3 X
* y2 C, s5 e: m二.TIMx的编码器模式介绍' k9 v1 `4 ] v: H
TIMx的编码器模式,每个定时器只能测量一组AB相的值(编码器的AB相),分别使用CH1和CH2接AB相,通过判断CH1和CH2的输入信号,来实现编码器的测速。需要配置TI1和TI2的极性、计数边沿、自动装载值等信息来驱动编码器模式。在实现编码器后,电机的转速会以计数器的值来表示,然后在另一个TIMx的10ms中断程序中读取编码器计数器的值(读取完要置零)。
1 k0 `; Y4 z o& g( {2 e/ L下面大概总结一下配置编码器模式的信息:: p c& O* k: z# s9 D9 d! J% A& K; p8 ~
& `6 R% ^- x! J$ J' E, q
1.计数边沿设置
* d7 X2 Z! H1 N- s* J我是使用编码器四倍频技术测速,所以要对AB相的上下沿都要计数,也就是说TI1和TI2的上下沿都要触发计数器计时。9 i; @1 J* c# o+ F
关于编码器计数模式,通过配置TIMx_SMCR寄存器中的SMS[2:0]位可以设置,参考手册中的原图如下:
/ ^; b' N4 W U } r) ]# L/ I) Y9 i" Q h
+ G) a8 s/ I/ U! Z3 ^
0 [" J7 ~3 R$ c, i. p; n+ l1 `7 U所以,要配置编码器模式3才可以对TI1和TI2的上下沿都计数,即SMS=011。8 `* |' H8 N! }, v" C
% B+ y, C4 _; x6 @2 j
/ [8 m! M' v- A% }) h4 r/ X
2.选择极性和使能
6 S" Z; m7 I4 E6 y$ I) a; r设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性,如图:+ m9 B" k' P- K4 v6 w% h4 z
1 H6 F( x5 k/ N9 q$ _6 R! `7 L3 p
" w- I- t: [4 b' O6 p) ?' x9 N
# B9 S8 r, }5 i% s: a9 T$ Y
( V8 e" }2 [; a* s5 x3.使能
; L2 F- y: X6 X5 R9 ^! j+ f yTIMx_CR1寄存器中的CEN=’1’用来使能计数器:* _. ~2 U9 O5 C
1 A- O' v; i) P: Y2 `
$ s4 T6 |3 F1 q+ W7 a
2 e. }2 c9 B/ x
: B* O% {. @$ ]2 T S4.计数方向
+ e" y6 F' z, Q% d, S& z在工作时,计数器只在0到TIMx_ARR寄存器的自动重装值之间进行连续计数,所以计数开始前要配置TIMx_ARR。
0 K( B4 r3 `, t% H8 Z: ~% S通过对AB相的输入捕获,可以得到电机的转动方向和转速,是通过计数器的计数方向和计数值来表示的,计数方向和编码器信号的对应关系如图:/ r5 ~; a _6 M& P; Q
- _$ g g' p) H( A2 F; ?
$ w. K" a2 n3 U
0 n" M8 S) q. P; }( h7 S四倍频配置如下:1 _% D/ U6 h! R. N+ N6 K
( [1 k& Q+ V0 ?9 P, O9 M) j
% u1 Y/ S! F6 Y# Y! T% W# j' x* u' N% v$ k2 W& [
得到的计数器计数过程就如图:$ p. Q1 T" B+ ?3 H" |# p- a
7 N, l! `; P) [4 X$ r
- c$ J1 c+ {# [. I! V
: D7 x! I& Y# e q. ], _# t
# s0 i- c/ g; X, p三.代码部分
( G4 G. k, @9 x: i1 z. H% s在STM32中,可以用TIM2、TIM4的CH1、CH2来连接俩个电机的AB相,进行编码器测速,然后在TIM3进行10ms的中断读取计数器的值,这样就实现了编码器的四倍频测速,代码如下:2 e/ I/ r, S5 ^8 f! c" J
/ f4 W+ o( S0 e+ y& l
TIM2、TIM4初始化代码
6 l1 z* [3 R/ D. Z- /* 测量编码器输出的TIM初始化,TIMx编码器模式 6 o1 g) B+ K- s B# O
- TIM2、TIM4编码器模式测速
+ }/ d2 _& A1 g. C) B - A电机:PA0、PA1(TIM2的CH1、CH2)
, b. N4 }; q4 {9 `! }4 p: u - B电机:PB6、PB7(TIM2的CH1、CH2)7 K) e# d+ F, b
- */7 b4 P% z3 u% a6 X# ^
- void Encoder_TIM2_TIM4_Init( void ). L7 i4 z& f/ F4 b3 c: w8 w
- {# D8 ?) P; h, h
- GPIO_InitTypeDef GPIO_InitStruct;
$ R* }1 G" m6 J, j1 I - TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
5 `% y8 x' \& [6 m. f4 D - TIM_ICInitTypeDef TIM_ICInitStruct;
) T q8 k3 ?/ i+ l) r" ^' Y; y+ x - 3 l. }# m: @' s/ `, H; Y
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE );
3 _1 S0 j+ E. m1 |( f; E - RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM4, ENABLE );6 G5 a N' s+ G k
-
9 D; M) ]6 f4 n - /* GPIO初始化 */
$ M. P) M' b7 j& | - GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;% e0 F" o* b4 H! i) C
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
& P3 o' K+ q7 M& _5 _ - GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;* R* S6 w$ A7 w( ~0 `
- GPIO_Init( GPIOA, &GPIO_InitStruct );
Q' A. G" X: d' r: J% L% y - GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
7 l( } S* f8 {- W - GPIO_Init( GPIOB, &GPIO_InitStruct );+ c: f4 K6 ~$ j) a0 J
-
& \: B( U% @$ W/ B- ?6 ] v/ P - /* 配置时基结构体 */& s' K% b( n) ?& U
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;- J2 W, B$ x5 W, ?- @: k
- TIM_TimeBaseInitStruct.TIM_Period = 65535;//定时器自动重装值
- y! Q u* S7 E% d7 D! r& E - TIM_TimeBaseInitStruct.TIM_Prescaler = 0;1 h7 D/ W5 ]; _: w" R. r* r9 L
- TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStruct );
' f: i; v8 W$ l! B: m. D3 f - TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );
4 k1 u# Y0 t+ j, e -
' `7 @3 m; \4 i' @* y - /* 编码器模式3,极性上升沿 */
7 u4 k) {8 i1 n6 _/ K! a; p5 b4 \ - TIM_EncoderInterfaceConfig( TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );* E1 |+ u% W& g2 G+ i
- TIM_EncoderInterfaceConfig( TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );; O C5 g. f0 l3 n8 `
1 q5 M" O& F. n5 [4 G- e- /* 配置输入捕获结构体 */
1 m, z2 A) T$ e( D( n9 W/ x7 a - TIM_ICStructInit( &TIM_ICInitStruct );
0 |& j6 ? Q% s# B' } - /*CCMR1寄存器位7:4是IC1F[3:0]:这几位定义了TI1输入的采样频率及数字滤波器长度。数字滤波器由一个事件计数器组成,它记2 B. t1 J# M& x4 t
- 录到N个事件后会产生一个输出的跳变:*/
! @. z& h8 K# S7 G: h - TIM_ICInitStruct.TIM_ICFilter = 10;//1010:采样频率fSAMPLING=fDTS/16, N=5
4 R+ D2 [$ {; t3 K/ h2 u7 F - TIM_ICInit( TIM2, &TIM_ICInitStruct );
7 L3 R" G; |+ n - TIM_ICInit( TIM4, &TIM_ICInitStruct );1 Q T0 k/ X0 B0 z+ y
- - m! B# t2 }8 i! f0 J3 Z
- /* 中断配置 */. q( V+ {: h: Z" U3 H+ O( j
- TIM_ClearFlag( TIM2, TIM_IT_Update );
) Q5 ~( K, N" N( B+ D0 _" C6 u - TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE );
; }! y; t& x4 B. Q - TIM_ClearFlag( TIM4, TIM_IT_Update );
Y) [& G9 N& w0 r - TIM_ITConfig( TIM4, TIM_IT_Update, ENABLE );
# m0 i: V0 ]$ O' O5 t -
! I4 F, R7 C# q - /* 配置计数器的值 */
7 w) a& l' W" _. s - TIM_SetCounter( TIM2, 0 );
7 ]) Q# `5 I( W/ O: {/ e8 K - TIM_SetCounter( TIM2, 0 );
# D: S5 a6 Q' c$ e- L, L( Y+ j1 v7 e -
! n: X/ O' @3 P3 F* J) y# C" H5 ] - /* 使能TIM */: B) j; V$ d+ G# p
- TIM_Cmd( TIM2, ENABLE );
+ O- O( y' _" ^ d; x o - TIM_Cmd( TIM4, ENABLE );
0 m7 N* s: X7 v5 }& G -
5 w8 p& w O, N5 l - }
+ Q( U Z. x' E4 A V. ]( f - 9 p* F) P/ k/ E3 i0 h) n, C
复制代码
5 v( b" i/ S8 W8 _; X- p9 w读取编码器计数值
$ D# l' Q+ h' e1 I+ R) ^& Y; r- /* 读取编码器计数 */ Z' ]1 E! o k; ^
- int Read_Encoder( uint8_t TIMx )
/ q: f4 e. D- L$ J# |5 d# A - {
l& Q& S1 M: ^8 g- u- l9 X - int Encoder;# h8 z3 \# s0 R( b% k2 G
- /* 读取相应TIM的计数器值CNT,然后清零 */
9 {! d$ `2 X1 | - switch(TIMx)- w, R. o3 |' l* N! U! E
- {8 m; B* |% P! d2 J
- case 2:Encoder = (short)TIM2->CNT;TIM2->CNT=0;break;# y. P; z4 U g( V- L5 o/ j# |
- case 4:Encoder = (short)TIM4->CNT;TIM4->CNT=0;break;
7 Q4 f* ~" y& h! z8 T - default:Encoder = 0;break;. h+ \% a+ F$ ~ F' E; ^6 S
- }3 i+ a+ |/ c9 @1 ?
- / j. B2 h- b+ |# m0 \6 c; C( z
- return Encoder;4 a# S3 G0 i( N1 h
- }' c2 Q9 X# R( Q
复制代码 X! F4 z: m. [
TIM2、TIM4中断程序& F3 Z: h, k: t* H1 J
- void TIM2_IRQHandler(void)
0 U5 n0 l( |1 N+ q5 P - {
4 a* H0 [; D: D9 k, R( o& S/ _ - /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。/ o# P" v6 l5 u' w! r- b" z
- 0:无输入捕获产生;
: U0 l' ?" a: { - 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */
2 H4 _" {9 S, I0 H7 N5 J4 F) r - if( TIM2->SR&0x0001 )+ I6 r, u9 E; q7 h+ \4 ~
- ;: V9 x: n. A, E8 ^, E9 U( `7 Y% O
- /* 清除中断标志位 */
" W* d/ W, H* D |8 j9 x - TIM2->SR&=~(1<<0);
. @) s X& ]) G" i* H - }
1 V# \2 a# a2 V* m) V" f { - ' I) F& Z+ u! \5 V$ Q# G
1 L' i! L& M. R W0 U' G9 x
6 G9 [" z4 e# x, P3 _; m- void TIM4_IRQHandler(void)
. O5 m+ y. t$ ]! E' w! H: O L - {) L& E* `' Q/ _
- /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。- k: S9 s% z& \- X# _
- 0:无输入捕获产生;2 Z7 i4 H6 x9 U& I) [7 M
- 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */$ G( k' ]7 q4 [4 {- X. p8 Z W4 D
- if( TIM4->SR&0x0001 )
/ L# C. P& \/ Y2 O - ;
6 g. }3 V% ^# I/ x( X7 q - /* 清除中断标志位 */1 `, u, F. Q( S# E
- TIM4->SR&=~(1<<0);. U9 ~, ~" J! ]( U( a
- }" R$ U, ]! T |5 h! p7 K8 a" T
3 i! a7 b( v; O& V1 u- i" O" a, a5 ~
复制代码
) c! k8 e4 M4 A E/ iTIM3配置、中断读取计数器值
! C1 [) D% _: G) o3 e/ W: s8 C- void TIM3_Int_Init(u16 arr,u16 psc)5 F* Q e' M" D9 N+ O% U' _
- {+ ^2 E- O1 A1 h1 I# X% N
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
( C% F+ G8 Q2 b4 n( [/ x& T$ j - NVIC_InitTypeDef NVIC_InitStructure;" W9 W; D2 c' j* J3 ~7 n
- % g; t$ Y: ]; s, n( i
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
: Y' K/ I3 V; J0 W
/ L! l7 {. k: ^( Y- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms
. p8 V& y3 k3 S- k# S - TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率 / r5 S1 r8 U7 D$ v/ j6 M0 T3 z; l* ]
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim, Z+ g* O1 k! v
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
, k9 Z; C. E, U$ a1 s- R - TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
8 j3 k: r: h( i0 W- G0 K* ` - 0 t# s! a) |4 b+ ]
- TIM_ITConfig( //使能或者失能指定的TIM中断- c3 s+ ]9 J1 q5 Z( F" N$ o
- TIM3, //TIM2
; Q- i3 `( L2 ]2 @* | - TIM_IT_Update ,
: F0 [0 G( Z* J) ~2 g5 g; i - ENABLE //使能
0 Q4 O/ [/ o8 a/ P/ @* R - );
0 n" {9 u5 [. C$ P8 V - NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断8 v: w0 L+ ?; s) C
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级9 H% _! O2 m; \
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
, ]4 B0 S2 r" j! d% W; j. } - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能( B, E9 J1 W) b0 n6 K
- NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
: @1 v8 W z/ c' X9 @
+ Y8 T- K- _' E) v4 M- TIM_Cmd(TIM3, ENABLE); //使能TIMx外设7 @7 s0 R8 p: c& f5 A9 L; `
- 0 g* _5 H% B2 U! i" s$ Q( G
- }
1 |8 l; h/ G/ Z# I - void TIM3_IRQHandler(void) //TIM3中断
6 c* R+ b! y2 c/ L9 _' m - {
a" T0 k8 A4 @# J) q; p( }2 u - if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 % L& V( f+ w Q# W- B8 b( c/ _
- {
( \/ _$ `7 A: x9 c - TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源 3 T5 x3 {' e* ~
- Encoder_Left=(short)TIM2->CNT;
0 V' e6 I1 C5 U& C6 D6 { - TIM2->CNT=0; 3 ^# }! W' s+ O W0 o. u# C
- }/ a# V- j$ m0 U8 F, H
- }
复制代码 I3 G" ^9 E5 p2 G+ g3 n
————————————————
* o. o1 i# S! l3 t+ n& y版权声明:Aspirant-GQ
6 g3 {1 B/ W1 P% P如有侵权请联系删除
: x3 S9 J0 Q* t5 N2 v
( t% _6 x) i% u9 I/ O" W) t* g+ h! B* G
- j: G: y/ a x) |& }: O6 `
|