Rotary Encoder旋转编码器

 

 1 #define PIN_HIGHBIT (7)
 2 #define PIN_LOWBIT  (5)
 3 #define PIN_PWR     (3)
 4 #define BAUDRATE    (9600)
 5 #define DEBUG         (1)
 6 
 7 // globals
 8 int state, prevState = 0, count = 0;
 9 /* old state, new state, change (+ means clockwise)
10  * 0 2 +
11  * 1 0 +
12  * 2 3 +
13  * 3 1 +
14  * 0 1 -
15  * 1 3 -
16  * 2 0 -
17  * 3 2 -
18  */
19 int encoderStates[4][4] = {
20  {  0, -1,  1,  0 }, 
21  {  1,  0,  0, -1 }, 
22  { -1,  0,  0,  1 }, 
23  {  0,  1, -1,  0 }, 
24 };
25 
26 void setup() {
27   pinMode(PIN_HIGHBIT, INPUT);
28   pinMode(PIN_LOWBIT, INPUT);
29   pinMode(PIN_PWR, OUTPUT);
30   digitalWrite(PIN_PWR, LOW);
31   digitalWrite(PIN_LOWBIT, HIGH);
32   digitalWrite(PIN_HIGHBIT, HIGH);
33   Serial.begin(BAUDRATE); 
34 }
35 
36 void loop() {
37   state = (digitalRead(PIN_HIGHBIT) << 1) | digitalRead(PIN_LOWBIT);
38   count += encoderStates[prevState][state];
39 
40 #ifdef DEBUG
41   if (state != prevState) {
42     Serial.print(state, DEC);
43     Serial.print(' ');
44     Serial.print(prevState, DEC);
45     Serial.print(' ');
46     Serial.println(count, DEC);
47   }
48 #endif
49 
50   prevState = state;
51 }

 

/*
          Rotary_Encoder_LED_Ring_Example
          www.mayhewlabs.com/products/rotary-encoder-led-ring 
          Copyright (c) 2011 Mayhew Labs.
          Written by Mark Mayhew
          
This example shows 3 sequences that are possible on the ring of LEDs around the encoder based on rotation of an encoder.  The 3 sequences are 
selected by entering 1, 2, or 3 in the serial command prompt.  The serial window shows the current rotary encoder count.  As the encoder is turned, 
the serial display shows a raw count of the rotary encoder's value and the LEDs show a scaled version of the value.  If the button on the rotary 
encoder is pushed, the bottom LED will come on.  Each section of code below discusses the process required to do this. 

A note on setting the output sequence:
Think of each LED as a single bit in a 16-bit long binary string.  If a bit is 1, the LED is on, if a bit is 0, the LED is off.  
By making a string of ones and zeros, we choose which LEDs to have on and off, and then send this string to the shift register to display it.
For example 1000000000000001 binary (0x8001 in hex) will have the fist and last LEDs on, the rest off.  

CREDIT:
Reading the rotary encoder is performed with Oleg's example code:a
http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino
*/

//These are the pins that will talk to the shift register through SPI
#define SDI    2    //Data
#define CLK    3    //Clock
#define LE     4    //Latch

//These are the rotary encoder pins A, B, and switch
#define ENC_A    8
#define ENC_B    9
#define ENC_SW   10
#define ENC_PORT PINB  //The port that the rotary encoder is on (see http://www.arduino.cc/en/Reference/PortManipulation)

// Global variables
int scaledCounter = 0;  //The LED output is based on a scaled veryson of the rotary encoder counter
int sequenceNumber=0;   //The output sequence for the LEDs
int incomingByte = 0;   //Serial input to select LED output sequence


/*This is a 2 dimensional array with 3 LED sequences.  The outer array is the sequence; 
  the inner arrays are the values to output at each step of each sequence.  The output values
  are 16 bit hex values (hex math is actually easier here!).  An LED will be on if its 
  corresponding binary bit is a one, for example: 0x7 = 0000000000000111 and the first 3 LEDs 
  will be on.
  
  The data type must be 'unsigned int' if the sequence uses the bottom LED since it's value is 0x8000 (out of range for signed int).
*/
unsigned int sequence[3][16] = {{0x0,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x100,0x200,0x400,0x800,0x1000,0x2000,0x4000},
                                {0x0,0x1,0x3,0x7,0xf,0x1f,0x3f,0x7f,0xff,0x1ff,0x3ff,0x7ff,0xfff,0x1fff,0x3fff,0x7fff},
                                {0x0,0x7fff,0x3ffe,0x1ffc,0xff8,0x7f0,0x3e0,0x1c0,0x80,0x1c0,0x3e0,0x7f0,0xff8,0x1ffC,0x3ffe,0x7fff},
                               };

void setup()
{
  //Set SPI pins to output
  pinMode(SDI, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(LE,OUTPUT);
  //Set encoder pins to input, turn internal pull-ups on
  pinMode(ENC_A, INPUT);
  digitalWrite(ENC_A, HIGH);
  pinMode(ENC_B, INPUT);
  digitalWrite(ENC_B, HIGH);
  pinMode(ENC_SW, INPUT);
  digitalWrite(ENC_SW, HIGH);
  //Set serial rate, prompt for desired sequence
  Serial.begin(115200);
  Serial.println("Enter 1, 2, or 3 to change the LED sequence");
}


void loop()
{ 
  //Local Variables
  static uint8_t counter = 0;      //this variable will be changed by encoder input
  int8_t tmpdata;
  
  //Get any serial input
  if (Serial.available() > 0) 
  {
    incomingByte = Serial.read();
  }
  
  //if the serial input is valid, set the LED output sequence appropriately 
  if (incomingByte == '1')
    sequenceNumber=0;
  if (incomingByte == '2')
    sequenceNumber=1;
  if (incomingByte == '3')
    sequenceNumber=2;
    
  //Call read_encoder() function    
  tmpdata = read_encoder();
  
  //if the encoder has moved
  if(tmpdata) 
    {
      //Print out the counter value
      Serial.print("Counter value: ");
      Serial.println(counter, DEC);
      //Set the new counter value of the encoder
      counter += tmpdata;      
      
      //Scale the counter value for referencing the LED sequence
      //***NOTE: Change the map() function to suit the limits of your rotary encoder application.
      //         The first two numbers are the lower, upper limit of the rotary encoder, the 
      //         second two numbers 0 and 14 are limits of LED sequence arrays.  This is done
      //         so that the LEDs can use a different scaling than the encoder value. 
      scaledCounter = map(counter,0,100,0,15);
      
      //Send the LED output to the shift register 
      digitalWrite(LE,LOW);
      shiftOut(SDI,CLK,MSBFIRST,(sequence[sequenceNumber][scaledCounter] >> 8));    //High byte first
      shiftOut(SDI,CLK,MSBFIRST,sequence[sequenceNumber][scaledCounter]);           //Low byte second
      digitalWrite(LE,HIGH);
    }
  
  //If the encoder switch is pushed, this will turn on the bottom LED.  The bottom LED is turned
  //on by 'OR-ing' the current display with 0x8000 (1000000000000000 in binary)
  if (!digitalRead(ENC_SW))
  {
    digitalWrite(LE,LOW);  
    shiftOut(SDI,CLK,MSBFIRST,((sequence[sequenceNumber][scaledCounter]|0x8000) >> 8));
    shiftOut(SDI,CLK,MSBFIRST,sequence[sequenceNumber][scaledCounter]);              
    digitalWrite(LE,HIGH);   
  }
}



/*************************************************************************
*    read_encoder() function as provided by Oleg:                        *
*    http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino *
*                                                                        *
*    Returns change in encoder state (-1,0,1)                            *
************************************************************************ */
int8_t read_encoder()
{
  int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
  static uint8_t old_AB = 0;
  /**/
  old_AB <<= 2;                   //remember previous state
  old_AB |= ( ENC_PORT & 0x03 );  //add current state
  return ( enc_states[( old_AB & 0x0f )]);
}

 

 

// -----
// RotaryEncoder.cpp - Library for using rotary encoders.
// This class is implemented for use with the Arduino environment.
// Copyright (c) by Matthias Hertel, http://www.mathertel.de
// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
// More information on: http://www.mathertel.de/Arduino
// -----
// 18.01.2014 created by Matthias Hertel
// 17.06.2015 minor updates.
// -----

#include "Arduino.h"
#include "RotaryEncoder.h"


// The array holds the values –1 for the entries where a position was decremented,
// a 1 for the entries where the position was incremented
// and 0 in all the other (no change or not valid) cases.

const int8_t KNOBDIR[] = {
  0, -1,  1,  0,
  1,  0,  0, -1,
  -1,  0,  0,  1,
0,  1, -1,  0  };


// positions: [3] 1 0 2 [3] 1 0 2 [3]
// [3] is the positions where my rotary switch detends
// ==> right, count up
// <== left,  count down


// ----- Initialization and Default Values -----

RotaryEncoder::RotaryEncoder(int pin1, int pin2) {
  
  // Remember Hardware Setup
  _pin1 = pin1;
  _pin2 = pin2;
  
  // Setup the input pins
  pinMode(pin1, INPUT);
  digitalWrite(pin1, HIGH);   // turn on pullup resistor

  pinMode(pin2, INPUT);
  digitalWrite(pin2, HIGH);   // turn on pullup resistor

  // when not started in motion, the current state of the encoder should be 3
  _oldState = 3;

  // start with position 0;
  _position = 0;
  _positionExt = 0;
} // RotaryEncoder()


long  RotaryEncoder::getPosition() {
  return _positionExt;
} // getPosition()


void RotaryEncoder::setPosition(long newPosition) {
  // only adjust the external part of the position.
  _position = ((newPosition<<2) | (_position & 0x03L));
  _positionExt = newPosition;
} // setPosition()


void RotaryEncoder::tick(void)
{
  int sig1 = digitalRead(_pin1);
  int sig2 = digitalRead(_pin2);
  int8_t thisState = sig1 | (sig2 << 1);

  if (_oldState != thisState) {
    _position += KNOBDIR[thisState | (_oldState<<2)];
    
    if (thisState == LATCHSTATE)
      _positionExt = _position >> 2;
    
    _oldState = thisState;
  } // if
} // tick()

// End

 

 

 

//modified from bildr article: http://bildr.org/2012/08/rotary-encoder-arduino/

//these pins can not be changed 2/3 are special pins
int encoderPin1 = 2;  // breakout PIN A
int encoderPin2 = 3;  // breakout PIN B
int encoderSwitchPin = 4; //breakout PIN SW

volatile int lastEncoded = 0;  // I don't know why the example used an int and a long to store encoder values. May have overflow error somtime
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

void setup() {
  Serial.begin (9600);

  pinMode(encoderPin1, INPUT); 
  pinMode(encoderPin2, INPUT);

  pinMode(encoderSwitchPin, INPUT);
  
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  digitalWrite(encoderSwitchPin, HIGH); //turn pullup resistor on
  
  digitalWrite(6, LOW);
  digitalWrite(5, LOW);


  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3) 
  attachInterrupt(0, updateEncoder, CHANGE); 
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop(){ 
  //Do stuff here
  if(digitalRead(encoderSwitchPin)){
    //button is not being pushed
    digitalWrite(5, LOW);
    digitalWrite(6, HIGH);
    Serial.println("Button NOT Pressed");
    
  }
  else{
    //button is being pushed
    digitalWrite(6, LOW);
    digitalWrite(5, HIGH);
    Serial.println("Button Pressed");
    
  }
 
  Serial.println(encoderValue);
  delay(500); //just here to slow down the output, and show it will work  even during a delay
}


void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number - creates a value by shifting a MSB to left twice and ORing LSB to that shifted MSB
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value  - creates new bit value by shifting lastEncoded to left twice and ORing encoded to it.

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  lastEncoded = encoded; //store this value for next time
}

 

 

 

方法

/* Rotary encoder handler for arduino. v1.1
 *
 * Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
 * Contact: bb@cactii.net
 *
 * A typical mechanical rotary encoder emits a two bit gray code
 * on 3 output pins. Every step in the output (often accompanied
 * by a physical 'click') generates a specific sequence of output
 * codes on the pins.
 *
 * There are 3 pins used for the rotary encoding - one common and
 * two 'bit' pins.
 *
 * The following is the typical sequence of code on the output when
 * moving from one step to the next:
 *
 *   Position   Bit1   Bit2
 *   ----------------------
 *     Step1     0      0
 *      1/4      1      0
 *      1/2      1      1
 *      3/4      0      1
 *     Step2     0      0
 *
 * From this table, we can see that when moving from one 'click' to
 * the next, there are 4 changes in the output code.
 *
 * - From an initial 0 - 0, Bit1 goes high, Bit0 stays low.
 * - Then both bits are high, halfway through the step.
 * - Then Bit1 goes low, but Bit2 stays high.
 * - Finally at the end of the step, both bits return to 0.
 *
 * Detecting the direction is easy - the table simply goes in the other
 * direction (read up instead of down).
 *
 * To decode this, we use a simple state machine. Every time the output
 * code changes, it follows state, until finally a full steps worth of
 * code is received (in the correct order). At the final 0-0, it returns
 * a value indicating a step in one direction or the other.
 *
 * It's also possible to use 'half-step' mode. This just emits an event
 * at both the 0-0 and 1-1 positions. This might be useful for some
 * encoders where you want to detect all positions.
 *
 * If an invalid state happens (for example we go from '0-1' straight
 * to '1-0'), the state machine resets to the start until 0-0 and the
 * next valid codes occur.
 *
 * The biggest advantage of using a state machine over other algorithms
 * is that this has inherent debounce built in. Other algorithms emit spurious
 * output with switch bounce, but this one will simply flip between
 * sub-states until the bounce settles, then continue along the state
 * machine.
 * A side effect of debounce is that fast rotations can cause steps to
 * be skipped. By not requiring debounce, fast rotations can be accurately
 * measured.
 * Another advantage is the ability to properly handle bad state, such
 * as due to EMI, etc.
 * It is also a lot simpler than others - a static state table and less
 * than 10 lines of logic.
 */

#include "Arduino.h"
#include "Rotary.h"

/*
 * The below state table has, for each state (row), the new state
 * to set based on the next encoder output. From left to right in,
 * the table, the encoder outputs are 00, 01, 10, 11, and the value
 * in that position is the new state to set.
 */

#define R_START 0x0

#ifdef HALF_STEP
// Use the half-step state table (emits a code at 00 and 11)
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
const unsigned char ttable[6][4] = {
  // R_START (00)
  {R_START_M,            R_CW_BEGIN,     R_CCW_BEGIN,  R_START},
  // R_CCW_BEGIN
  {R_START_M | DIR_CCW, R_START,        R_CCW_BEGIN,  R_START},
  // R_CW_BEGIN
  {R_START_M | DIR_CW,  R_CW_BEGIN,     R_START,      R_START},
  // R_START_M (11)
  {R_START_M,            R_CCW_BEGIN_M,  R_CW_BEGIN_M, R_START},
  // R_CW_BEGIN_M
  {R_START_M,            R_START_M,      R_CW_BEGIN_M, R_START | DIR_CW},
  // R_CCW_BEGIN_M
  {R_START_M,            R_CCW_BEGIN_M,  R_START_M,    R_START | DIR_CCW},
};
#else
// Use the full-step state table (emits a code at 00 only)
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6

const unsigned char ttable[7][4] = {
  // R_START
  {R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START},
  // R_CW_FINAL
  {R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW},
  // R_CW_BEGIN
  {R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START},
  // R_CW_NEXT
  {R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START},
  // R_CCW_BEGIN
  {R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START},
  // R_CCW_FINAL
  {R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW},
  // R_CCW_NEXT
  {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};
#endif

/*
 * Constructor. Each arg is the pin number for each encoder contact.
 */
Rotary::Rotary(char _pin1, char _pin2) {
  // Assign variables.
  pin1 = _pin1;
  pin2 = _pin2;
  // Set pins to input.
  pinMode(pin1, INPUT);
  pinMode(pin2, INPUT);
#ifdef ENABLE_PULLUPS
  digitalWrite(pin1, HIGH);
  digitalWrite(pin2, HIGH);
#endif
  // Initialise state.
  state = R_START;
}

unsigned char Rotary::process() {
  // Grab state of input pins.
  unsigned char pinstate = (digitalRead(pin2) << 1) | digitalRead(pin1);
  // Determine new state from the pins and state table.
  state = ttable[state & 0xf][pinstate];
  // Return emit bits, ie the generated event.
  return state & 0x30;
}

 

 

/* Rotary encoder handler for arduino. v1.1
 *
 * Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
 * Contact: bb@cactii.net
 *
 * A typical mechanical rotary encoder emits a two bit gray code
 * on 3 output pins. Every step in the output (often accompanied
 * by a physical 'click') generates a specific sequence of output
 * codes on the pins.
 *
 * There are 3 pins used for the rotary encoding - one common and
 * two 'bit' pins.
 *
 * The following is the typical sequence of code on the output when
 * moving from one step to the next:
 *
 *   Position   Bit1   Bit2
 *   ----------------------
 *     Step1     0      0
 *      1/4      1      0
 *      1/2      1      1
 *      3/4      0      1
 *     Step2     0      0
 *
 * From this table, we can see that when moving from one 'click' to
 * the next, there are 4 changes in the output code.
 *
 * - From an initial 0 - 0, Bit1 goes high, Bit0 stays low.
 * - Then both bits are high, halfway through the step.
 * - Then Bit1 goes low, but Bit2 stays high.
 * - Finally at the end of the step, both bits return to 0.
 *
 * Detecting the direction is easy - the table simply goes in the other
 * direction (read up instead of down).
 *
 * To decode this, we use a simple state machine. Every time the output
 * code changes, it follows state, until finally a full steps worth of
 * code is received (in the correct order). At the final 0-0, it returns
 * a value indicating a step in one direction or the other.
 *
 * It's also possible to use 'half-step' mode. This just emits an event
 * at both the 0-0 and 1-1 positions. This might be useful for some
 * encoders where you want to detect all positions.
 *
 * If an invalid state happens (for example we go from '0-1' straight
 * to '1-0'), the state machine resets to the start until 0-0 and the
 * next valid codes occur.
 *
 * The biggest advantage of using a state machine over other algorithms
 * is that this has inherent debounce built in. Other algorithms emit spurious
 * output with switch bounce, but this one will simply flip between
 * sub-states until the bounce settles, then continue along the state
 * machine.
 * A side effect of debounce is that fast rotations can cause steps to
 * be skipped. By not requiring debounce, fast rotations can be accurately
 * measured.
 * Another advantage is the ability to properly handle bad state, such
 * as due to EMI, etc.
 * It is also a lot simpler than others - a static state table and less
 * than 10 lines of logic.
 */
 
    //http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
 
 /* Modified 5/22/2015 by Phill Fisk
  * Added methods and constructor to handle button-equiped rotary encoders
  * Added support methods to return clockwise and counter-clockwise defines
  */

#include "Arduino.h"
#include "rotary.h"

/*
 * The below state table has, for each state (row), the new state
 * to set based on the next encoder output. From left to right in,
 * the table, the encoder outputs are 00, 01, 10, 11, and the value
 * in that position is the new state to set.
 */

#define R_START 0x0

#ifdef HALF_STEP
// Use the half-step state table (emits a code at 00 and 11)
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
const unsigned char ttable[6][4] = {
  // R_START (00)
  {R_START_M,            R_CW_BEGIN,     R_CCW_BEGIN,  R_START},
  // R_CCW_BEGIN
  {R_START_M | DIR_CCW, R_START,        R_CCW_BEGIN,  R_START},
  // R_CW_BEGIN
  {R_START_M | DIR_CW,  R_CW_BEGIN,     R_START,      R_START},
  // R_START_M (11)
  {R_START_M,            R_CCW_BEGIN_M,  R_CW_BEGIN_M, R_START},
  // R_CW_BEGIN_M
  {R_START_M,            R_START_M,      R_CW_BEGIN_M, R_START | DIR_CW},
  // R_CCW_BEGIN_M
  {R_START_M,            R_CCW_BEGIN_M,  R_START_M,    R_START | DIR_CCW},
};
#else
// Use the full-step state table (emits a code at 00 only)
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6

const unsigned char ttable[7][4] = {
  // R_START
  {R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START},
  // R_CW_FINAL
  {R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW},
  // R_CW_BEGIN
  {R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START},
  // R_CW_NEXT
  {R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START},
  // R_CCW_BEGIN
  {R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START},
  // R_CCW_FINAL
  {R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW},
  // R_CCW_NEXT
  {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};
#endif

/*
 * Constructor. Each arg is the pin number for each encoder contact.
 */
Rotary::Rotary(char _pin1, char _pin2) {
  // Moved to init method()
  init(_pin1, _pin2);
}

/*
 * Overloaded constructor, added to support rotary encoders that 
 * also include a button
 */
Rotary::Rotary(char _pin1, char _pin2, char _buttonPin) {
  // intiialize the rotary encoder button
  buttonTimer = 0;
  buttonPin = _buttonPin;
  pinMode(buttonPin, INPUT);
#ifdef ENABLE_PULLUPS
  digitalWrite(buttonPin, HIGH);
#endif

  // run the original initialization
  init(_pin1, _pin2);
}

/*
 * Moved constructor initialization logic here to support multiple constructors
 */
void Rotary::init(char _pin1, char _pin2) {
  // Assign variables.
  pin1 = _pin1;
  pin2 = _pin2;
  // Set pins to input.
  pinMode(pin1, INPUT);
  pinMode(pin2, INPUT);
#ifdef ENABLE_PULLUPS
  digitalWrite(pin1, HIGH);
  digitalWrite(pin2, HIGH);
#endif
  // Initialise state.
  state = R_START;
}

unsigned char Rotary::process() {
  // Grab state of input pins.
  unsigned char pinstate = (digitalRead(pin2) << 1) | digitalRead(pin1);
  // Determine new state from the pins and state table.
  state = ttable[state & 0xf][pinstate];
  // Return emit bits, ie the generated event.
  return state & 0x30;
}

/*
 * Added to return clockwise def. makes sketch easier to read 
 * (just check against this method for movement)
 */
unsigned char Rotary::clockwise() {
  return DIR_CW;
}

/*
 * Added to return counter-clockwise def. makes sketch easier to read 
 * (just check against this method for movement)
 */
unsigned char Rotary::counterClockwise() {
  return DIR_CCW;
}

/*
 * Reads the rotary encoder button, and returns true if the 
 * button has been pressed and released, based on the debounce dealy passed in
 *
 * Presuming the button is wired with one lead to a GPIO pin and the other pin 
 * to ground, the button will read high when open (not pressed) and low when
 * closed (pressed). In other words, a transition of high -> low -> high (1 -> 0 -> 1)
 * will indicate a button "press". The debounce delay is configurable (passed in)
*/
bool Rotary::buttonPressedReleased(short debounce_delay) {
  if (buttonState == BUTTON_PRESSED) {                  // If the button has been pressed
    if (millis() - buttonTimer > debounce_delay) {      // and the debounce timer has expired
      if (digitalRead(buttonPin)) {                     // and the pin reads HIGH (open)
        buttonState |= BUTTON_RELEASED;                 // then the button has been pressed and released
      }
    }
  }
  else {                                                // if the button hasn't been pressed yet, read the pin
    if (!digitalRead(buttonPin)) {                      // if the pin is LOW (closed), then the button has been pushed in
      buttonState |= BUTTON_PRESSED;                    // set the state
      buttonTimer = millis();                           // and start the timer
    }
  }

  // Check to see if the button has been pressed and released
  if (buttonState == (BUTTON_PRESSED | BUTTON_RELEASED)) { 
    buttonState = 0x00;                                 // Reset the button state before returning true
    return true;
  }
  else {
    return false;
  }
}

/*
* Reads the encoder button, and returns true if the button has been
* pressed and held down for a given amount of time.
*/
bool Rotary::buttonPressedHeld(short delay_millis) {
  // Is the button closed (being pressed)?  
  if (!digitalRead(buttonPin)) {
    // If this is the first time we've checked the button, set the state and start the timer
    if (buttonState != BUTTON_PRESSED) {
      buttonState = BUTTON_PRESSED;
      buttonTimer = millis();
    }
    else {
      // Otherwise, check the timer to see if it's expired
      if (millis() - buttonTimer > delay_millis) {
        // the wait timer has expired, reset the button state
        buttonState = BUTTON_RESET;
        // and return true indicating the button has been held down for long enough
        return true;
      }
    }
  }
  else {
    // button is open (not being pressed) was it already pressed?
    if (buttonState == BUTTON_PRESSED) {
      // it was pressed and released too quickly, reset it
      buttonState = BUTTON_RESET;
    }
  }

  return false;
}

/*
* Reads the encoder button and returns the current state (pressed OR released)
* Does not return the composite state (just for checking the state right now)
*/
unsigned char Rotary::readButton() {
  if (digitalRead(buttonPin)) {
    return BUTTON_RELEASED;
  }
  else {
    return BUTTON_PRESSED;
  }
}

/*
* Resets the state of the button
*/
void Rotary::resetButton() {
  buttonState = BUTTON_RESET;
}

 

posted @ 2017-04-05 18:59  sinferwu  阅读(924)  评论(0)    收藏  举报