supercctv 发表于 2012-3-4 14:59:34

也谈Arduino与旋转编码器的两种连接方式(中断方式,普通D口)

本帖最后由 supercctv 于 2012-3-4 15:03 编辑

翻出去年在北京中发买的旋转编码器,测试了下与arduino的连接。

原理图就不画了,旋转编码器 A,B端分别接10K上拉至VCC,A、B端分别与Arduino主板连接。有时环境存在干扰,会反跳的话,A、B端再通过0.1uf的电容接地即可。

分别测试了两种的连接方式,均成功。

1.采用中断方式。参照czad先前的帖子。我把程序简化了下,意图仅在于说明旋转编码器的正反计数即可。#define PinA 2//中断0
#define PinB 3//中断1

unsigned long time = 0;
long count = 0; //计数值
long num = 0;

//初始化
void setup()
{
Serial.begin(9600); //窗口初始化

pinMode(PinA,INPUT); //D2脚为输入
pinMode(PinB,INPUT); //D3脚为输入

attachInterrupt(0, blinkA, LOW);//注册中断0调用函数blinkA
attachInterrupt(1, blinkB, LOW);//注册中断1调用函数blinkB

time = millis(); //时间初值
}

//主体程序
void loop()
{
while (num != count)
{
    num = count;
    Serial.println(num);
}
}

//中断0调用函数
void blinkA()
{
if ((millis() - time) > 3) //防抖动处理
      count ++;
time = millis();
}

//中断1调用函数
void blinkB()
{
if ((millis() - time) > 3)//防抖动处理
      count --;
time = millis();
}
有图有真相:


2.采用普通Digital口的方式,这里用D4与D5。第一种方法要用掉两个中断,有点浪费,有时中断端口要留着其他用处。参考Arduino Cookbook第二版。PS:第一版中,那个图是错误。const int encoderPinA = 4;
const int encoderPinB = 5;

boolean encoderALast = LOW;// remembers the previous pin state

void setup()
{
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
digitalWrite(encoderPinA, HIGH);
digitalWrite(encoderPinB, HIGH);
Serial.begin (9600);
}

void loop()
{
boolean encoderA = digitalRead(encoderPinA);
if ((encoderALast == HIGH) && (encoderA == LOW))
{
    if (digitalRead(encoderPinB) == LOW)
    {
      encoderPos--;
    }
    else
    {
      encoderPos++;
    }
    Serial.print (encoderPos);
}
encoderALast = encoderA;
}有图有真相:




旋转编码器的问题该完结了吧,哈哈~

我在极客的第一帖,特此留念~

GIOCHEN 发表于 2012-7-5 00:10:29

收藏,关于ARDUINO 与编码器的 应用 资料实在太少了,就找到SIMON MONK 的那个实例,还没试;P

小黑 发表于 2012-7-27 18:09:04

有没有计数的中断啊(我也不知道啊 )我看着上面写的那个中断太频繁了   

pww999 发表于 2012-7-27 20:46:05

本帖最后由 pww999 于 2012-7-27 20:48 编辑

学习了,

中断就系停止当前,执行其它,完后,最回来执行当前未完的?   

请问实际用途在那?

在什么时候设置用中断?

supercctv 发表于 2012-7-29 22:40:36

pww999 发表于 2012-7-27 20:46 static/image/common/back.gif
学习了,

中断就系停止当前,执行其它,完后,最回来执行当前未完的?   


个人认为,和你需要控制的外设的时序有关。
如果旋转编码使用普通IO进行驱动的话,就要写在你的主程序里面。响应的时间,需要考虑主程序其他操作的。
如果在中断里面,那自然主程序遇到中断会停止,然后执行中断操作,当然也许评估中断对主程序的影响。
至于用于什么场合,需要具体情况,具体分析

小黑 发表于 2012-7-30 03:22:25

pww999 发表于 2012-7-27 20:46 static/image/common/back.gif
学习了,

中断就系停止当前,执行其它,完后,最回来执行当前未完的?   


用在同时执行的时候    比如你在写作业顺便烧了一壶水   水开了   就是中断   你得处理一下   然后继续写你的作业   OK??

pww999 发表于 2012-7-30 07:51:53

小黑 发表于 2012-7-30 03:22 static/image/common/back.gif
用在同时执行的时候    比如你在写作业顺便烧了一壶水   水开了   就是中断   你得处理一下   然后继 ...

单片机都是单线程的吧?
程序都是由上往下执行?
往往用IF 判断 是否继续写作业 还是水开了要处理一下?
只是不太明白

pww999 发表于 2012-8-5 19:51:39

试了一下

中断计数时有时会数值突变成好几百,或者几千,不准确

而用普通IF 计算很准确?

文少 发表于 2012-8-9 13:33:47

好段子,先MARK一下备用~~

勤奋工作 发表于 2013-3-31 16:05:12

楼主的方法在电机低速情况下可用,电机转速一高则无法识别。因为楼主判正转,反转的方法是用延时来识别的,若要做到高速情况下可用,应外加D触发器,从而实现正转触发中断0,翻转触发中断1

葱拌豆腐 发表于 2013-4-13 12:44:02

勤奋工作 发表于 2013-3-31 16:05 static/image/common/back.gif
楼主的方法在电机低速情况下可用,电机转速一高则无法识别。因为楼主判正转,反转的方法是用延时来识别的, ...

同意,而且手册里说attachinterrupt调用函数mills时,返回值是不会发生变化的。
Note
Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function.

qptimus 发表于 2013-4-13 15:49:52

我看数据手册说在中断函数中,millis()会失效,测试也的确如此,另外中断中不能直接调用普通变量,如果变量要在中断中访问,要使用volatile进行申明,测试也是的确如此。你的这段代码能正常运行吗?

bigas2 发表于 2013-6-22 16:30:48

这两种哪个准确些?高速时

wanji 发表于 2013-7-5 10:00:58

{:soso_e179:}两种方法都很好,学习了

tanbocandy 发表于 2013-7-7 22:24:41

http://playground.arduino.cc/Main/RotaryEncoders   这个可以看看 挺好的
页: [1] 2
查看完整版本: 也谈Arduino与旋转编码器的两种连接方式(中断方式,普通D口)