Arduino使用旋转编码器

来源:互联网 发布:淘宝关于dns劫持的教程 编辑:程序博客网 时间:2024/05/01 13:12
这次介绍的是我买的37款传感器套件中的旋转编码器。首先是实物图。
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
通过查阅资料,旋转编码器既可以左右旋转,又能当成按钮按下。首先测试一下按下的功能,该功能对应的输出引脚是SW。
测试代码如下: 

int Led =4; //定义LED 接口
int coderPin = 10;
void setup()
{
pinMode(Led, OUTPUT);
pinMode(coderPin, INPUT);
digitalWrite(coderPin,HIGH);
Serial.begin(9600);
}
void loop()
{
val = digitalRead(coderPin);
if (val==HIGH)
{
digitalWrite(Led, HIGH);
}
else
{
digitalWrite(Led,LOW );
}
}

测试的实物连接图如下,测试的视频在连接图之后:
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
这里需要注意的是SW引脚默认输出的是HIGH信号,按下后输出LOW信号。setup函数的digitalWrite(coderPin,HIGH);
这句代码很重要,没有加这句之前,从引脚10获得的值经常变化,不开始摸不着头绪,后来看到参考文献2中的介绍,初始化
时需要将coderPin上拉,果然加了这句话之后,从引脚10获得的值就稳定了,没有再擅自变动。
  然后是另外两个引脚CLK和DT,通过百度查阅资料时,看到的大部分文章中都附了下面的图形,给出的介绍说是旋转编码
器中A和B两个通道中的信号图,但是我买的旋转编码器上没有标A和B啊!!!只有CLK和DT两个引脚。
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
 只有自己写测试代码看这两个引脚的输出了。测试代码如下:

int Led =4; //定义LED 接口
int coderPin = 10;
int dtPin=11;
int clkPin=12;
int val=0;
void setup()
{
pinMode(Led, OUTPUT);
pinMode(coderPin, INPUT);
digitalWrite(coderPin,HIGH);
pinMode(dtPin, INPUT);
pinMode(clkPin, INPUT);
Serial.begin(9600);
}
void loop()
{
val = digitalRead(coderPin);
Serial.print(val);
val = digitalRead(dtPin);


Serial.print(",");
Serial.print(val);

val = digitalRead(clkPin);
Serial.print(",");
Serial.println(val);
}

读出来的数据放到matlab里面做成图,图形如下左上角是DT引脚的输出点图,右上角是CLK引脚的输出点图,左下角是DT引脚和CLK引脚数据和到一起的点图,右下角是DT引脚输出值与CLK引脚输出值的和的图。好像也看不出来什么东西。
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
 通过看DT引脚和CLK引脚的输出值,转动的时候这两个引脚的值在变化,但是如果没有转动,则这两个引脚的值始终为1.所以上图中大部分点都分布在值为1的水平线上。
然后再试参考文献2中使用中断的代码:

//定义引脚连接
int CLK = 2;
int DT = 11;
const int interrupt0 = 0;

void setup()
{
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
attachInterrupt(interrupt0, ClockChanged, CHANGE);//设置中断0的处理函数,电平变化触发
Serial.begin(9600);
}

void loop()
{
}

//中断处理函数
void ClockChanged()
{
int clkValue = digitalRead(CLK);//读取CLK引脚的电平
int dtValue = digitalRead(DT);//读取DT引脚的电平
Serial.print(clkValue);
Serial.print(",");
Serial.println(dtValue);
}

这时候只有在转动旋转编码器的时候才会有数据向串口输出,将输出的数据整理为图形如下,下图是顺时针时获取到的数据图形,红色的是CLK引脚的输出值,蓝色的是DT引脚的输出,可以看到这两个引脚的输出大部分时候都是相反的,CLK为0时,对应位置的DT输出大部分为1:
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
 下图是逆时针时获取到的数据图形,红色的是CLK引脚的输出值,蓝色的是DT引脚的输出,可以看到逆时针转动的时候CLK输出为1的时候比顺时针的时候多,DT输出为0的时候也比较密集。
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
 看上述的图形好像也总结不出来什么规律,还得参考别人的文章来看是怎么计数。还得看刚才那个AB通道信号图。CW的时候在A通道从LOW到HIGH时,此时B通道为HIGH,而CCW的时候,如果A通道从LOW到HIGH,B通道为LOW。大部分的文章都是根据这个规律来区分是正转还是反转。这个AB通道应该就是对应的CLK和DT。
通过测试,参考文献4中的代码不是很稳定,在我计算机上测试时POSITION跳动比较大:
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
 参考文献4中的代码的值比较均匀,但是手动转一下就会增加两个值,程序可能还是需要改进。
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
 
分析原因,应该是旋转编码器转动一下,就会产生多次中断事件,所以才造成上述代码测试时的值跳动或者多次变动。得去找方法判断是不是转动了。
重新运行本文的第三段代码,查找其中的规律,逆时针时如下图所示,总是以0,1开头,1,0结尾:
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
 
 顺时针时如下图所示,总是以0,0开头,1,1结尾:
Arduino使用旋转编码器 - gc_2299 - gc_2299的博客
所以规律应该是顺时针时,检测到0,0就可以认为是开始转动,接下来的数据中如果有1,1,则认为正在转动,再下面的数据中如果有0,0就认为上一个转动结束,开始下一个转动。逆时针的规律类似。
根据分析写的最终的程序为:

//定义引脚连接
#define CW_START_CLK 0
#define CW_START_DT 0
#define CW_END_CLK 1
#define CW_END_DT 1
#define CCW_START_CLK 0
#define CCW_START_DT 1
#define CCW_END_CLK 1
#define CCW_END_DT 0

int CLK = 2;//CLK->D2
int DT = 11;//DT->D3
int SW = 10;//SW->D4
const int interrupt0 = 0;// Interrupt 0 在 pin 2 上
int count = 0;//计数值
int lastCLK = 0;//CLK历史值

int stage = -1; //两个阶段,0,开始,1,进行

void setup()
{
pinMode(SW, INPUT);
digitalWrite(SW, HIGH);
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
attachInterrupt(interrupt0, ClockChanged, CHANGE);//设置中断0的处理函数,电平变化触发
Serial.begin(9600);
}

void loop()
{
if (!digitalRead(SW) && count != 0) //读取到按钮按下并且计数值不为0时把计数器清零
{
count = 0;
Serial.print("count:");
Serial.println(count);
}
}

//中断处理函数
void ClockChanged()
{
int clkValue = digitalRead(CLK);//读取CLK引脚的电平
int dtValue = digitalRead(DT);//读取DT引脚的电平

if ((clkValue == CW_START_CLK) && (dtValue == CW_START_DT))
{
if (stage == -1)
{
stage = 0;
}
else if (stage == 1)
{
stage = 0;
count++;
Serial.print("count:");
Serial.println(count);
}
}
else if ((clkValue == CW_END_CLK) && (dtValue == CW_END_DT))
{
if (stage == 0)
{
stage = 1;
}
}
else if ((clkValue == CW_START_CLK) && (dtValue == CCW_START_DT))
{
if (stage == -1)
{
stage = 0;
}
else if (stage == 1)
{
stage = 0;
count--;
Serial.print("count:");
Serial.println(count);
}
}
else if ((clkValue == CCW_END_CLK) && (dtValue == CCW_END_DT))
{
if (stage == 0)
{
stage = 1;
}
}
}

 
参考文献
[1] http://www.arduino.cn/forum.php?mod=viewthread&tid=2423&highlight =%E6%97%8B%E8%BD%AC%E7%BC%96%E7%A0%81%E5%99%A8
[2]http://www.cnblogs.com/conexpress/p/4984802.html
[3]http://blog.csdn.net/xuanyuanlei1020/article/details/51725653
[4]http://www.arduino.cn/thread-2423-1-1.html
原创粉丝点击