【Arduino】旋转编码器的Arduino使用方法

摘要:
SW应为Switch,CLK应为Clock,DT应为Data。按下或释放SW(红色)+GND(黑色)时,没有变化。当释放VCC(红色)+SW(黑色)时,仪表引脚指向0。Arduino检测方法是将连接到SW的引脚设置为INPUT(输入),并向上拉以输出高电平//连接到按钮的引脚设置为拉起串行。开始(9600);按下按钮时读取CLK和DT的值:

以前用CRT显示器的时候,调整显示器的时候用一个圆盘转动和点击的方法就可以实现选择菜单和修改设置项的值,比多个按钮的方式方便很多。

【Arduino】旋转编码器的Arduino使用方法第1张【Arduino】旋转编码器的Arduino使用方法第2张

鼠标滚轮也是这种操作方法,旋转+点击,只是方向不同。最近在网上买了旋转编码器模块,想把它用到实际制作中。在网上找了很多资料,测试发现其中的代码或多或少都有问题。于是决定自己研究一下旋转编码器的原理,只涉及高低电平应该会比较简单。

我买的旋转编码器模块有5个引脚,分别是VCC, GND, SW, CLK, DT。其中VCC和GND用来接电源和地,按缩写SW应该是Switch(开关)、CLK是Clock(时钟)、DT是Data(数据)。

【Arduino】旋转编码器的Arduino使用方法第3张

 

网上的资料虽然代码不是很理想,但介绍的原理基本是没问题的。旋转编码器的操作是旋转和按压转轴,在按下转轴的时候SW引脚的电平会变化,旋转的时候每转动一步CLK和DT的电平是有规律的变化。在只接电源的情况下先测一下各种操作时引脚电平的变化,没有示波器只好用万用表测电压。

点击:SW(红)+GND(黑)时按下和松开按钮没有任何变化,VCC(红)+SW(黑)松开时表针指向0,按下时高电平。据此可以推测SW平时为高阻态,按下时接地。用Arduino检测的方法是设置连接SW的引脚为INPUT并上拉输出高电平,检测到引脚为低电平则表示按钮按下,以下代码可以正确检测出按钮的变化。

//定义引脚连接
int SW= 4;  // SW->D4
bool lastButtonStatus = false;
 
void setup()
{
  pinMode(SW, INPUT);
  digitalWrite(SW, HIGH);//连接按钮的引脚设为上拉
  Serial.begin(9600);
}
 
void loop()
{
  bool buttonStatus = !digitalRead(SW);//高电平时未按下,状态为false
  if (buttonStatus != lastButtonStatus)
  {
    Serial.println(buttonStatus ? "pressed" : "released");
    lastButtonStatus = buttonStatus;//保存当前状态
  }
  delay(100);
}

【Arduino】旋转编码器的Arduino使用方法第4张

旋转:CLK(红)+GND(黑),每旋转一次(和方向无关),电平转换一次,DT(红)+GND(黑),变化情况和上一种情况一致,并且CLK和DT的电平保持一致。VCC(红)+CLK(黑),VCC(红)+DT(黑)也是同样的情况。CLK(红)+DT(黑)或者CLK(黑)+DT(红)时,每次旋转(和方向无关)指针都会轻微摆动然后归零,并且相邻两步指针的摆动方向相反。结论:每次旋转CLK和DAT引脚的电平都会变化,电平变化有时间差,但无法区分往哪个方向旋转。

编写测试代码,在按下按钮的时候读取CLK和DT的值:

 1 //定义引脚连接
 2 int CLK = 2;//CLK->D2
 3 int DT = 3;//DT->D3
 4 int SW = 4;//SW->D4
 5  
 6 void setup()
 7 {
 8   pinMode(SW, INPUT);
 9   digitalWrite(SW, HIGH);//连接按钮的引脚设为上拉
10   pinMode(CLK, INPUT);
11   pinMode(DT, INPUT);
12   Serial.begin(9600);
13 }
14  
15 void loop()
16 {
17   if (!digitalRead(SW)) //读取到按钮按下时读取CLK和DT的值
18   {
19     int clkValue = digitalRead(CLK);//读取CLK引脚的电平
20     int dtValue = digitalRead(DT);//读取DT引脚的电平
21     Serial.print("CLK:");
22     Serial.print(clkValue);
23     Serial.print("; DT:");
24     Serial.println(dtValue);
25     delay(1000);
26   }
27 }

测试发现不管顺时针还是逆时针旋转,每次按下按钮之后读取的CLK和DT的值都是一样的,并且相邻两步之间的值是不一样的,符合用万用表测量的结果。

【Arduino】旋转编码器的Arduino使用方法第5张

万用表测量时发现CLK和DT的变化有一定的时间差,可以用Arduino在CLK电平变化的瞬间读取DT的值,可能会找到其中的规律。改成通过中断0监控CLK上的电平变化,读取CLK和DT的电平值:

 1 //定义引脚连接
 2 int CLK = 2;//CLK->D2
 3 int DT = 3;//DT->D3
 4 const int interrupt0 = 0;// Interrupt 0 在 pin 2 上
 5  
 6 void setup()
 7 {
 8   pinMode(CLK, INPUT);
 9   pinMode(DT, INPUT);
10   attachInterrupt(interrupt0, ClockChanged, CHANGE);//设置中断0的处理函数,电平变化触发
11   Serial.begin(9600);
12 }
13  
14 void loop()
15 {
16 }
17  
18 //中断处理函数
19 void ClockChanged()
20 {
21   int clkValue = digitalRead(CLK);//读取CLK引脚的电平
22   int dtValue = digitalRead(DT);//读取DT引脚的电平
23   Serial.print("CLK:");
24   Serial.print(clkValue);
25   Serial.print("; DT:");
26   Serial.println(dtValue);
27 }

顺时针旋转一步:

【Arduino】旋转编码器的Arduino使用方法第6张

顺时针旋转3步(用横线分隔):

【Arduino】旋转编码器的Arduino使用方法第7张

逆时针旋转3步(用横线分隔):

【Arduino】旋转编码器的Arduino使用方法第8张

根据以上测试结果,每旋转一次触发的中断次数不一致,可能是硬件本身引起的,类似按钮抖动。多次测试之后,查看每次变化的最后一组值,顺时针旋转时CLK和DT的值不一致,逆时针旋转时CLK和DT的值一致。修改代码,顺时针时对计数值加1,逆时针时对计数值减1,按下按钮时计数值清零。

 1 //定义引脚连接
 2 int CLK = 2;//CLK->D2
 3 int DT = 3;//DT->D3
 4 int SW = 4;//SW->D4
 5 const int interrupt0 = 0;// Interrupt 0 在 pin 2 上
 6 int count = 0;//计数值
 7 int lastCLK = 0;//CLK历史值
 8  
 9 void setup()
10 {
11   pinMode(SW, INPUT);
12   digitalWrite(SW, HIGH);
13   pinMode(CLK, INPUT);
14   pinMode(DT, INPUT);
15   attachInterrupt(interrupt0, ClockChanged, CHANGE);//设置中断0的处理函数,电平变化触发
16   Serial.begin(9600);
17 }
18  
19 void loop()
20 {
21   if (!digitalRead(SW) && count != 0) //读取到按钮按下并且计数值不为0时把计数器清零
22   {
23     count = 0;
24     Serial.print("count:");
25     Serial.println(count);
26   }
27 }
28  
29 //中断处理函数
30 void ClockChanged()
31 {
32   int clkValue = digitalRead(CLK);//读取CLK引脚的电平
33   int dtValue = digitalRead(DT);//读取DT引脚的电平
34   if (lastCLK != clkValue)
35   {
36     lastCLK = clkValue;
37     count += (clkValue != dtValue ? 1 : -1);//CLK和DT不一致时+1,否则-1
38     Serial.print("count:");
39     Serial.println(count);
40   }
41 }

测试发现大多数时候可以正确输出:

【Arduino】旋转编码器的Arduino使用方法第9张

偶尔旋转不是很顺畅会出现跳动的情况,这时候能感觉到旋钮在两步之间跳动了一下。看到有人说在引脚和地之间接上滤波电容会好一些,实际测试发现并没有改善。推测由于旋钮是D字型的,用手旋转的时候确实会出现跳动的情况,装上旋钮帽之后应该会避免这种情况。

【Arduino】旋转编码器的Arduino使用方法第10张

旋转编码器可以用于需要精确调整值(电位器不准确),操作菜单等场合。后续会使用旋转编码器制作一些小东西,也欢迎大家分享旋转编码器相关代码。

 

免责声明:文章转载自《【Arduino】旋转编码器的Arduino使用方法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇IDEA springboot+maven+mybatis pojo代码自动生成重构之路第七篇——大型重构下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Halcon 学习笔记--形态学(5)

一、二值化与灰度图像 1、 二值化图像只有两个元素之分0和1—非黑即白  算子: binary_threshold(Image : Region : Method, LightDark : UsedThreshold)参数:Image:需要进行阈值的图像Region:处理后的区域Method:分割方法('max_separability':最大限度的可分性...

关于三级联动或者四级联动等的一些思考

原理概述如图 1、当页面初始化时应当初始化的数据源: I级数据源、II级数据源、III级数据源、IV级数据源。。。。。。 所以在初始化I级数据源的时候,需要把II、III、IV级的数据源也初始化了 初始化II级的数据源时,需要把III、IV级的也初始化了,以次类推。。。。。。 最重要的时候在初始化页面时要把四级都初始化了,本人在此出现过错误,记录一下,提...

ADODB——RecordSet对象

转自网友,看着挺全就转了,供大家学习研究。 Recordset 对象的属性1、CursorType 属性 AdOpenForwardOnly: 仅向前游标,默认值。除了只能在记录中向前滚动外,与静态游标相同。当只需要在记录集中单向移动时,使用它可提高性能。(顾名思义,这种游标只能向前移动。然而,由于这种游标功能有限,将它用于系统资源时是非常有效的。) Ad...

i.MX6ULL的GPIO简要介绍。

详细介绍可参考《i.MX 6UltraLite Applications ProcessorReference Manual》第 26 章 General Purpose Input/Output (GPIO)(P1133)。GPIO框图   一、IOMUXC复用选择器 1 在IOMUXC 外设中,MUX Mode 和 Pad Settings 寄存器命...

sql记录查询重复注意事项(经验提升),in的用法和效率

sql查询重复记录,使用: select * from dimappnamenew as appn where id in (   select id   from dimappnamenew group by packagename,storename,app_name having count(*)>1 )  id是表的主键,三个属性映射后可以...

Linux串口通信之termios结构体说明

termios结构体中,该结构体一般包括如下的成员:tcflag_t c_iflag;      tcflag_t c_oflag;      tcflag_t c_cflag;      tcflag_t c_lflag;     cc_t     c_cc[NCCS];    其具体意义如下 c_iflag:输入模式标志,控制终端输入方式,具体参数如下...