Author Topic: 2 Rotary Encoders with Arduino?  (Read 9797 times)

0 Members and 1 Guest are viewing this topic.

Offline Thane of CawdorTopic starter

  • Regular Contributor
  • *
  • Posts: 96
2 Rotary Encoders with Arduino?
« on: March 02, 2014, 04:25:15 am »
Hi,


I am a little confused on how to use two rotary encoders to control the brightness of two different LED's. I have managed to get one rotary encoder to work using the code from this website: http://www.hobbytronics.co.uk/arduino-tutorial6-rotary-encoder. How can I use this code so that I can use two encoders with two analog output pins (PWM).


Many Thanks.
 

Offline JoeN

  • Frequent Contributor
  • **
  • Posts: 991
  • Country: us
  • We Buy Trannies By The Truckload
Re: 2 Rotary Encoders with Arduino?
« Reply #1 on: March 02, 2014, 04:45:33 am »
Why would you want to waste two PWM pins for what is a simple digital input application?  This code uses pins 11 and 12 but any pins will do.  You would put the second encoder on another two pins and just double up the code, at least that is the most straightforward way.  If you had lots of encoders, you could refactor it out into a function, of course.  If you can to do that I will leave it up to you.

Assuming the code you provided works with one encoder and one LED, something like this should work for two encoders and two LEDs.  I haven't tested this nor even compiled it, but, pin 10 is the second LED, pin 7 and 8 are the A and B for encoder #2.  You can change these.

Code: [Select]
int brightness1 = 120;    // how bright the LED is, start at half brightness
int brightness2 = 120;    // how bright the LED is, start at half brightness
int fadeAmount = 10;    // how many points to fade the LED by
unsigned long currentTime;
unsigned long loopTime;
const int pin_A1 = 12;  // pin 12
const int pin_B1 = 11;  // pin 11
const int pin_A2 = 7;  // pin 7
const int pin_B2 = 8;  // pin 8
unsigned char encoder_A1;
unsigned char encoder_B1;
unsigned char encoder_A1_prev=0;
unsigned char encoder_A2;
unsigned char encoder_B2;
unsigned char encoder_A2_prev=0;

void setup()  {
  // declare pin 9 to be an output:
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(pin_A1, INPUT);
  pinMode(pin_B1, INPUT);
  pinMode(pin_A2, INPUT);
  pinMode(pin_B2, INPUT);
  currentTime = millis();
  loopTime = currentTime;
}

void loop()  {
  // get the current elapsed time
  currentTime = millis();
  if(currentTime >= (loopTime + 5)){
    // 5ms since last check of encoder = 200Hz 
    encoder_A1 = digitalRead(pin_A1);    // Read encoder pins
    encoder_B1 = digitalRead(pin_B1);   
    if((!encoder_A1) && (encoder_A1_prev)){
      // A has gone from high to low
      if(encoder_B1) {
        // B is high so clockwise
        // increase the brightness, dont go over 255
        if(brightness1 + fadeAmount <= 255) brightness1 += fadeAmount;               
      }   
      else {
        // B is low so counter-clockwise     
        // decrease the brightness, dont go below 0
        if(brightness1 - fadeAmount >= 0) brightness1 -= fadeAmount;               
      }   

    }   
    encoder_A1_prev = encoder_A1;     // Store value of A for next time   
   
    // set the brightness of pin 9:
    analogWrite(9, brightness1);   

    // 5ms since last check of encoder = 200Hz 
    encoder_A2 = digitalRead(pin_A2);    // Read encoder pins
    encoder_B2 = digitalRead(pin_B2);   
    if((!encoder_A2) && (encoder_A2_prev)){
      // A has gone from high to low
      if(encoder_B2) {
        // B is high so clockwise
        // increase the brightness, dont go over 255
        if(brightness2 + fadeAmount <= 255) brightness2 += fadeAmount;               
      }   
      else {
        // B is low so counter-clockwise     
        // decrease the brightness, dont go below 0
        if(brightness2 - fadeAmount >= 0) brightness2 -= fadeAmount;               
      }   

    }   
    encoder_A2_prev = encoder_A2;     // Store value of A for next time   
   
    // set the brightness of pin 10:
    analogWrite(10, brightness2);   
  }
  // Other processing can be done here
                           
}
Have You Been Triggered Today?
 

Offline Thane of CawdorTopic starter

  • Regular Contributor
  • *
  • Posts: 96
Re: 2 Rotary Encoders with Arduino?
« Reply #2 on: March 02, 2014, 05:01:58 am »
Hi

Thanks for the help. It worked!   :-+ Just one question, what do you mean by refactoring into a function?



Thanks again!
 

Offline JoeN

  • Frequent Contributor
  • **
  • Posts: 991
  • Country: us
  • We Buy Trannies By The Truckload
Re: 2 Rotary Encoders with Arduino?
« Reply #3 on: March 02, 2014, 08:04:24 am »
Hi

Thanks for the help. It worked!   :-+ Just one question, what do you mean by refactoring into a function?



Thanks again!

It's a little complex to explain, but refactoring code means changing the way that it is written to make the code more readable or maintainable (or some other positive purpose) without actually functionally changing the code.  The code I created really just duplicated code in order to track that second rotary encoder.  A better way would be to make a function that could track any rotary encoder on any two pins and adjust any brightness variable.  That way, when you wanted to go to three or four encoders (subject to actual pin availability, of course) the code wouldn't expand further, no more than making a function call at least.  At three copies of the code it would start getting ugly, any change you make to the routine has to be made in three places, not one.

http://en.wikipedia.org/wiki/Refactor_code
Have You Been Triggered Today?
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: 2 Rotary Encoders with Arduino?
« Reply #4 on: March 02, 2014, 10:27:25 am »
You can use the same code strategy as above (I've done it on PICs several times) - by using pin-change interrupts - that way you can eliminate most of the code -= and it's as fast as can be.

Simply detect the change on the A-pin, and determine where the B-pin is. There are only four combinations, boiled down to two possible results - count up, or count down.
Don't ask a question if you aren't willing to listen to the answer.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: 2 Rotary Encoders with Arduino?
« Reply #5 on: March 02, 2014, 11:32:04 am »
My suggestion:

1) Put it in a routine so your code is easier to read and can be reused later;
2) Use a state machine for each routine - far simpler code than what you have now;
3) Use interrupt so it runs in the background and no missing clicks.
================================
https://dannyelectronics.wordpress.com/
 

Offline linux-works

  • Super Contributor
  • ***
  • Posts: 2028
  • Country: us
    • netstuff
Re: 2 Rotary Encoders with Arduino?
« Reply #6 on: March 02, 2014, 05:57:26 pm »
look for interrupt based rotary reading.  arduino online examples have lots.

if you don't use an ISR you will miss clicks as you turn the knob too fast.  doing it inside the main routine is a non-starter.  I suggest abandoning that approach right away unless you know the knob will turn very very slowly and dropped events are ok for your app.

I also suggest using both pins on each encoder as state-change pins on the arduino.  arduino 328 supports only 2 pins doing that but the 328 CHIP supports many more, so you may have to go outside the standard arduino lib to do this (not a big deal) or use a mega chip which has more pin-change events you can map to.

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6289
  • Country: 00
Re: 2 Rotary Encoders with Arduino?
« Reply #7 on: March 02, 2014, 07:35:46 pm »
I would formulate the code as a state machine for simplicity.  Something along these lines below. If you want two just copy/paste the code twice and rename to avoid conflict between the two  (yes, I know, one can use classes or templates to avoid source code duplication but I try to keep it simple).  Just make sure your loop() spins fast enough.  BTW, digitalRead() has some unnecessary overhead, you can use something like library to make it faster https://github.com/zapta/linbus/blob/master/beeper/arduino/io_pins.h

// Returns encoder state as bits <a, b>.
inline byte readEncoderState() {
 return (readDigital(pinA1) ? 0b10 : 0b00 ) + (readDigital(pinA2) ? 0b01 : 0b00);
}

// Last state of this encoder
byte last_state;

// in main setup():

last_state = readEncoderState();

// in the main loop()

const byte new_state = readEncoderState();
if (last_state == 0b10) {
  if (new_state == 0b11) {
    // do increment up with limit enforcement.
  }  else if (new_state == 0b00) {
    // do increment down with limit enforcement.
  }
}
last_state == new_state;
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: 2 Rotary Encoders with Arduino?
« Reply #8 on: March 02, 2014, 07:47:38 pm »
All those if statements cab be easily implemented via a look up table.

3 or so statements in total.
================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf