// We use 4-character tabstops, so IN VIM: :set ts=4 sw=4 // ...that's: ESCAPE key, colon key, then "s-e-t SPACE key t-s-=-4 SPACE key s-w-=-4 CARRIAGE RETURN key" /* AdaEncoder.h - A library for reading Lady Ada's or Sparkfun's rotary encoder. Should work for any rotary encoder with 2 pins (4 states). Version 0.7 Tue Nov 20 17:56:29 CST 2012 */ /* Copyright 2011 Michael Schwager (aka, "GreyGnome") This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Questions? Send mail to mschwage@gmail.com */ /* Behavior goes like this: * 11 is the detent position for an encoder. So the encoder will go through an order like this: * 11 <=> 01 <=> 00 <=> 10 <=> 11 OR 11 <=> 10 <=> 00 <=> 01 <=> 11 * depending on direction. The <=> represent a possible bounce situation. Therefore, we keep track of the * encoder behavior in a binary number called (appropriately enough) encoder. Encoder has 8 bits. * * The process starts when we get an interrupt and read the encoder pins. * - Reading: 11 is either a bounce back to start, or the final reading: * - If encoder is currently xxxx0001, you have advanced CW. * - If encoder is currently xxxx0010, you have advanced CCW. * - otherwise, you'd simply bounced. No advance. * - "encoder" is set to xxxx1111. * - Reading: 01 or 10: * - If "encoder" is currently xxxx1111, set it to 1101 or 1110, appropriately. * - If "encoder" is xxxx00xy, you'd either bounced or moved to the next position, which means we get closer to detent. No effect. * - Reading: 00: we are in the middle. AND encoder with xxxx0011 */ #undef DEBUG #ifndef AdaEncoder_h #define AdaEncoder_h #ifndef PinChangeInt_h #define LIBCALL_OOPINCHANGEINT #include "../ooPinChangeInt/ooPinChangeInt.h" #endif #include "../cbiface/cbiface.h" #if defined(ARDUINO) && ARDUINO >= 100 #include #else #include #include #endif // The Pin map below is copyright by the Arduino people. I include it here so I can remember stuff as I code. // ATMEL ATMEGA8 & 168 / ARDUINO // // // // +-\/-+ // // PC6 1| |28 PC5 (AI 5) // // (D 0) PD0 2| |27 PC4 (AI 4) // // (D 1) PD1 3| |26 PC3 (AI 3) // // (D 2) PD2 4| |25 PC2 (AI 2) // // PWM+ (D 3) PD3 5| |24 PC1 (AI 1) // // (D 4) PD4 6| |23 PC0 (AI 0) // // VCC 7| |22 GND // // GND 8| |21 AREF // // PB6 9| |20 AVCC // // PB7 10| |19 PB5 (D 13) // // PWM+ (D 5) PD5 11| |18 PB4 (D 12) // // PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM // // (D 7) PD7 13| |16 PB2 (D 10) PWM // // (D 8) PB0 14| |15 PB1 (D 9) PWM // // +----+ // // const static uint8_t A0 = 14; // const static uint8_t A1 = 15; // const static uint8_t A2 = 16; // const static uint8_t A3 = 17; // const static uint8_t A4 = 18; // const static uint8_t A5 = 19; // const static uint8_t A6 = 20; // const static uint8_t A7 = 21; // // Macros to find pins: // #define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) // #define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) // #define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) // #define analogInPinToBit(P) (P) // #define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) // #define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) // #define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) /* struct encoder { volatile uint8_t* port; uint8_t bitA; uint8_t bitB; uint8_t turning; // Flag to keep track of turning state int8_t clicks; // Counter to indicate cumulative clicks in either direction int8_t direction; // indicator char id; encoder *next; };*/ class AdaEncoder : public CallBackInterface { public: AdaEncoder(char _id, uint8_t _pinA, uint8_t _pinB) { /* * Add a new encoder * Params : * pinA CW pin (Arduino pin number) * pinB CCW pin * */ addEncoder(_id, _pinA, _pinB); } int8_t query(); // BUG under pre-0.7 versions (had uint8_t) int8_t getClicks(); // BUG under pre-0.7 versions (had uint8_t) char getID(); static AdaEncoder *getFirstEncoder(); static AdaEncoder *genie(); static AdaEncoder *genie(int8_t *clicks, char *id); // GEt Next Indicated Encoder - gets the next encoder with non-zero clicks private: void addEncoder(char _id, uint8_t _pinA, uint8_t _pinB); void attachInterrupt(uint8_t _pinA, uint8_t _pinB); void cbmethod(); static void debugMessage(); static void turnOffPWM(uint8_t timer); volatile uint8_t* port; uint8_t pinA, bitA; uint8_t pinB, bitB; uint8_t turning; // Flag to keep track of turning state int8_t clicks; // Counter to indicate cumulative clicks in either direction int8_t direction; // indicator char id; AdaEncoder *next; }; #endif //AdaEncoder.h