以Arduino方式学习使用旋转编码器EC11

本文介绍了如何使用ESP8266和ArduinoIDE测试旋转编码器,包括接口连接、信号采集、中断处理和逻辑判断,同时提到了使用中断和现成库的便利性。
摘要由CSDN通过智能技术生成

平时买个什么模块,需要测试是否正常。通常这种情况下,我优先选择用ESP8266或者其它可以在ArduinoIDE下使用的开发板来测试。原因无他,因为可以直接使用支持库、以及连接、下载、串口测试显示接收等方便,不需要额外做其他事情。所以当买来的旋转编码器在拿到手里后,立马就用ESP8266来测试了。
论坛里已经有不少伙计发了有关编码器的帖子,我这里也就不再详细说明编码器的资料了,只上干货。
先看看ESP8266的引脚图:
 


旋转编码器的接口:
 


编码器的电原理图:
 


输出信号:
 


A、B两相都输出方波,顺时针方向旋转时,A相超前B相90度,逆时针方向旋转时,B相超前A相90度;
为了方便接线和测试,我用洞洞板重新改了接线方式,使所有接线都放在一侧。使用ESP8266的D1,D2这两个口采集A、B数据。 


为了方便看编码器旋转时信号的变化,首先使用以下程序进行测试:

复制
// 本程序使用ESP8266测试旋转编码器,使用D1(GPIO5)接A,D2(GPIO4)接B

// 引脚定义

#defineBMQ_A  5

#defineBMQ_B  4

// 旋转标志变量

unsignedchar flag = 0;

// 上次状态

unsignedchar status_old = 0;

// 当前状态

unsignedchar status_cur = 0;

// 旋转计数,顺时针:+1;逆时针:-1

int cnt = 0;

void setup(){

  // 串口设置

  Serial.begin(115200);

  

  // LED设置

  pinMode(LED_BUILTIN, OUTPUT);

  // 设置D1(GPIO5)、D2(GPIO4)为数字输入口

  pinMode(BMQ_A, INPUT);    // D1 - A

  pinMode(BMQ_B, INPUT);    // D2 - B

  // 设置中断,下降沿和上升沿均触发中断

  //attachInterrupt(digitalPinToInterrupt(BMQ_A), a_proc, FALLING | RISING);

  //attachInterrupt(digitalPinToInterrupt(BMQ_B), b_proc, FALLING | RISING);

  status_old=digitalRead(BMQ_A)*2+digitalRead(BMQ_B);

}

void loop(){

   status_cur=digitalRead(BMQ_A)*2+digitalRead(BMQ_B);

   if(status_old != status_cur){

     status_old=status_cur;

     Serial.print("A:");

     Serial.print(digitalRead(BMQ_A));

     Serial.print(" B:");

     Serial.println(digitalRead(BMQ_B));

   }

}

// 中断处理函数,边沿触发

IRAM_ATTR void a_proc(){

  status_cur=digitalRead(BMQ_A)*2+digitalRead(BMQ_B);

  if(status_cur != status_old){

    status_old=status_cur;

    Serial.print("a_proc ");

    Serial.print("A:");

    Serial.print(digitalRead(BMQ_A));

    Serial.print(" B:");

    Serial.println(digitalRead(BMQ_B));

  }

    

}

IRAM_ATTR void b_proc(){

  status_cur=digitalRead(BMQ_A)*2+digitalRead(BMQ_B);

  if(status_cur != status_old){

    status_old=status_cur;

    Serial.print("b_proc ");

    Serial.print("A:");

    Serial.print(digitalRead(BMQ_A));

    Serial.print(" B:");

    Serial.println(digitalRead(BMQ_B));

  }

}



运行后,从串口收集到的信息如下:
初始化状态:A:0 B:0
1、顺时针旋转一格场合:
    A:1 B:0
    A:1 B:1
    A:0 B:1
    A:0 B:0
2、逆时针旋转一格场合
    A:0 B:1
    A:1 B:1
    A:1 B:0
    A:0 B:0
程序改为边沿中断触发处理场合(需要开放Setup中attachInterrupt的中断设置代码,注释掉loop中代码)
1、顺时针旋转一格场合:
    a_proc A:1 B:0
    b_proc A:1 B:1
    a_proc A:0 B:1
    b_proc A:0 B:0
2、逆时针旋转一格场合
    b_proc A:0 B:1
    a_proc A:1 B:1
    b_proc A:1 B:0
    a_proc A:0 B:0
和循环处理的取得数据变化是一致的。可以使用中断方式来处理。根据数据的变化规律,准备用以下逻辑进行判断处理,
1、初始化时记录A、B口数据,计算为A*2+B
2、中断发生时,采集数据,数据发生变化并且匹配顺时针或者逆时针的变化规律时,存储到标志数组,
3、采集到的变化数据够4个时,与变化规律进行比较,从而判断出是顺时针旋转,还是逆时针旋转。
整理代码如下:

复制


// 本程序测试旋转编码器,使用D1(GPIO5)接A,D2(GPIO4)接B



// 引脚定义

#define BMQ_A 5

#define BMQ_B 4



// 一组数据采集完成的标志

unsigned char flag = 0;

// 当前数据存储位置

unsigned char pos = 0;

// 完整数据采集周期变量

unsigned char chg[8];



// 上次状态

unsigned char status_old = 0;

// 当前状态

unsigned char status_cur = 0;



// 旋转计数,顺时针:+1;逆时针:-1

long step = 0;



void setup() {

  // 串口设置

  Serial.begin(230400);

  

  // LED设置

  pinMode(LED_BUILTIN, OUTPUT);



  // 设置D1(GPIO5)、D2(GPIO4)为数字输入口

  pinMode(BMQ_A, INPUT);    // D1 - A

  pinMode(BMQ_B, INPUT);    // D2 - B



  // 设置中断,下降沿和上升沿均触发中断

  attachInterrupt(digitalPinToInterrupt(BMQ_A), a_proc, FALLING | RISING);

  attachInterrupt(digitalPinToInterrupt(BMQ_B), b_proc, FALLING | RISING);



  status_old=digitalRead(BMQ_A)*2+digitalRead(BMQ_B);

}



void loop() {



}



// 中断处理函数,边沿触发

IRAM_ATTR void a_proc() {

  //Serial.println("a_proc");

  com_proc();

}



IRAM_ATTR void b_proc() {

  //Serial.println("b_proc");

  com_proc();

}



void com_proc() {

  int val=0;

  if (flag==0) {

    // 当前状态

    status_cur=digitalRead(BMQ_A)*2+digitalRead(BMQ_B);

    if (status_cur != status_old) {

      Serial.print("pos=");

      Serial.print(pos);

      Serial.print("  AB=");

      Serial.println(status_cur);

      // 有变化

      status_old=status_cur;

      // 保存

      chg[pos++]=status_cur;

      if (pos>=4) {

        // 完成一组数据采集

        flag=1;   // 设置标志,防止下一次中断打断下面的处理



        // 计算这组数据的变化顺序

        val=chg[0]*1000 + chg[1]*100 +chg[2]*10 +chg[3];

        // 为了能避免用户在旋转不到位时进行反方向的旋转,需要判断多种值的判定

        // 正常的顺时针旋转为2310,逆时针为1320,通过切换组合顺序,可以避免漏判

        if (val == 2310 || val==3102 || val==1023 || val==231) {

          // 顺时针转动

          step++;

          Serial.print("Shun:");

          Serial.println(step);

        } else if (val == 1320 || val==3201 || val==2013 || val==132) {

          // 逆时针转动

          step--;

          Serial.print("Ni:");

          Serial.println(step);

        }

        if (val == 1020 || val==1013 || val==2023 || val==2020) {

          // 转了一半不动,或者回去了,保留后两位数据

          chg[0]=chg[2];

          chg[1]=chg[3];

          pos=2;

          // 恢复标志

          flag=0;

        } else {

          // 存储位置归位

          pos=0;

          // 恢复标志

          flag=0;

        }

      }  

    }

  }

}


以上代码是经过了以下测试,没有任何问题的,响应速度也很快:
1、慢速顺时针旋转测试
2、慢速逆时针旋转测试
3、快速顺时针旋转测试
4、快速逆时针旋转测试
5、快速旋转中顺时针、逆时针无规律快速切换测试
6、旋转一格不到,就回位,或者反转的测试

以上处理逻辑,应该同样适用于ARM、RISC等其它架构的单片机。
对不喜欢动手敲太多代码的朋友,你也可以选择安装别人做好的名为“Encoder”的库,有现成的例子可以帮助你。


---------------------
作者:suncat0504
链接:https://bbs.21ic.com/icview-3343098-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用以下步骤来实现: 1. 连接EC11旋转编码器和57步进电机到Arduino板上。EC11旋转编码器一般有3个引脚,包括正极(+)、负极(-)和信号引脚(SW)。57步进电机一般有4个引脚,包括A+、A-、B+和B-。 2. 在Arduino IDE中编写代码。代码需要包括两个函数:一个函数用于读取旋转编码器旋转方向,另一个函数用于控制57步进电机的旋转方向和步数。 3. 在代码中定义旋转编码器的引脚和步进电机的引脚。这样可以让代码更加清晰易懂。 4. 在代码中初始化旋转编码器和步进电机。初始化包括将引脚模式设置为输入或输出,以及将步进电机的初始位置设置为0。 5. 在代码中编写循环函数,用于不断读取旋转编码器旋转方向,并根据旋转方向控制步进电机的旋转方向和步数。循环函数可以使用Arduino的delay函数来控制每次旋转的时间。 下面是一个简单的示例代码: ```c++ #include <Stepper.h> // 定义旋转编码器的引脚 const int ec11PinA = 2; const int ec11PinB = 3; const int ec11PinSW = 4; // 定义57步进电机的引脚 const int stepperPinA = 8; const int stepperPinB = 9; const int stepperPinC = 10; const int stepperPinD = 11; // 定义步进电机的步数和速度 const int stepsPerRevolution = 200; const int speed = 10; // 初始化步进电机 Stepper myStepper(stepsPerRevolution, stepperPinA, stepperPinB, stepperPinC, stepperPinD); // 初始化旋转编码器 int lastPosition = 0; int currentPosition = 0; void setup() { // 将旋转编码器的引脚设置为输入 pinMode(ec11PinA, INPUT); pinMode(ec11PinB, INPUT); pinMode(ec11PinSW, INPUT); // 将步进电机的引脚设置为输出 pinMode(stepperPinA, OUTPUT); pinMode(stepperPinB, OUTPUT); pinMode(stepperPinC, OUTPUT); pinMode(stepperPinD, OUTPUT); // 设置步进电机的初始位置为0 myStepper.setSpeed(speed); myStepper.step(0); } void loop() { // 读取旋转编码器旋转方向 int delta = readEncoder(); // 如果旋转方向不为0,控制步进电机旋转 if (delta != 0) { int steps = delta * 10; // 每次旋转10步 myStepper.step(steps); lastPosition = currentPosition; currentPosition += steps; } // 等待一段时间,再次读取旋转编码器 delay(50); } // 读取旋转编码器旋转方向 int readEncoder() { int delta = 0; int a = digitalRead(ec11PinA); int b = digitalRead(ec11PinB); if (a != b) { if (a == HIGH) { delta = 1; } else { delta = -1; } } return delta; } ``` 这个例子中,每次旋转编码器,步进电机就会旋转10步。你可以根据需要自行调整步数。同时,如果需要控制步进电机的左右旋转,可以根据步进电机的旋转方向来控制。例如,如果需要向左旋转,可以将步数设置为负数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值