//From bildr article: http://bildr.org/2012/08/rotary-encoder-arduino/ //Note: This code is for reference only. It may not work! class RotaryEncoder { public: //Identification information int encoderPin1; //Encoder data 1 int encoderPin2; //Encoder data 2 int encoderBtnPin; //Integrated pushbutton input //Data processing information volatile int lastEncoded; //voltaile long encoderValue; boolean newValue; //Allows loop program to send serial data outside of interrupt boolean rotDirection; //Rotation Direction, CW = 0, CCW = 1 unsigned long lastClickTime; //Stores the last time the button was clicked for determining double clicks boolean dblClicked; //Double clicked? //int lastMSB; //Last most significant bit //int lastLSB; //Last least significant bit //Constructor RotaryEncoder(int nPin1, int nPin2, int nPin3); //Methods boolean isNew(); boolean hasDblClicked(); void SendRot(); void SendDblClick(); }; RotaryEncoder::RotaryEncoder(int nPin1, int nPin2, int nPin3) { encoderPin1 = nPin1; encoderPin2 = nPin2; encoderBtnPin = nPin3; lastEncoded = 0; newValue = false; lastClickTime = 0; dblClicked = false; //lastMSB = 0; //lastLSB = 0; pinMode(encoderPin1, INPUT_PULLUP); pinMode(encoderPin2, INPUT_PULLUP); pinMode(encoderBtnPin, INPUT_PULLUP); //call updateEncoder() when any high/low changed seen attachInterrupt(encoderPin1, updateEncoder, CHANGE); attachInterrupt(encoderPin2, updateEncoder, CHANGE); attachInterrupt(encoderBtnPin, encoderBtn_ISR, CHANGE); //Button interrupt service handler @todo } boolean RotaryEncoder::isNew() { return newValue; } boolean RotaryEncoder::hasDblClicked() { return dblClicked; } /* Rotary Encoder Message Format The format is similar to the other formats used: [00001] [0] [00] [0] [0000000] ID # Type Value Super speed Don't Care The ID number, 1, is reserved for the rotary encoder The type is binary (0) The value can be: 0 = CW, 1 = CCW, 2 = Double Click The super speed bit is 1 when the rotary dial is pressed down and held while rotating It speeds up scrolling by letting the computer know to send multiple rotation messages detent */ void RotaryEncoder::SendRot() { newValue = false; //Reset the flag int message = 0; message |= rotDirection; message <<= 1; //Shift the value left 1 bit to make room for super speed bit message |= digitalRead(encoderBtnPin); //Add in the value of the integrated push button message <<= 7; //Shift the value left 7 bits to line it up with the data format sendMessage(1, 0, message); } void RotaryEncoder::SendDblClick() { dblClicked = false; //Reset the flag sendMessage(1, 0, 0b0000001100000000); //Send a binary 2 in the value position (indicates Dbl Click) //Note that we do not care about the super speed bit in this situation } RotaryEncoder encoder(P2_0, P2_1, P2_2); //New rotary encoder connected to pins 8-10 void setup() { Serial.begin (9600); } void loop() { if(encoder.isNew()) encoder.SendRot(); if(encoder.hasDblClicked()) encoder.SendDblClick(); } void sendMessage(int a, int b, int c) //Placeholder function { } void updateEncoder() { int MSB = digitalRead(encoder.encoderPin1); //MSB = most significant bit int LSB = digitalRead(encoder.encoderPin2); //LSB = least significant bit int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number int sum = (encoder.lastEncoded << 2) | encoded; //adding it to the previous encoded value if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) //CW { encoder.newValue = true; encoder.rotDirection = false; //CW } if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) //CCW { encoder.newValue = true; encoder.rotDirection = true; //CCW } encoder.lastEncoded = encoded; //store this value for next time } //Called when the encoder button is pressed void encoderBtn_ISR() { /*if(lastClickTime == 0) //Last click time has been reset, this is the first click lastClickTime = millis(); else //This is another click (or bounce?) {*/ unsigned long deltaClickTime = millis()-encoder.lastClickTime; if(deltaClickTime >= 100 && deltaClickTime < 300) //Lower/upper limit 1/10 to 3/10 second encoder.dblClicked = true; //It's within range, set the flag else if(deltaClickTime > 300) //It's over the length of time, reset the lastClickTime encoder.lastClickTime = millis(); //} }