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

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

[复制链接]
攻城狮Melo 发布时间:2023-3-18 12:18
一.储备知识
; 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
20200222110643214.png 20200222110619523.png + 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
20200222121758415.png
" w- I- t: [4 b' O6 p) ?' x9 N 2020022212182348.png
# 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 `
20200222122058845.png
$ s4 T6 |3 F1 q+ W7 a 20200222122048369.png 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; ?
20200222122445815.png $ 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
2020022212252355.png
% 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
20200222122557930.png - 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
  1. /* 测量编码器输出的TIM初始化,TIMx编码器模式 6 o1 g) B+ K- s  B# O
  2. TIM2、TIM4编码器模式测速
    + }/ d2 _& A1 g. C) B
  3. A电机:PA0、PA1(TIM2的CH1、CH2)
    , b. N4 }; q4 {9 `! }4 p: u
  4. B电机:PB6、PB7(TIM2的CH1、CH2)7 K) e# d+ F, b
  5. */7 b4 P% z3 u% a6 X# ^
  6. void Encoder_TIM2_TIM4_Init( void ). L7 i4 z& f/ F4 b3 c: w8 w
  7. {# D8 ?) P; h, h
  8.         GPIO_InitTypeDef GPIO_InitStruct;
    $ R* }1 G" m6 J, j1 I
  9.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    5 `% y8 x' \& [6 m. f4 D
  10.         TIM_ICInitTypeDef TIM_ICInitStruct;
    ) T  q8 k3 ?/ i+ l) r" ^' Y; y+ x
  11.         3 l. }# m: @' s/ `, H; Y
  12.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE );
    3 _1 S0 j+ E. m1 |( f; E
  13.         RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM4, ENABLE );6 G5 a  N' s+ G  k
  14.        
    9 D; M) ]6 f4 n
  15.         /* GPIO初始化 */
    $ M. P) M' b7 j& |
  16.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;% e0 F" o* b4 H! i) C
  17.         GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    & P3 o' K+ q7 M& _5 _
  18.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;* R* S6 w$ A7 w( ~0 `
  19.         GPIO_Init( GPIOA, &GPIO_InitStruct );
      Q' A. G" X: d' r: J% L% y
  20.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
    7 l( }  S* f8 {- W
  21.         GPIO_Init( GPIOB, &GPIO_InitStruct );+ c: f4 K6 ~$ j) a0 J
  22.        
    & \: B( U% @$ W/ B- ?6 ]  v/ P
  23.         /* 配置时基结构体 */& s' K% b( n) ?& U
  24.         TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;- J2 W, B$ x5 W, ?- @: k
  25.         TIM_TimeBaseInitStruct.TIM_Period = 65535;//定时器自动重装值
    - y! Q  u* S7 E% d7 D! r& E
  26.         TIM_TimeBaseInitStruct.TIM_Prescaler = 0;1 h7 D/ W5 ]; _: w" R. r* r9 L
  27.         TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStruct );
    ' f: i; v8 W$ l! B: m. D3 f
  28.         TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );
    4 k1 u# Y0 t+ j, e
  29.        
    ' `7 @3 m; \4 i' @* y
  30.         /* 编码器模式3,极性上升沿 */
    7 u4 k) {8 i1 n6 _/ K! a; p5 b4 \
  31.         TIM_EncoderInterfaceConfig( TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );* E1 |+ u% W& g2 G+ i
  32.         TIM_EncoderInterfaceConfig( TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );; O  C5 g. f0 l3 n8 `

  33. 1 q5 M" O& F. n5 [4 G- e
  34.         /* 配置输入捕获结构体 */
    1 m, z2 A) T$ e( D( n9 W/ x7 a
  35.         TIM_ICStructInit( &TIM_ICInitStruct );
    0 |& j6 ?  Q% s# B' }
  36.         /*CCMR1寄存器位7:4是IC1F[3:0]:这几位定义了TI1输入的采样频率及数字滤波器长度。数字滤波器由一个事件计数器组成,它记2 B. t1 J# M& x4 t
  37. 录到N个事件后会产生一个输出的跳变:*/
    ! @. z& h8 K# S7 G: h
  38.         TIM_ICInitStruct.TIM_ICFilter = 10;//1010:采样频率fSAMPLING=fDTS/16, N=5
    4 R+ D2 [$ {; t3 K/ h2 u7 F
  39.         TIM_ICInit( TIM2, &TIM_ICInitStruct );
    7 L3 R" G; |+ n
  40.         TIM_ICInit( TIM4, &TIM_ICInitStruct );1 Q  T0 k/ X0 B0 z+ y
  41.         - m! B# t2 }8 i! f0 J3 Z
  42.         /* 中断配置 */. q( V+ {: h: Z" U3 H+ O( j
  43.         TIM_ClearFlag( TIM2, TIM_IT_Update );
    ) Q5 ~( K, N" N( B+ D0 _" C6 u
  44.         TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE );
    ; }! y; t& x4 B. Q
  45.         TIM_ClearFlag( TIM4, TIM_IT_Update );
      Y) [& G9 N& w0 r
  46.         TIM_ITConfig( TIM4, TIM_IT_Update, ENABLE );
    # m0 i: V0 ]$ O' O5 t
  47.        
    ! I4 F, R7 C# q
  48.         /* 配置计数器的值 */
    7 w) a& l' W" _. s
  49.         TIM_SetCounter( TIM2, 0 );
    7 ]) Q# `5 I( W/ O: {/ e8 K
  50.         TIM_SetCounter( TIM2, 0 );
    # D: S5 a6 Q' c$ e- L, L( Y+ j1 v7 e
  51.        
    ! n: X/ O' @3 P3 F* J) y# C" H5 ]
  52.         /* 使能TIM */: B) j; V$ d+ G# p
  53.         TIM_Cmd( TIM2, ENABLE );
    + O- O( y' _" ^  d; x  o
  54.         TIM_Cmd( TIM4, ENABLE );
    0 m7 N* s: X7 v5 }& G
  55.        
    5 w8 p& w  O, N5 l
  56. }
    + Q( U  Z. x' E4 A  V. ]( f
  57. 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
  1. /* 读取编码器计数 */  Z' ]1 E! o  k; ^
  2. int Read_Encoder( uint8_t TIMx )
    / q: f4 e. D- L$ J# |5 d# A
  3. {
      l& Q& S1 M: ^8 g- u- l9 X
  4.         int Encoder;# h8 z3 \# s0 R( b% k2 G
  5.         /* 读取相应TIM的计数器值CNT,然后清零 */
    9 {! d$ `2 X1 |
  6.         switch(TIMx)- w, R. o3 |' l* N! U! E
  7.         {8 m; B* |% P! d2 J
  8.                 case 2:Encoder = (short)TIM2->CNT;TIM2->CNT=0;break;# y. P; z4 U  g( V- L5 o/ j# |
  9.                 case 4:Encoder = (short)TIM4->CNT;TIM4->CNT=0;break;
    7 Q4 f* ~" y& h! z8 T
  10.                 default:Encoder = 0;break;. h+ \% a+ F$ ~  F' E; ^6 S
  11.         }3 i+ a+ |/ c9 @1 ?
  12.         / j. B2 h- b+ |# m0 \6 c; C( z
  13.         return Encoder;4 a# S3 G0 i( N1 h
  14. }' c2 Q9 X# R( Q
复制代码
  X! F4 z: m. [
TIM2、TIM4中断程序& F3 Z: h, k: t* H1 J
  1. void TIM2_IRQHandler(void)
    0 U5 n0 l( |1 N+ q5 P
  2. {
    4 a* H0 [; D: D9 k, R( o& S/ _
  3.         /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。/ o# P" v6 l5 u' w! r- b" z
  4. 0:无输入捕获产生;
    : U0 l' ?" a: {
  5. 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */
    2 H4 _" {9 S, I0 H7 N5 J4 F) r
  6.         if( TIM2->SR&0x0001 )+ I6 r, u9 E; q7 h+ \4 ~
  7.                 ;: V9 x: n. A, E8 ^, E9 U( `7 Y% O
  8.         /* 清除中断标志位 */
    " W* d/ W, H* D  |8 j9 x
  9.         TIM2->SR&=~(1<<0);
    . @) s  X& ]) G" i* H
  10. }
    1 V# \2 a# a2 V* m) V" f  {
  11. ' I) F& Z+ u! \5 V$ Q# G

  12. 1 L' i! L& M. R  W0 U' G9 x

  13. 6 G9 [" z4 e# x, P3 _; m
  14. void TIM4_IRQHandler(void)
    . O5 m+ y. t$ ]! E' w! H: O  L
  15. {) L& E* `' Q/ _
  16.         /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。- k: S9 s% z& \- X# _
  17. 0:无输入捕获产生;2 Z7 i4 H6 x9 U& I) [7 M
  18. 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */$ G( k' ]7 q4 [4 {- X. p8 Z  W4 D
  19.         if( TIM4->SR&0x0001 )
    / L# C. P& \/ Y2 O
  20.                 ;
    6 g. }3 V% ^# I/ x( X7 q
  21.         /* 清除中断标志位 */1 `, u, F. Q( S# E
  22.         TIM4->SR&=~(1<<0);. U9 ~, ~" J! ]( U( a
  23. }" R$ U, ]! T  |5 h! p7 K8 a" T

  24. 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
  1. void TIM3_Int_Init(u16 arr,u16 psc)5 F* Q  e' M" D9 N+ O% U' _
  2. {+ ^2 E- O1 A1 h1 I# X% N
  3.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    ( C% F+ G8 Q2 b4 n( [/ x& T$ j
  4.         NVIC_InitTypeDef NVIC_InitStructure;" W9 W; D2 c' j* J3 ~7 n
  5. % g; t$ Y: ]; s, n( i
  6.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
    : Y' K/ I3 V; J0 W

  7. / L! l7 {. k: ^( Y
  8.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值         计数到5000为500ms
    . p8 V& y3 k3 S- k# S
  9.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  / r5 S1 r8 U7 D$ v/ j6 M0 T3 z; l* ]
  10.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim, Z+ g* O1 k! v
  11.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    , k9 Z; C. E, U$ a1 s- R
  12.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    8 j3 k: r: h( i0 W- G0 K* `
  13. 0 t# s! a) |4 b+ ]
  14.         TIM_ITConfig(  //使能或者失能指定的TIM中断- c3 s+ ]9 J1 q5 Z( F" N$ o
  15.                 TIM3, //TIM2
    ; Q- i3 `( L2 ]2 @* |
  16.                 TIM_IT_Update ,
    : F0 [0 G( Z* J) ~2 g5 g; i
  17.                 ENABLE  //使能
    0 Q4 O/ [/ o8 a/ P/ @* R
  18.                 );
    0 n" {9 u5 [. C$ P8 V
  19.         NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断8 v: w0 L+ ?; s) C
  20.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级9 H% _! O2 m; \
  21.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    , ]4 B0 S2 r" j! d% W; j. }
  22.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能( B, E9 J1 W) b0 n6 K
  23.         NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    : @1 v8 W  z/ c' X9 @

  24. + Y8 T- K- _' E) v4 M
  25.         TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设7 @7 s0 R8 p: c& f5 A9 L; `
  26.                                                          0 g* _5 H% B2 U! i" s$ Q( G
  27. }
    1 |8 l; h/ G/ Z# I
  28. void TIM3_IRQHandler(void)   //TIM3中断
    6 c* R+ b! y2 c/ L9 _' m
  29. {
      a" T0 k8 A4 @# J) q; p( }2 u
  30.         if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 % L& V( f+ w  Q# W- B8 b( c/ _
  31.                 {
    ( \/ _$ `7 A: x9 c
  32.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 3 T5 x3 {' e* ~
  33.                 Encoder_Left=(short)TIM2->CNT;
    0 V' e6 I1 C5 U& C6 D6 {
  34.                 TIM2->CNT=0;        3 ^# }! W' s+ O  W0 o. u# C
  35.                 }/ a# V- j$ m0 U8 F, H
  36. }
复制代码
  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 `
收藏 评论0 发布时间:2023-3-18 12:18

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版