一.储备知识7 g6 P% F6 x9 |/ a& s* n
通过STM32的定时器编码器接口模式对编码器进行四倍频,并使用M法测速得到小车电机的速度信息。
" e* @7 E; J" H, `编码器的相关知识之前介绍过:编码器s
) a: I& z9 }( p- C qM法测速:读取每10ms的脉冲数,以脉冲数的多少代表速度的快慢。
$ r- T3 x: T- M+ o! b1 D q8 S/ V0 O( B0 _
二.TIMx的编码器模式介绍
7 B! S3 R" {! H4 yTIMx的编码器模式,每个定时器只能测量一组AB相的值(编码器的AB相),分别使用CH1和CH2接AB相,通过判断CH1和CH2的输入信号,来实现编码器的测速。需要配置TI1和TI2的极性、计数边沿、自动装载值等信息来驱动编码器模式。在实现编码器后,电机的转速会以计数器的值来表示,然后在另一个TIMx的10ms中断程序中读取编码器计数器的值(读取完要置零)。 [ T$ Z4 U' ?+ ]- j
下面大概总结一下配置编码器模式的信息:
4 {- D( I5 C8 F9 F$ k& u
+ m, P2 _5 a+ |, [- B. q1.计数边沿设置
/ z* r& m3 c2 S: |2 a n我是使用编码器四倍频技术测速,所以要对AB相的上下沿都要计数,也就是说TI1和TI2的上下沿都要触发计数器计时。
5 g! V. S7 z7 n( @1 ~; u9 P关于编码器计数模式,通过配置TIMx_SMCR寄存器中的SMS[2:0]位可以设置,参考手册中的原图如下:; K( _$ m2 b) Y' ^! f
9 a* ~; p9 e. L0 U
6 |1 ]& @: f# n* L0 R
0 @1 h. Q/ Y' z1 N
所以,要配置编码器模式3才可以对TI1和TI2的上下沿都计数,即SMS=011。
2 w- X. |6 j6 S: j4 Q$ R
2 O4 T( J) @/ `/ z8 O B2 o8 h1 c4 J8 |% C) t4 w' C
2.选择极性和使能
% V# G; T$ g; F; R- s9 G1 m* T6 n设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性,如图:
6 t/ q8 T3 I6 q7 }! J2 Q7 b2 Z: g, E5 d4 f$ }
3 i2 ^7 q3 z# Z5 _4 I. O
2 d! y, f' U d" {7 k2 E8 a" B+ I9 I& L+ T$ Z" e$ J% Z
3.使能
( I2 T6 e2 i/ YTIMx_CR1寄存器中的CEN=’1’用来使能计数器:
/ [0 }+ T2 u; w% S6 R
1 S" l( l. G0 P( w
: x7 W; D$ {- W6 x5 y
$ Y- p' [4 i* ` G% ]( H
/ D' r3 p0 g6 _* l" k6 g1 l9 [4.计数方向5 r6 D% ^& p7 Q, H7 |8 _' u
在工作时,计数器只在0到TIMx_ARR寄存器的自动重装值之间进行连续计数,所以计数开始前要配置TIMx_ARR。% _. u, c: p' g% Q8 ~/ S
通过对AB相的输入捕获,可以得到电机的转动方向和转速,是通过计数器的计数方向和计数值来表示的,计数方向和编码器信号的对应关系如图:
2 J! k a& q/ P" l: g
7 d [& t y: Q3 c4 B" P& y
; b; `8 p8 Y* \- _
8 u3 t! q! L" E' n# Y& g3 [
四倍频配置如下:
% v8 o l% ?' ?4 a. e1 E9 Q# d! C( ~8 D+ a0 @' C0 T0 [7 U3 y
! H% w5 N$ f7 x2 ~8 U
1 o. `" ?- L+ c$ O8 l+ a- O得到的计数器计数过程就如图:
1 j8 ~7 U' C) m1 {
6 @+ r/ Y9 b( Z& b/ F
# i# A! e( {1 |) _" {: h
& [1 }( R: @- e8 K5 o1 }; y& _3 W
4 T# @' e* j" W( g" m) Z9 [7 f1 b
三.代码部分
/ g/ {" H1 l+ M0 `. H在STM32中,可以用TIM2、TIM4的CH1、CH2来连接俩个电机的AB相,进行编码器测速,然后在TIM3进行10ms的中断读取计数器的值,这样就实现了编码器的四倍频测速,代码如下:
* s: I5 i2 v' \7 p9 \, l9 X9 n; X+ A5 i4 @
TIM2、TIM4初始化代码/ k% F1 f6 Y+ N/ G& Y
- /* 测量编码器输出的TIM初始化,TIMx编码器模式
' Y4 [, g# d0 S - TIM2、TIM4编码器模式测速
2 v5 N3 Z" E0 F* [8 u1 \ - A电机:PA0、PA1(TIM2的CH1、CH2)
, J4 {4 q* ^2 H% x8 b9 N - B电机:PB6、PB7(TIM2的CH1、CH2)8 Q" _% x: S0 z: t! o" g" b7 B
- */" c1 \$ B7 k, O, ]( Z+ a
- void Encoder_TIM2_TIM4_Init( void )
8 y# l. B d3 P% S; c - {* O# u4 s, O9 W5 B' p0 J; w# R
- GPIO_InitTypeDef GPIO_InitStruct;
! b# A' j. m9 _9 u9 ?, }& k - TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
3 @3 u. h5 B" @ - TIM_ICInitTypeDef TIM_ICInitStruct;
. K! s4 q6 k; `& j9 @ - 0 b7 C0 c" X, [- l: x
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE );
( L* H' y$ H6 i" r5 g - RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM4, ENABLE );/ C2 X0 R4 v7 I! s: V! N1 ^ {
- " p7 S$ t% l! _/ v
- /* GPIO初始化 */7 W/ j& j, X9 @: u
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;3 v9 _1 z0 G7 h
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;3 s4 h* T3 R! H% b! b
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;5 q B4 m: t: e0 P
- GPIO_Init( GPIOA, &GPIO_InitStruct );) X0 o1 x) U; @. m% }, f! T
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
$ C# g( m. n* \ - GPIO_Init( GPIOB, &GPIO_InitStruct );" q' p/ [! v6 p; Z" a# ?, j# U
-
+ b# a! W1 p) L \4 j- h3 D - /* 配置时基结构体 */
( G2 O7 d- B! f - TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;( [: J: R! \3 m: O! Y
- TIM_TimeBaseInitStruct.TIM_Period = 65535;//定时器自动重装值
. G. F+ w/ u3 r. r - TIM_TimeBaseInitStruct.TIM_Prescaler = 0;9 I! O' \5 y% g
- TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStruct );
& Y! }2 c& r' L$ e - TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );* e/ v" O4 A8 F, [# ] f
- 2 B6 t5 E- n! B! K
- /* 编码器模式3,极性上升沿 */
" H# t. m+ i2 M - TIM_EncoderInterfaceConfig( TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );+ Q9 f" q1 ?' Y/ D
- TIM_EncoderInterfaceConfig( TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );
$ S% P, F3 f. |9 |- e0 ?- ?+ k
) X2 v: h9 {% n5 ]* K7 k7 @1 f- /* 配置输入捕获结构体 */$ Y* W% t0 w w! l0 N
- TIM_ICStructInit( &TIM_ICInitStruct );+ ]. [/ ?0 Q# ~5 { U) M2 Q
- /*CCMR1寄存器位7:4是IC1F[3:0]:这几位定义了TI1输入的采样频率及数字滤波器长度。数字滤波器由一个事件计数器组成,它记& k( k# |6 u* f
- 录到N个事件后会产生一个输出的跳变:*/
/ q# h ~3 H% m' ]4 M& y - TIM_ICInitStruct.TIM_ICFilter = 10;//1010:采样频率fSAMPLING=fDTS/16, N=5
+ `+ \% r, v" z, j - TIM_ICInit( TIM2, &TIM_ICInitStruct );
$ i( h( H0 ?3 \# a& K - TIM_ICInit( TIM4, &TIM_ICInitStruct );, \" x7 R9 T( _
- 4 ]2 f& a2 U! B
- /* 中断配置 */
" F0 ^$ q* j! h5 G' Z0 U9 ^ - TIM_ClearFlag( TIM2, TIM_IT_Update );
* c4 K: Z4 C* z) Y+ c3 t; q - TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE );
) O% ~6 y! x: k1 U - TIM_ClearFlag( TIM4, TIM_IT_Update );
4 {: H( W+ l8 T* X0 \: Y" w0 V - TIM_ITConfig( TIM4, TIM_IT_Update, ENABLE );3 a2 u) f3 t2 r+ n5 o8 o$ W
-
# p$ D( U( D# ? - /* 配置计数器的值 */7 }2 V Z9 b2 j4 f0 P
- TIM_SetCounter( TIM2, 0 );
. d- ~# |; }* |0 H! P0 E - TIM_SetCounter( TIM2, 0 );& b# L, r+ H; B" t
- 4 h E. @+ S7 t. k1 e' b
- /* 使能TIM */
: i6 }, K) l- A' T* X5 j @ - TIM_Cmd( TIM2, ENABLE );5 C6 d& w# a/ m- Y1 ]- W& T9 K {; n
- TIM_Cmd( TIM4, ENABLE );7 d; F* ]! G$ W( C6 H) N
- / h; ?# @# v/ S1 g3 }2 Q
- }* R4 j1 j2 j" i# | Y8 q- C& M
( S" e1 t( u0 d. S& b. j1 u) W& Q
复制代码 % U7 p/ b2 b1 R4 p- q
读取编码器计数值
$ z ~' G# x' {/ z6 B* \7 Z; F- /* 读取编码器计数 */
- H& H5 w% t1 W9 C( N' U: E - int Read_Encoder( uint8_t TIMx ) L- s" f" v$ Z9 I5 G
- {
, z' l5 H4 ?# o8 B - int Encoder;
" _0 n: O$ e! ^! n* q# a3 {& n - /* 读取相应TIM的计数器值CNT,然后清零 */
* L. I3 l9 D; {2 B3 F9 W% P7 C - switch(TIMx)
( j" j* F4 \0 I$ C9 C3 g - {8 K; P- D' }# j, v6 l: [
- case 2:Encoder = (short)TIM2->CNT;TIM2->CNT=0;break;) w O: y$ L" D; w7 m+ w0 I3 b0 V
- case 4:Encoder = (short)TIM4->CNT;TIM4->CNT=0;break;
8 N- j6 |" j8 y - default:Encoder = 0;break;
; p: R" W+ `& x# p0 g - }
' L3 ^/ @6 {9 m' {! k1 } z3 H$ a0 x -
7 {* W9 U y. z+ `& V& l) T5 T - return Encoder;- p" [8 C4 D" s( ^: |$ ?/ H6 H
- }
6 o1 O8 K6 }' \6 Z3 \6 X
复制代码 7 T' q( g) A$ C: m
TIM2、TIM4中断程序
5 S" s9 w" i( k5 U$ L' M* u- void TIM2_IRQHandler(void)0 f* a( }1 l4 z4 N a# s
- {7 X( {. b/ Z* `1 C- _8 B, A) F l
- /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。- ~) e6 N* K4 D" I
- 0:无输入捕获产生;0 A) N* X" ?- A2 j$ Y8 W" B3 Y
- 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */6 P$ H. g% M. b4 o
- if( TIM2->SR&0x0001 )
5 R* }; l; ~: t; J8 R - ;( s/ h$ c0 w. e( q ` l9 T
- /* 清除中断标志位 */3 m& t* E. v+ w& z
- TIM2->SR&=~(1<<0);
# c1 \7 h3 J) s0 t, V - }
' K. A/ \3 `; t
; A/ o2 B- l) d. U0 R: V0 `
! v9 j5 n6 m/ L- C0 c: x) ^
" o$ E' n7 A) U0 @- void TIM4_IRQHandler(void)" W! `5 H C3 E* F
- {+ h% D$ k7 V! C6 t4 p6 K, t% ^
- /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。
6 \+ V/ W: O9 p. U' ?" l8 X - 0:无输入捕获产生;
0 H0 r7 j: {( Z - 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */
) S9 @; v+ Q3 s - if( TIM4->SR&0x0001 )
3 ^$ D" p6 K% h - ;
' ~, G! o$ o( X& Y5 `8 D$ O' S; s - /* 清除中断标志位 */
9 u X$ U1 `% B; Z - TIM4->SR&=~(1<<0);
8 S" k4 C" b. r+ f; z - }) t7 D. C* u4 s N8 Q! B
- % p. O6 @% q% X' U
复制代码 8 O% B* J' N n# ]7 g
TIM3配置、中断读取计数器值
2 c- H, ]3 g' K# t- void TIM3_Int_Init(u16 arr,u16 psc)
9 s% |9 S" x$ i - {" Z$ h1 L5 @; D) Y* X
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; O* w0 D/ C5 U$ v/ p0 `
- NVIC_InitTypeDef NVIC_InitStructure;. \$ Z7 I t2 A0 f. K
- 4 g" _0 o) D: `7 b+ ~" D
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能0 e, A( o+ e% |4 g
- 7 V) u; ^5 u& y' q g+ H
- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms
' Q+ [$ `. R! X2 L; ?7 { - TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率 0 N7 f/ [" _6 F4 ^3 i2 W
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim' u5 R4 j* v# t6 L0 L' ^
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式# b" _7 n+ R$ H/ \6 N& i$ U
- TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
8 P9 W7 P8 c5 J# _( q, W - ' H) {% r$ ^3 x' w6 r2 J
- TIM_ITConfig( //使能或者失能指定的TIM中断( k* n7 W* r) R9 t: ^6 Q9 u! s8 l
- TIM3, //TIM2
9 B2 f; h+ W5 ~ ^ - TIM_IT_Update ,
' X: y8 \. S+ A* ?* t" G9 @ - ENABLE //使能
, Z) M7 d, I; [% }' t' @: j - );
" n; a+ X9 ^/ p) T) H# L9 ^ - NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
: C/ I/ V. k f4 _5 d - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级0 K5 f0 X, Q2 R) [( ~
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级 p1 C8 Z! r$ d* A! O
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
8 f2 o9 Q' Q& o$ t, L, b7 X/ \+ \% e9 B - NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器) H) N, f* {$ ~6 p, `
- & v U0 x+ g' I- u, P1 U) f
- TIM_Cmd(TIM3, ENABLE); //使能TIMx外设. u+ w' {4 O3 D0 v) X# N
-
4 D' B' d4 z2 k! f" z - }
: P! |; y- ?8 [) ]) Y$ m3 p( o( H4 W - void TIM3_IRQHandler(void) //TIM3中断
, b0 D( i. A7 j& S - {7 _5 Z" q9 F6 x8 y4 t& t; R* P
- if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 8 _4 n4 Y& Z9 s& ]( b
- {+ d, B. I% J6 I$ s" K
- TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
: _9 p& r& i9 R! C( W( c - Encoder_Left=(short)TIM2->CNT;
; T7 [9 ?5 R; p4 D# o - TIM2->CNT=0; - U( v, p: _; C) y! c+ q5 Y" _
- }
3 h( D8 `; z8 L - }
复制代码
4 p5 a6 F% c# R————————————————
. W! h) r, I$ B6 x+ P3 F1 p8 z# [版权声明:Aspirant-GQ
# Y. V+ U K# ?: Z: V1 j R如有侵权请联系删除+ \1 `6 O) S0 n$ `% b- |6 x' p
; G$ w: [0 W2 Y8 V8 [& f7 m5 F% N- O- I* z; r: ?; c5 S C$ D' B
6 b- ^1 K! y, U, Q
|