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

【经验分享】STM32-增量式旋转编码器测量

[复制链接]
STMCU小助手 发布时间:2022-1-16 17:55
一、增量式旋转编码器1、简介
  • 编码器(encoder)是将信号(如比特流)或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。编码器把角位移或直线位移转换成电信号,前者称为码盘,后者称为码尺。
  • 按照读出方式编码器可以分为接触式和非接触式两种;
  • 按照工作原理编码器可分为增量式和绝对式两类。增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小。绝对式编码器的每一个位置对应一个确定的数字码,因此它的示值只与测量的起始和终止位置有关,而与测量的中间过程无关。 
  • 旋转编码器是集光机电技术于一体的速度位移传感器。它将被测的角位移直接转换成数字信号(高速脉冲信号)。
  • 我们通常用的是增量型编码器,可将旋转编码器的输出脉冲信号直接输入给PLC,利用PLC的高速计数器对其脉冲信号进行计数,以获得测量结果。不同型号的旋转编码器,其输出脉冲的相数也不同,有的旋转编码器输出A、B、Z三相脉冲,有的只有A、B相两相,最简单的只有A相。A、B为相差90度的脉冲,Z相信号在编码器旋转一圈只有一个脉冲,通常用来做零点的依据,连接时要注意PLC输入的响应时间。旋转编码器还有一条屏蔽线,使用时要将屏蔽线接地,提高抗干扰性。
  • 信号输出有正弦波(电流或电压),方波(TTL、HTL),集电极开路(PNP、NPN),推拉式多种形式,其中TTL为长线差分驱动(对称A,A-;B,B-;Z,Z-),HTL也称推拉式、推挽式输出,编码器的信号接收设备接口应与编码器对应。信号连接—编码器的脉冲信号一般连接计数器、PLC、计算机,PLC和计算机连接的模块有低速模块与高速模块之分,开关频率有低有高。如单相联接,用于单方向计数,单方向测速。A.B两相联接,用于正反向计数、判断正反向和测速。A、B、Z三相联接,用于带参考位修正的位置测量。A、A-,B、B-,Z、Z-连接,由于带有对称负信号的连接,在后续的差分输入电路中,将共模噪声抑制,只取有用的差模信号,因此其抗干扰能力强,可传输较远的距离。对于TTL的带有对称负信号输出的编码器,信号传输距离可达150米。
  • 线数:旋转一周信号线输出脉冲数,也成为分辨率
    9 O, W1 c. M' T3 `( w5 }- H0 U
  •   E5 L( V* {+ Y" x! N7 [  S

    ) n8 |5 r4 \! |3 z. v
1248164-20180510192503629-93708335.png
6 O2 @6 _3 |4 e$ a3 p2 ]
1248164-20180510195028614-102457577.png
2、型号
此篇文章使用的旋转编码器型号有两种。
传感器(增量式旋转编码器)

7 }& _+ F" X) k3 A8 N
型号
供电电压
输出方式
分辨率
品牌/厂家
输出电平
S20-1000型拉线位移传感器
5-24V
NPN集电极开路
400
Omron/欧姆龙
* o+ P0 e0 l0 t2 U* {
DT100E40R1024-HI
增量型大孔径编码器
5-30V
HTL(推挽式)
1024
冬莅自动化技术(上海)有限公司
www.shdongli.cn
高:VCC*70%
低:1V

% m* ]3 D) h! q( L1 O7 ~

  G( @+ G5 u. m' ^0 a" h6 `' {二、硬件设计
  由于增量型编码器输出脉冲,可以直接接入PLC单片机,利用PLC高速计数器进行测量。将编码器接入STM32单片机需要一个定时器资源,并将定时器配置为编码器模式,稍后会简要介绍配置方法。根据传感器的输出方式,进而来判断是否需要进行信号预处理。对于集电极开路输出的传感器接入必须使用上拉电阻。注意STM32大多数引脚的输入电压都在3.3V左右,尽量不要过压。如果电压较大,最好加隔离电路,比如6N136光耦,类似下图

9 |' c& p. }( {+ }) b
1248164-20180510200405732-66175176.png
/ J- M) k8 w& t) i. y
  我在这里并没有使用隔离电路,而是对传感器统一使用了5V供电,并在信号接入端人为加了3.3V上拉(上拉电阻1K),这种接口电路在我自己设计的采集板上统一留出了8个。编码器应用中并未使用Z相,仅使用了A、B两相进行编码器计数。按照线序说明接入STM32的定时器引脚,PA6、PA7对应TIM3的CH1、CH2通道,PB6、PB7对应TIM4的CH1、CH2通道。对于第二种传感器的推挽输出方式而言,实验证明这种接入电路也是可行的。(具体电路没有进行分析,只是图个方便。但是5*70%=3.5V应该是勉强可以直接接入stm32引脚的)
5 z- Q7 A! i9 ]! Y1 C$ C8 b! z2 O
1248164-20180510202458411-1027273337.png
) S4 A) y2 |) g, d
三、软件设计1、STM32定时器编码器模式简介
  参考官方文档,摘录几个要点:
  • 编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。
  • 两个输入TI1和TI2被用来最为增量编码器的接口,TI1FP1和TI2FP2是TI1和TI2在通过滤波器和极性控制后的信号,计数器由每次在TI1FP1和TI2FP2的有效跳变驱动,根据跳变顺序,产生计数脉冲和方向信号,计数器向上或向下计数,同时硬件对TIMx_CR1寄存器的DIR位进行相应设计
  • IC1、TI1概念理解:TI1是定时器输入通道,IC1是输入捕获通道(两者可以交错)。配置CCMR1寄存器的CC1S位可以指定IC1的映射方式。可配置滤波器和预分频器。1 l& H- @9 v4 q( |! T5 S- d

    , u: o3 d" a0 [, L2 w

' a$ i( b+ V# O+ H6 b" U. ]
1248164-20180510211213519-2095565993.png

5 A3 D! _' Y* t5 \& e) }
1248164-20180510210619647-836174267.png
) p9 F2 V: I5 [& `% ~
  • 计数方向与编码器信号的关系" {5 {4 j3 |$ f: W5 y

    0 C% j7 H7 R, t% ~1 D- t% O. z

9 g: _0 Q4 p7 n: |1 N
% N' I. |- g: ^" o$ j1 n' Z2 b
1248164-20180510211455433-476773874.png
5 E/ e1 t, _% j3 f1 o2 \! d" O4 \* ?4 Z" u

; |! R- Q/ A( V5 V6 ^$ _
2、软件实现
  1. 1 /********************************************
    ( U* u% r/ N8 V1 W2 S2 M! A
  2.   2 $ }8 w2 h0 Y- D7 n9 n* d/ }- x
  3.   3 TIM3、TIM4定时器编码器模式配置/ b2 P4 D, X% ?+ }
  4.   4
    . a+ Y, T2 R' E! h  k
  5.   5 *********************************************/
    2 N: o" ^* U7 |# T! x
  6.   6
    , p2 i8 I% ], Y8 j2 @1 |
  7.   7 #include "sys.h"
    + G0 U* b' m( c
  8.   8 #include "encoder.h"
    5 u0 J7 m0 A) C6 S1 W' v- W  m
  9.   9 $ H, n2 [! o8 ~( H; }4 v2 h: p0 p9 r
  10. 10 int TIM3ITCount=0;//中断溢出次数
    % k9 U0 m- N; R/ ^
  11. 11 int TIM4ITCount=0;//中断溢出次数# c. C  |4 t8 ~
  12. 12
    # j4 w5 v0 H6 H* K) L
  13. 13 void TIM3_IRQHandler(void)
    8 I# M: {" R# F/ Q1 {
  14. 14 {   3 }* V& [! ?) Z0 c# O/ M8 P
  15. 15     if(TIM3->SR&0x0001)//溢出中断
    - i1 Y* d+ r- E% Z  O7 ?( c
  16. 16     {# O# J7 M2 @3 K  O$ j( f2 r$ ~2 E: @
  17. 17         
    . L4 V6 T- B' L( I; S5 V
  18. 18     }   + u# D8 g# z5 [) c8 w6 _, y# C
  19. 19     TIM3->SR&=~(1<<0);//清除标志位   
    # N0 H! q7 }+ v: I4 `4 {
  20. 20 }. M  Z8 [; u0 K) k4 W- L  [4 i2 q
  21. 21 . o) \7 I, z1 \+ X' v8 C
  22. 22 void TIM4_IRQHandler(void)
    : }+ \' o1 s" L6 Z
  23. 23 {   
    " p% G  r9 H1 a9 [9 ~, c
  24. 24     if(TIM4->SR&0x0001)//溢出中断) t/ g5 z7 b2 j) a! V; j
  25. 25     {7 @; L& s: y4 D, _; w( t2 \
  26. 26     }   ! B: f6 f, I4 X
  27. 27     TIM4->SR&=~(1<<0);//清除标志位      U9 U" G' ^: _: l: I) E
  28. 28 }3 H5 @' E4 `9 h! n2 N! p# ~
  29. 29 4 @7 j. N+ w* |1 I" s2 N
  30. 30 void TIM3_Encoder_Init()- o1 H! l/ T5 Y. U! `3 Z
  31. 31 {! n& M" s+ V, M! s* \* @7 r' }/ v
  32. 32     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    & g' G! h: X+ H8 O( J  q; p
  33. 33     TIM_ICInitTypeDef TIM_ICInitStructure;9 d3 v3 R1 q  C) U! U! H
  34. 34     GPIO_InitTypeDef GPIO_InitStructure;
    3 x0 s# O# u  j0 p4 g
  35. 35     NVIC_InitTypeDef NVIC_InitStructure;5 o5 y2 B3 g" f9 {9 D
  36. 36     
    * S% l6 H. u* V0 |+ c4 r
  37. 37     //时钟使能9 K6 `  }) ^. s$ N+ U% J
  38. 38     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  //使能 TIM3 时钟
    0 n* |6 P- H* c8 V, Z* I3 n) q% D5 Z
  39. 39     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA 时钟
    : Y+ e2 E/ v& g- w" k* h
  40. 40     - F2 B/ h$ h: L9 L8 Q- T$ M; `( }
  41. 41     //GPIO配置& U. {& l. h+ N. O) j
  42. 42     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //PA6、PA7设置
    & g5 W" V, D' ?- P
  43. 43     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    4 ?) P) [" Q, C9 r2 [
  44. 44     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  ]5 S7 Y. d2 i" N& `6 L
  45. 45     GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA2 d$ [8 a9 Z4 l% Y# o5 N1 A
  46. 46     * j& {6 @, `. o  T; A5 [
  47. 47     //定时器初始化
      K3 n  b/ H6 m% O, C3 v/ L1 z* P: }, B
  48. 48     TIM_DeInit(TIM3);  w$ n9 b) j" q% ]  A0 s
  49. 49     TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);( z% A# E, I8 P8 ^- ^6 X: O
  50. 50     TIM_TimeBaseStructure.TIM_Period =65535;//预装载值+ U+ u4 o& h) q- O$ x
  51. 51     TIM_TimeBaseStructure.TIM_Prescaler = 0;//预分频
    % q9 |! R2 ]9 @0 `, t9 R& w1 Q
  52. 52     TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;
    - k7 P" H- c$ q5 F( \* b. |+ k( C
  53. 53     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    ) Q; c% }- |& Y4 G2 `. G& |$ H  |
  54. 54     TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    7 K' ~7 T! q' F* s8 \! u' U; ]
  55. 55     0 L0 K  {. j% g5 ^$ R, c  K
  56. 56     //编码器模式配置
    ( h1 q8 |6 `: l6 F! R
  57. 57     TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);
    : \7 p" Y$ q6 t0 |3 C
  58. 58     TIM_ICStructInit(&TIM_ICInitStructure);
    # N# V0 C$ J: U/ C5 E
  59. 59     TIM_ICInitStructure.TIM_ICFilter = 6;//ICx_FILTER;8 _+ b. n. f5 o2 f: e
  60. 60     TIM_ICInit(TIM3, &TIM_ICInitStructure);% Y$ H% V: Z! a) S4 d1 C
  61. 61     
    ' y% u, n* C+ Q( f- A8 E( _
  62. 62     //初始化 NVIC 中断优先级分组- a# q0 _4 H: N# V9 z: Q' f  s# ^; R
  63. 63     NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 中断1 h; Z; M/ B, j/ J. x. m) O
  64. 64     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级 2 级
    $ E* o3 ]' a; }5 b' H
  65. 65     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级 0 级5 }8 ?+ E5 r+ u" y( \" Z; T, l
  66. 66     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能1 }, A  M$ f# X, j1 \
  67. 67     NVIC_Init(&NVIC_InitStructure); //初始化 NVIC
    5 U3 m: x8 ^  U' ~) p0 M
  68. 68     
    ( B+ ]; S, f3 H/ k  j) w* g
  69. 69     //中断配置
    + M9 F4 b) b  l$ e" D2 `
  70. 70     TIM_ClearFlag(TIM3, TIM_FLAG_Update);
    ' B8 a8 _& ^+ e# P0 z& S- s
  71. 71     TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
    9 g! g! w. v3 k5 ]
  72. 72     
    ! Y- t; @1 Y! x
  73. 73     //Reset counter
    # w( y6 e: L# r) @1 G4 n
  74. 74     TIM3->CNT = 0;
    ' P5 |; {  ^8 T3 t; e* o2 T
  75. 75     //使能定时器
    4 P/ `1 ^% O: z, m
  76. 76     TIM_Cmd(TIM3, ENABLE);   
    ! I+ l1 @* S% m. t0 T4 K/ Q
  77. 77 }
    ( W8 n5 X3 N5 S- s
  78. 78
    9 h/ P3 s1 f% C; L
  79. 79 void TIM4_Encoder_Init()0 w- Q7 G; @; f  \7 Z  I* ?" E3 f0 a
  80. 80 {
    , I$ d. `) N! y
  81. 81     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;( }" z0 l6 c+ K- X6 j
  82. 82     TIM_ICInitTypeDef TIM_ICInitStructure;
    1 n+ d* a0 N8 K3 ^- B& {7 l
  83. 83     GPIO_InitTypeDef GPIO_InitStructure;
    / c) @0 k! A/ p  l8 \* W# O6 B
  84. 84     NVIC_InitTypeDef NVIC_InitStructure;, o9 D4 |/ }0 R6 |
  85. 85     
    9 q& E  i0 T( k# ~
  86. 86     //时钟使能3 o0 \  q+ ~, N4 `
  87. 87     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);  //使能 TIM4 时钟
    , A, l5 Y: e; n2 z
  88. 88     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能 GPIOB 时钟
    - Q7 `: V  E9 L
  89. 89       k9 X9 _* c% Q7 m. _, R$ ]6 U0 D
  90. 90     //GPIO配置1 i# R5 q/ w- F
  91. 91     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //PB6、PB7设置
    # f0 q) [% Y% a2 E: Y- v
  92. 92     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    * z% x  `/ X; w
  93. 93     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    6 `9 _1 I7 M9 X) e
  94. 94     GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化 GPIOA7 n  w& y6 {  h; Y  }. _& k
  95. 95     8 ]+ N8 J& x0 M- {3 U
  96. 96     //定时器初始化
    2 [) }4 Q) U5 P$ j* Q
  97. 97     TIM_DeInit(TIM4);
    ! r- M3 v1 C. E
  98. 98     TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    - g4 i% ^" z1 ?; s1 M, R) B
  99. 99     TIM_TimeBaseStructure.TIM_Period =65535;//预装载值
    & C6 f8 B7 [6 E# J( O% F6 G% c
  100. 100     TIM_TimeBaseStructure.TIM_Prescaler = 0;//预分频
    2 r7 r4 _. f  v& {; s5 C  N! A% _
  101. 101     TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;9 _+ l8 [3 Q9 d0 `- C
  102. 102     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    , r6 y: X# \9 R+ j# K# w) @
  103. 103     TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); / E4 @: r' x( ?) u/ L% W* v
  104. 104     
    2 R0 f/ q7 f' Y3 c5 F7 |5 T
  105. 105     //编码器模式配置9 q  Q; {5 z1 m4 t; _) G
  106. 106     TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);4 f* ^2 J9 P3 I- ~
  107. 107     TIM_ICStructInit(&TIM_ICInitStructure);
    ; ^$ e4 I& {9 C* j0 G: X
  108. 108     TIM_ICInitStructure.TIM_ICFilter = 6;//ICx_FILTER;+ l6 v; F7 Z6 W. [
  109. 109     TIM_ICInit(TIM4, &TIM_ICInitStructure);+ f$ Z+ I& J  w4 y
  110. 110     $ j+ U* q: Q: t- V, S
  111. 111     //初始化 NVIC 中断优先级分组) b& K5 }  h& ^# p1 w
  112. 112     NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM4 中断& y1 E- i1 Y0 T, Q* Z! R* i$ H5 {
  113. 113     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级 2 级
    & R( L" n& q& H3 y( A& O; L1 J
  114. 114     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级 0 级* |2 ^6 Q4 H; l( e7 [/ ~+ U/ D
  115. 115     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
    ' Y: o9 U* P7 A/ c
  116. 116     NVIC_Init(&NVIC_InitStructure); //初始化 NVIC2 r) ~: U; R3 A: S2 ]
  117. 117     ; \' D/ ]5 |9 o& Y6 \) C
  118. 118     //中断配置1 Q, H* t. R- S& {, k; A& b8 i
  119. 119     TIM_ClearFlag(TIM4, TIM_FLAG_Update);4 u% ^9 o4 R7 S5 b8 E( W
  120. 120     TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);& w" P2 O/ A/ U  l. v! [8 {
  121. 121     : `+ l1 g0 m; a% {/ W- G
  122. 122     //Reset counter; i% a0 h) E+ D6 M  d* S% a8 y
  123. 123     TIM4->CNT = 0;5 ?) E$ T0 T1 \- f" Q
  124. 124     //使能定时器+ a# \& D" j& o9 N/ O
  125. 125     TIM_Cmd(TIM4, ENABLE);   
      @4 T) m4 S+ Z( |# I
  126. 126 }
    8 v1 h6 X9 v. G
  127. 9 X( ~& {& T* `7 w: V
  128. encoder.c
复制代码
8 n3 J8 z* ]1 Q1 f) ?9 U

" Y0 G. E7 J' y8 {* r& t3、注意事项
  • 更新中断可以不开。但是由于没有使用Z相信号,所以这里保留更新中断,实际上目前中断里什么也没做
  • 由于是双相下降沿计数,所以转一次会输出两个脉冲,转一周脉冲数为分辨率*2,注意处理。当然你也可以配置为其它计数倍数
  • 这里预装载65535,可改为线数*2,即可对转一周的位置进行严格编码
  • TIMx->CNT的值即为编码器的位置(并不一定是输出脉冲值,跟旋转方向和预装载值有关,增量编码器的零点是初始化自己定义的)
  • GPIO配置为浮空输入模式。对于集电极开路输出的编码器,如果你没有外部上拉,则使用内部上拉,配置为上拉输入模式即可。, J* R. w3 I+ S; |. _" [
    - S' b6 \4 K) F: }7 t

! x0 T- j9 ^8 `; w9 ]
/ @1 b' f& H& d7 N" Q* W0 h$ A
赞 收藏 评论0 发布时间:2022-1-16 17:55

举报

0个回答

所属标签

相似技术帖

官网相关资源

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