使用Arduino 连接旋转编码器
时间:2022-09-29 09:30:00
文章目录
-
- 1. 所需的材料
- 2. 连接导线旋转编码器是如何工作的?
- 3. 旋转编码器的类型
- 4. KY-040旋转编码器引脚和说明
- 5. Arduino连接到旋转编码器的电路图
- 6. 为旋转编码器编写的编写Arduino程序
-
- 7.3 完整代码
- 8. 补充其他网民的代码
参考资料:https://www.arduino.cn/thread-2423-1-1.html
1. 所需的材料
- 旋转编码器(KY-040)
- Arduino UNO开发板
- 液晶1602
- 电位器10k
- 面包板
2. 如何连接导线旋转编码器?
旋转编码器是一种机电换能器,这意味着它将机械运动转化为电子脉冲。它由旋钮组成。旋转时,旋钮将逐渐移动并产生一系列脉冲序列,每个步骤都有预定的宽度。编码器有很多种,每个编码器都有自己的工作机制。稍后我们将了解这些类型,但现在我们只关注它们KY由于我们在我们的教程中使用了040增量编码器。
编码器的内部机械结构如下所示。它基本上由圆盘(灰色)和放置在圆盘顶部的导电垫(铜色)组成。这些导电焊盘放置在相同的距离,如下所示。输出引脚固定在圆盘顶部,当旋钮旋转时,导电垫与输出引脚接触。有两个输出引脚,输出A和输出B,如下图所示。
输出引脚A和输出B产生的输出波分别显示为蓝色和绿色。当导电焊盘直接位于引脚下时,它会变得更高,导致导电时间。当导电焊盘移动时,引脚会变低,导致上述波形的关闭时间。现在,如果我们计算脉冲数,我们将能够确定编码器移动了多少步。
当脉冲信号足以计算旋转旋钮时,为什么我们需要两个脉冲信号?这是因为我们需要确定旋钮的旋转方向。如果你看看这两个脉冲,你会注意到它们都是90°异相。因此,当顺时针旋转旋钮时,输出A将首先变高,当旋钮逆时针旋转时,输出B将首先变高。
3. 旋转编码器的类型
市场上有许多类型的旋转编码器,设计工程师可以根据自己的应用程序选择一个。最常见的类型如下所示
- 增量编码器
- 绝对值编码器
- 磁编码器
- 光学编码器
- 激光编码器
这些编码器是基于输出信号和传感技术,增量编码器和绝对值编码器是基于输出信号,磁性、光和激光编码器是基于传感技术。这里使用的编码器是增量编码器。
4. KY-040旋转编码器的引脚和说明
KY-如下所示
前两个引脚(接地和Vcc)通常用于为编码器供电 5V电源。编码器除了顺时针和逆时针旋转旋钮外,还有一个开关(低电平有效),可以按下内部旋钮。通过引脚3(Switch)获得。最后,它有两个输出引脚,产生上述波形。现在让我们学习如何与我们一起学习Arduino进行连接。
5. Arduino连接到旋转编码器的电路图
旋转编码器和Arduino如下图所示
旋转编码器有5个引脚,如上图标签所示。前两个引脚是接地和Vcc,它连接到Arduino的地和 5V引脚。编码器的开关连接到数字引脚D8,并通过1k电阻拉高。两个输出引脚分别连接到D9和D8。
通过旋转显示Rotary我们需要一个显示模块来增加或减少编码器的变量值。这里常用的字符图形点阵液晶1602。我们将连接的显示屏设置为4位工作模式,并使用它Arduino的 5V引脚供电。电位计用于调整LCD显示屏的对比度。面包板上可以搭建完整的电路,一旦完成所有连接,效果看起来像下图。
由于单片机内部电阻大,使用单片机内部的上拉输入可能会带来更大的功耗,arduino已知每圈脉冲数为2500的基本原理是,当计数大道2500时,计数一圈,如果是stm三十二是溢出中断。A、B判断相的高低电平关系AB相的先后关系,进而判断转向。
通常有三个部分可以区分正反转和检测零点:A相,B相和Z相,A与B相差1/4周期(相位差90度),可用于区分正转或反转;Z与单圈脉冲相比,码盘可以作为编码器的参考部分,如下图所示:
6. 为旋转编码器编写的编写Arduino程序
如果您了解旋转编码器的工作原理,编程Arduino开发板很容易连接到旋转编码器。我们只需要读取脉冲数来确定编码器的旋转数,并首先检查哪个脉冲高,以找到编码器旋转的方向。在本文中,我们将在LCD第一行显示增减数字,第二行显示编码器方向。
因为我们用了一个LCD所以包含了显示屏Arduino IDE默认存在的液晶库。然后我们将其定义为连接LCD和Arduino引脚。最后,我们将这些引脚初始化LCD显示屏。
#include //Default Arduino LCD Library is included const int rs = 7, en = 6, d4 = 5, d5 = 4, d6 = 3, d7 = 2; //Mention the pin number for LCD connection
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
lcd.begin(16, 2); //Initialise 16*2 LCD
接下来在setup函数中,我们在LCD屏幕上显示介绍消息,然后等待2秒钟,以便用户可以读完该消息。这是为了确保LCD能够正常工作。
lcd.print(" Rotary Encoder "); //Intro Message line 1
lcd.setCursor(0, 1);
lcd.print(" With Arduino "); //Intro Message line 2
delay(2000);
lcd.clear();
Rotary编码器有三个输出引脚,对于Arduino来说,它们都是INPUT引脚。这三个引脚分别是开关(Switch)、输出A(Output A)和输出B(Output B)。这些引脚使用pinMode函数声明为Input,如下所示。
//pin Mode declaration
pinMode (Encoder_OuputA, INPUT);
pinMode (Encoder_OuputB, INPUT);
pinMode (Encoder_Switch, INPUT);
在void setup()函数中,我们读取输出A引脚的状态以检查引脚的最后状态。然后,我们将使用此信息与新值进行比较,以检查哪个引脚(输出A或输出B)变高。
Previous_Output = digitalRead(Encoder_OuputA); //Read the inital value of Output A
最后在loop函数内,我们必须将输出A和输出B的值与先前输出进行比较,以检查哪一个先变高。这可以通过简单地将A和B的当前输出值与先前输出进行比较来完成,如下所示。
if (digitalRead(Encoder_OuputA) != Previous_Output)
{
if (digitalRead(Encoder_OuputB) != Previous_Output)
{
Encoder_Count ++;
lcd.clear();
lcd.print(Encoder_Count);
lcd.setCursor(0, 1);
lcd.print("Clockwise");
}
在上面的代码中,如果输出B已从先前的输出改变,则执行第二个if条件。在这种情况下,编码器变量的值递增,LCD显示编码器以顺时针方向旋转。类似地,如果if条件不符合,则在随后的其他条件中,我们递减变量并显示编码器沿逆时针方向旋转。代码如下所示。
else
{
Encoder_Count--;
lcd.clear();
lcd.print(Encoder_Count);
lcd.setCursor(0, 1);
lcd.print("Anti - Clockwise");
}
}
最后,在loop函数结束时,我们必须使用当前输出值更新先前的输出值,以便可以使用相同的逻辑重复循环。
Previous_Output = digitalRead(Encoder_OuputA);
另一个可选方法是检查编码器上的开关是否被按下。这可以通过检查旋转编码器上的开关销来监控。该引脚是低电平有效引脚,意味着按下该按钮时它将变为低电平。如果没有按下引脚保持高电平,我们也使用了一个上拉电阻,以确保在未按下开关时保持高电平,从而避免浮空状态。
if (digitalRead(Encoder_Switch) == 0)
{
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Switch pressed");
}
Arduino控制旋转编码器的工作过程
一旦硬件和代码准备就绪,只需将代码上传到Arduino开发板板,然后向Arduino供电。您可以通过USB电缆为其供电,也可以使用12V适配器。上电时,LCD应显示介绍消息,然后变为空白。现在旋转旋转编码器,您应该看到值根据旋转方向递增或递减。第二行将显示编码器是以顺时针方向还是逆时针方向旋转。下图显示了实际的工作过程:
此外,当按下按钮时,第二行将显示按下按钮。这只是一个旋转编码器与Arduino连接的示例程序,检查它是否按预期工作。现在,您应该可以将编码器用于任何项目并进行相应的编程。
7.3 完整代码
/* Interfacing Rotary Encoder with Arduino Power LCD and Rotary encoder from the +5V pin of Arduino LCD RS -> pin 7 LCD EN -> pin 6 LCD D4 -> pin 5 LCD D5 -> pin 4 LCD D6 -> pin 3 LCD D7 -> pin 2 Encoder Switch -> pin 10 Encoder Output A -> pin 9 Encoder Output B -> pin 8 */
int Encoder_OuputA = 9;
int Encoder_OuputB = 8;
int Encoder_Switch = 10;
int Previous_Output;
int Encoder_Count;
#include //Default Arduino LCD Librarey is included
const int rs = 7, en = 6, d4 = 5, d5 = 4, d6 = 3, d7 = 2; //Mention the pin number for LCD connection
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
lcd.begin(16, 2); //Initialise 16*2 LCD
lcd.print(" Rotary Encoder "); //Intro Message line 1
lcd.setCursor(0, 1);
lcd.print(" With Arduino "); //Intro Message line 2
delay(2000);
lcd.clear();
//pin Mode declaration
pinMode (Encoder_OuputA, INPUT);
pinMode (Encoder_OuputB, INPUT);
pinMode (Encoder_Switch, INPUT);
Previous_Output = digitalRead(Encoder_OuputA); //Read the inital value of Output A
}
void loop() {
//aVal = digitalRead(pinA);
if (digitalRead(Encoder_OuputA) != Previous_Output)
{
if (digitalRead(Encoder_OuputB) != Previous_Output)
{
Encoder_Count ++;
lcd.clear();
lcd.print(Encoder_Count);
lcd.setCursor(0, 1);
lcd.print("Clockwise");
}
else
{
Encoder_Count--;
lcd.clear();
lcd.print(Encoder_Count);
lcd.setCursor(0, 1);
lcd.print("Anti - Clockwise");
}
}
Previous_Output = digitalRead(Encoder_OuputA);
if (digitalRead(Encoder_Switch) == 0)
{
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Switch pressed");
}
}
8. 补充其他的网友的代码
#define PinA 2 //外部中断0 #define PinZ 3 //外部中断1 #define PinB 8 //编码器的OUT_B信号连接到数字端口8 //变量初始化 unsigned long time1 = 0; // 时间标记 float time_cw; float time_ccw; long count = 0; const float d = 75.7 / 1000; //轮子的直径 const float pi = 3.141592654;//圆周率 int num = 0;//圈数 double t;//一圈的运动时间 float velocity; double time3;//外部中断1产生时的时间,即捕捉到Z相的置零信号时,用于在loop循环内进行一圈时间长短的计算 void setup() { pinMode(PinA, INPUT_PULLUP);//因为编码器信号为
欧姆龙E6B2-CWZ6C,为开漏输出,因此需要上拉电阻,此处采用arduino的内部上拉输入模式,置高 pinMode(PinB, INPUT_PULLUP);//同上 pinMode(PinZ, INPUT_PULLUP);//同上 attachInterrupt(0, Encode, FALLING);//脉冲中断函数:捕捉A相信号,并判断A、B相先后顺序 attachInterrupt(1, Set_state , FALLING);//用于在捕捉到Z的零信号时,进行状态置零 Serial.begin (9600); } void loop() { double distance; //正转 if (count == 2500) { // Serial.println("ok");//调试用 num = num + 1; time_cw = millis(); t = time_cw - time3; t = t / 1000; distance = num * d * pi; velocity = d * pi / t; Serial.print("The wheel has run "); Serial.print(distance); Serial.println("m."); Serial.print("The cw_speed is "); Serial.print(velocity); Serial.println("m/s."); Serial.print("The time is "); Serial.print(t); Serial.println("s."); } //反转 if (count == -2500) { // Serial.println("ok");//调试用 num = num + 1; time_ccw = millis(); t = time_ccw - time3; t = t / 1000; distance = num * d * pi; velocity = d * pi / t; Serial.print("The wheel has run "); Serial.print(distance); Serial.println("m."); Serial.print("The ccw_speed is "); Serial.print(velocity); Serial.println("m/s."); Serial.print("The time is "); Serial.print(t); Serial.println("s."); } } // 编码器计数中断子程序 void Encode() { //为了不计入噪音干扰脉冲, //当2次中断之间的时间大于5ms时,计一次有效计数 if ((millis() - time1) > 5) { //当编码器码盘的OUTA脉冲信号下跳沿每中断一次, if ((digitalRead(PinA) == LOW) && (digitalRead(PinB) == HIGH)) { count--; } else { count++; } } time1 == millis(); } void Set_state() { count = 0; time3 = millis();//发生中断时的时间 }