风筝
发表于: 2018-11-20 20:28:18 | 显示全部楼层

在本篇文章中,我们将学习旋转编码器的工作原理以及如何将其与Arduino开发板一起使用。旋转编码器是一种位置传感器,用于确定旋转轴的角度位置。它根据旋转运动产生模拟或数字电信号。

Rotary-Encoder-Module-300x286.jpg

有许多不同类型的旋转编码器,可通过输出信号或传感技术进行分类。在本篇文章中,我们使用的特定旋转编码器是增量式旋转编码器,它是测量旋转的最简单的位置传感器。

Rotary-Encoders-Classification.png


该旋转编码器也称为正交编码器或相对旋转编码器,其输出是一系列方波脉冲。


旋转编码器的工作原理

让我们详细了解编码器,看看它的工作原理。以下是方波脉冲的产生方式:编码器有一个带有均匀间隔的接触区的磁盘,它们连接到公共引脚C和另外两个独立的接触引脚A和B,如下图所示。

Rotary-Encoder-How-It-Works-Working-Principle.png

当磁盘逐步开始旋转时,引脚A和B将开始与公共引脚接触,并相应地产生两个方波输出信号。


如果我们只计算信号的脉冲,则可以使用两个输出中的任何一个来确定旋转位置。但是,如果我们想要确定旋转方向,我们需要同时考虑两个信号。


我们可以注意到两个输出信号相互错开了90度。如果编码器顺时针旋转,则输出A将在输出B之前。

Rotary-Encoder-Output-Signal-Working-Principle-Photo-.png


因此,如果我们计算每次信号变化时的步数,从高到低或从低到高,我们可以注意到那时两个输出信号具有相反的值。反之亦然,如果编码器逆时针旋转,则输出信号具有相等的值。因此,考虑到这一点,我们可以轻松地对控制器进行编程,以读取编码器位置和旋转方向。


旋转编码器Arduino示例

让我们用Arduino开发板做一个实际的例子吧。我将用于此示例的特定模块位于分线板上,它有五个引脚。第一个引脚是输出A,第二个引脚是输出B,第三个引脚是Button引脚,当然另外两个引脚是VCC和GND引脚。

Rotary-Encoder-Arduino-Tutorial-Example.jpg

我们可以将输出引脚连接到Arduino开发板的任何数字引脚。


本篇文章所需的组件如下所示:

●    旋转编码器模块

●    Arduino开发板

●    面包板和跳线


源代码

以下是该示例的Arduino代码:

  1. #define outputA 6
  2. #define outputB 7
  3. int counter = 0;
  4. int aState;
  5. int aLastState;  
  6. void setup() {
  7.    pinMode (outputA,INPUT);
  8.    pinMode (outputB,INPUT);
  9.    
  10.    Serial.begin (9600);
  11.    // Reads the initial state of the outputA
  12.    aLastState = digitalRead(outputA);   
  13. }
  14. void loop() {
  15.    aState = digitalRead(outputA); // Reads the "current" state of the outputA
  16.    // If the previous and the current state of the outputA are different, that means a Pulse has occured
  17.    if (aState != aLastState){     
  18.      // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
  19.      if (digitalRead(outputB) != aState) {
  20.        counter ++;
  21.      } else {
  22.        counter --;
  23.      }
  24.      Serial.print("Position: ");
  25.      Serial.println(counter);
  26.    }
  27.    aLastState = aState; // Updates the previous state of the outputA with the current state
  28. }
复制代码

代码描述:首先,我们需要定义编码器所连接的引脚,并定义程序所需的一些变量。在setup()函数部分,我们需要将两个引脚定义为输入,启动串行通信以在串行监视器上打印结果,以及读取输出A的初始值并将值放入变量aLastState中。


然后在loop()函数部分我们再次读取输出A,但现在我们将值放入aState变量。因此,如果我们旋转编码器并生成脉冲,则这两个值将不同,并且第一个“if”语句将变为true。在那之后使用第二个“if”语句,我们确定旋转方向。如果输出B状态与输出A状态不同,则计数器将增加1,否则它将减小。最后,在串行监视器上打印结果后,我们需要使用aState变量更新aLastState变量。


这就是我们在这个例子中所需要的一切。如果上传代码,启动串行监视器并开始旋转编码器,我们将开始获取串行监视器中的值。我拥有的特定模块每个完整周期计数30个。


示例2 - 使用旋转编码器控制步进电机

除了这个基本示例之外,我再举一个使用旋转编码器控制步进电机位置的例子。


Controlling-a-stepper-motor-using-a-Rotary-Encoder.jpg


以下是该示例的Arduino代码:

  1. #include <LiquidCrystal.h> // includes the LiquidCrystal Library
  2. LiquidCrystal lcd(1, 2, 4, 5, 6, 7); // Creates an LC object. Parameters: (rs, enable, d4, d5, d6, d7)
  3. // defines pins numbers
  4. #define stepPin 8
  5. #define dirPin  9
  6. #define outputA 10
  7. #define outputB 11
  8. int counter = 0;
  9. int angle = 0;
  10. int aState;
  11. int aLastState;  

  12. void setup() {
  13.   // Sets the two pins as Outputs
  14.   pinMode(stepPin,OUTPUT);
  15.   pinMode(dirPin,OUTPUT);
  16.   pinMode (outputA,INPUT);
  17.   pinMode (outputB,INPUT);
  18.   
  19.   aLastState = digitalRead(outputA);
  20.   lcd.begin(16,2); // Initializes the interface to the LCD screen, and specifies the dimensions (width and height) of the display }
  21. }
  22. void loop() {
  23.   aState = digitalRead(outputA);
  24.   
  25.   if (aState != aLastState){     
  26.      if (digitalRead(outputB) != aState) {
  27.        counter ++;
  28.        angle ++;
  29.        rotateCW();  
  30.      }
  31.      else {
  32.        counter--;
  33.        angle --;
  34.        rotateCCW();
  35.      }
  36.      if (counter >=30 ) {
  37.       counter =0;
  38.      }
  39.      
  40.      lcd.clear();
  41.      lcd.print("Position: ");
  42.      lcd.print(int(angle*(-1.8)));
  43.      lcd.print("deg");
  44.      lcd.setCursor(0,0);
  45.      
  46.    }
  47.   aLastState = aState;
  48. }
  49. void rotateCW() {
  50.   digitalWrite(dirPin,LOW);
  51.     digitalWrite(stepPin,HIGH);
  52.     delayMicroseconds(2000);
  53.     digitalWrite(stepPin,LOW);
  54.     delayMicroseconds(2000);
  55. }
  56. void rotateCCW() {
  57.   digitalWrite(dirPin,HIGH);
  58.     digitalWrite(stepPin,HIGH);
  59.     delayMicroseconds(2000);
  60.     digitalWrite(stepPin,LOW);
  61.     delayMicroseconds(2000);   
  62. }
复制代码

以上就是本篇文章的全部内容,如果遇到任何问题,请随时在本帖下面进行回复。

跳转到指定楼层
gzpenglin
发表于: 2021-11-6 17:48:54 | 显示全部楼层

感谢楼主分享!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 700 | 回复: 1479



手机版|

GMT+8, 2024-3-29 20:30 , Processed in 0.121281 second(s), 8 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表