你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的TIMx实现编码器四倍频

[复制链接]
攻城狮Melo 发布时间:2023-3-18 12:18
一.储备知识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
20200222110643214.png 20200222110619523.png 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 o
8 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$ }
20200222121758415.png
3 i2 ^7 q3 z# Z5 _4 I. O 2020022212182348.png
2 d! y, f' U  d" {7 k2 E
8 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
20200222122058845.png : x7 W; D$ {- W6 x5 y
20200222122048369.png $ 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
20200222122445815.png ; 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
2020022212252355.png
! 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
20200222122557930.png # 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 p
9 \, l9 X9 n; X+ A5 i4 @
TIM2、TIM4初始化代码/ k% F1 f6 Y+ N/ G& Y
  1. /* 测量编码器输出的TIM初始化,TIMx编码器模式
    ' Y4 [, g# d0 S
  2. TIM2、TIM4编码器模式测速
    2 v5 N3 Z" E0 F* [8 u1 \
  3. A电机:PA0、PA1(TIM2的CH1、CH2)
    , J4 {4 q* ^2 H% x8 b9 N
  4. B电机:PB6、PB7(TIM2的CH1、CH2)8 Q" _% x: S0 z: t! o" g" b7 B
  5. */" c1 \$ B7 k, O, ]( Z+ a
  6. void Encoder_TIM2_TIM4_Init( void )
    8 y# l. B  d3 P% S; c
  7. {* O# u4 s, O9 W5 B' p0 J; w# R
  8.         GPIO_InitTypeDef GPIO_InitStruct;
    ! b# A' j. m9 _9 u9 ?, }& k
  9.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    3 @3 u. h5 B" @
  10.         TIM_ICInitTypeDef TIM_ICInitStruct;
    . K! s4 q6 k; `& j9 @
  11.         0 b7 C0 c" X, [- l: x
  12.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE );
    ( L* H' y$ H6 i" r5 g
  13.         RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM4, ENABLE );/ C2 X0 R4 v7 I! s: V! N1 ^  {
  14.         " p7 S$ t% l! _/ v
  15.         /* GPIO初始化 */7 W/ j& j, X9 @: u
  16.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;3 v9 _1 z0 G7 h
  17.         GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;3 s4 h* T3 R! H% b! b
  18.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;5 q  B4 m: t: e0 P
  19.         GPIO_Init( GPIOA, &GPIO_InitStruct );) X0 o1 x) U; @. m% }, f! T
  20.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
    $ C# g( m. n* \
  21.         GPIO_Init( GPIOB, &GPIO_InitStruct );" q' p/ [! v6 p; Z" a# ?, j# U
  22.        
    + b# a! W1 p) L  \4 j- h3 D
  23.         /* 配置时基结构体 */
    ( G2 O7 d- B! f
  24.         TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;( [: J: R! \3 m: O! Y
  25.         TIM_TimeBaseInitStruct.TIM_Period = 65535;//定时器自动重装值
    . G. F+ w/ u3 r. r
  26.         TIM_TimeBaseInitStruct.TIM_Prescaler = 0;9 I! O' \5 y% g
  27.         TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStruct );
    & Y! }2 c& r' L$ e
  28.         TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );* e/ v" O4 A8 F, [# ]  f
  29.         2 B6 t5 E- n! B! K
  30.         /* 编码器模式3,极性上升沿 */
    " H# t. m+ i2 M
  31.         TIM_EncoderInterfaceConfig( TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );+ Q9 f" q1 ?' Y/ D
  32.         TIM_EncoderInterfaceConfig( TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );
    $ S% P, F3 f. |9 |- e0 ?- ?+ k

  33. ) X2 v: h9 {% n5 ]* K7 k7 @1 f
  34.         /* 配置输入捕获结构体 */$ Y* W% t0 w  w! l0 N
  35.         TIM_ICStructInit( &TIM_ICInitStruct );+ ]. [/ ?0 Q# ~5 {  U) M2 Q
  36.         /*CCMR1寄存器位7:4是IC1F[3:0]:这几位定义了TI1输入的采样频率及数字滤波器长度。数字滤波器由一个事件计数器组成,它记& k( k# |6 u* f
  37. 录到N个事件后会产生一个输出的跳变:*/
    / q# h  ~3 H% m' ]4 M& y
  38.         TIM_ICInitStruct.TIM_ICFilter = 10;//1010:采样频率fSAMPLING=fDTS/16, N=5
    + `+ \% r, v" z, j
  39.         TIM_ICInit( TIM2, &TIM_ICInitStruct );
    $ i( h( H0 ?3 \# a& K
  40.         TIM_ICInit( TIM4, &TIM_ICInitStruct );, \" x7 R9 T( _
  41.         4 ]2 f& a2 U! B
  42.         /* 中断配置 */
    " F0 ^$ q* j! h5 G' Z0 U9 ^
  43.         TIM_ClearFlag( TIM2, TIM_IT_Update );
    * c4 K: Z4 C* z) Y+ c3 t; q
  44.         TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE );
    ) O% ~6 y! x: k1 U
  45.         TIM_ClearFlag( TIM4, TIM_IT_Update );
    4 {: H( W+ l8 T* X0 \: Y" w0 V
  46.         TIM_ITConfig( TIM4, TIM_IT_Update, ENABLE );3 a2 u) f3 t2 r+ n5 o8 o$ W
  47.        
    # p$ D( U( D# ?
  48.         /* 配置计数器的值 */7 }2 V  Z9 b2 j4 f0 P
  49.         TIM_SetCounter( TIM2, 0 );
    . d- ~# |; }* |0 H! P0 E
  50.         TIM_SetCounter( TIM2, 0 );& b# L, r+ H; B" t
  51.         4 h  E. @+ S7 t. k1 e' b
  52.         /* 使能TIM */
    : i6 }, K) l- A' T* X5 j  @
  53.         TIM_Cmd( TIM2, ENABLE );5 C6 d& w# a/ m- Y1 ]- W& T9 K  {; n
  54.         TIM_Cmd( TIM4, ENABLE );7 d; F* ]! G$ W( C6 H) N
  55.         / h; ?# @# v/ S1 g3 }2 Q
  56. }* R4 j1 j2 j" i# |  Y8 q- C& M

  57. ( 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
  1. /* 读取编码器计数 */
    - H& H5 w% t1 W9 C( N' U: E
  2. int Read_Encoder( uint8_t TIMx )  L- s" f" v$ Z9 I5 G
  3. {
    , z' l5 H4 ?# o8 B
  4.         int Encoder;
    " _0 n: O$ e! ^! n* q# a3 {& n
  5.         /* 读取相应TIM的计数器值CNT,然后清零 */
    * L. I3 l9 D; {2 B3 F9 W% P7 C
  6.         switch(TIMx)
    ( j" j* F4 \0 I$ C9 C3 g
  7.         {8 K; P- D' }# j, v6 l: [
  8.                 case 2:Encoder = (short)TIM2->CNT;TIM2->CNT=0;break;) w  O: y$ L" D; w7 m+ w0 I3 b0 V
  9.                 case 4:Encoder = (short)TIM4->CNT;TIM4->CNT=0;break;
    8 N- j6 |" j8 y
  10.                 default:Encoder = 0;break;
    ; p: R" W+ `& x# p0 g
  11.         }
    ' L3 ^/ @6 {9 m' {! k1 }  z3 H$ a0 x
  12.        
    7 {* W9 U  y. z+ `& V& l) T5 T
  13.         return Encoder;- p" [8 C4 D" s( ^: |$ ?/ H6 H
  14. }
    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
  1. void TIM2_IRQHandler(void)0 f* a( }1 l4 z4 N  a# s
  2. {7 X( {. b/ Z* `1 C- _8 B, A) F  l
  3.         /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。- ~) e6 N* K4 D" I
  4. 0:无输入捕获产生;0 A) N* X" ?- A2 j$ Y8 W" B3 Y
  5. 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */6 P$ H. g% M. b4 o
  6.         if( TIM2->SR&0x0001 )
    5 R* }; l; ~: t; J8 R
  7.                 ;( s/ h$ c0 w. e( q  `  l9 T
  8.         /* 清除中断标志位 */3 m& t* E. v+ w& z
  9.         TIM2->SR&=~(1<<0);
    # c1 \7 h3 J) s0 t, V
  10. }
    ' K. A/ \3 `; t

  11. ; A/ o2 B- l) d. U0 R: V0 `

  12. ! v9 j5 n6 m/ L- C0 c: x) ^

  13. " o$ E' n7 A) U0 @
  14. void TIM4_IRQHandler(void)" W! `5 H  C3 E* F
  15. {+ h% D$ k7 V! C6 t4 p6 K, t% ^
  16.         /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。
    6 \+ V/ W: O9 p. U' ?" l8 X
  17. 0:无输入捕获产生;
    0 H0 r7 j: {( Z
  18. 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */
    ) S9 @; v+ Q3 s
  19.         if( TIM4->SR&0x0001 )
    3 ^$ D" p6 K% h
  20.                 ;
    ' ~, G! o$ o( X& Y5 `8 D$ O' S; s
  21.         /* 清除中断标志位 */
    9 u  X$ U1 `% B; Z
  22.         TIM4->SR&=~(1<<0);
    8 S" k4 C" b. r+ f; z
  23. }) t7 D. C* u4 s  N8 Q! B
  24. % p. O6 @% q% X' U
复制代码
8 O% B* J' N  n# ]7 g
TIM3配置、中断读取计数器值
2 c- H, ]3 g' K# t
  1. void TIM3_Int_Init(u16 arr,u16 psc)
    9 s% |9 S" x$ i
  2. {" Z$ h1 L5 @; D) Y* X
  3.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;  O* w0 D/ C5 U$ v/ p0 `
  4.         NVIC_InitTypeDef NVIC_InitStructure;. \$ Z7 I  t2 A0 f. K
  5. 4 g" _0 o) D: `7 b+ ~" D
  6.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能0 e, A( o+ e% |4 g
  7. 7 V) u; ^5 u& y' q  g+ H
  8.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值         计数到5000为500ms
    ' Q+ [$ `. R! X2 L; ?7 {
  9.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  0 N7 f/ [" _6 F4 ^3 i2 W
  10.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim' u5 R4 j* v# t6 L0 L' ^
  11.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式# b" _7 n+ R$ H/ \6 N& i$ U
  12.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    8 P9 W7 P8 c5 J# _( q, W
  13. ' H) {% r$ ^3 x' w6 r2 J
  14.         TIM_ITConfig(  //使能或者失能指定的TIM中断( k* n7 W* r) R9 t: ^6 Q9 u! s8 l
  15.                 TIM3, //TIM2
    9 B2 f; h+ W5 ~  ^
  16.                 TIM_IT_Update ,
    ' X: y8 \. S+ A* ?* t" G9 @
  17.                 ENABLE  //使能
    , Z) M7 d, I; [% }' t' @: j
  18.                 );
    " n; a+ X9 ^/ p) T) H# L9 ^
  19.         NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    : C/ I/ V. k  f4 _5 d
  20.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级0 K5 f0 X, Q2 R) [( ~
  21.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级  p1 C8 Z! r$ d* A! O
  22.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    8 f2 o9 Q' Q& o$ t, L, b7 X/ \+ \% e9 B
  23.         NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器) H) N, f* {$ ~6 p, `
  24. & v  U0 x+ g' I- u, P1 U) f
  25.         TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设. u+ w' {4 O3 D0 v) X# N
  26.                                                          
    4 D' B' d4 z2 k! f" z
  27. }
    : P! |; y- ?8 [) ]) Y$ m3 p( o( H4 W
  28. void TIM3_IRQHandler(void)   //TIM3中断
    , b0 D( i. A7 j& S
  29. {7 _5 Z" q9 F6 x8 y4 t& t; R* P
  30.         if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 8 _4 n4 Y& Z9 s& ]( b
  31.                 {+ d, B. I% J6 I$ s" K
  32.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源
    : _9 p& r& i9 R! C( W( c
  33.                 Encoder_Left=(short)TIM2->CNT;
    ; T7 [9 ?5 R; p4 D# o
  34.                 TIM2->CNT=0;        - U( v, p: _; C) y! c+ q5 Y" _
  35.                 }
    3 h( D8 `; z8 L
  36. }
复制代码

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
赞 收藏 评论0 发布时间:2023-3-18 12:18

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版