/* Quadrature divider for a high resolution quadrature encoder Takes the quad inputs from the encoder (encoder pin A to Arduino pin 2, encoder pin B to Arduino pin 3 & encoder ground pin to ground (GND), produces two outputs, 'strobeA' (pin 4) and 'strobeB' (pin 5). The division ratio can be between 2 & 255 Basically the code initialises a counter with the division ratio. On each state change of the encoder, the counter is decremented, however if the direction of the encoder has changed, the counter is re-initialised, and the process starts again. When the counter reaches zero, the code enters a 'finite state machine' formed by the switch (state) and subsequent case statements. Tested it with my optical encoder,not sure what its resolution is, but it is Type H38S400B. Turning it as quickly as I could, the minimum pulse width from the encoder seemed to be about 500uS, so I guess even this polling method should not miss any encoder pulses. This source file is under General Public License version 3. Please feel free to distribute it, hack it, or do anything else you like to it. A collaboration between Jim Smith - G3ZQC and Glenn Percy - VK3PE Date: 23/07/2018 Date: 26/07/2018 added Direction output. Date: 05/08/2018 Jim, fixed bug. Runs on Arduino Nano (and Nano Zero) & ATtiny85 */ #include //https://github.com/buxtronix/arduino/tree/master/libraries/Rotary // Pin definitions for 'Glenn' are for an ATtiny85 #define encA 2 #define encB 1 //3 jim (NANO) //1 Glenn (ATtiny85) #define StrobeA 4 #define StrobeB 3 //jim 5 (NANO) //3 Glenn (ATtiny85) #define direction 0 //now implemented glenn (ATtiny85) // #define CW 1 #define CCW 0 Rotary r = Rotary(encA, encB); int div_ratio = 12; //16 // Set division ratio to required value between 2 and 255 int dir; int prev_direction = CW; int counter; int State; struct State { int Out; int Next[2]; }; typedef const struct State STyp; #define notAnotB 0 #define AnotB 1 #define notAB 2 #define AB 3 STyp FSM[4]= { {0x00,{notAB,AnotB}}, //State 0 notA & notB {0x01,{notAnotB,AB}}, //State 1 A & notB {0x02,{AB,notAnotB}}, //State 2 notA & B {0x03,{AnotB,notAB}} //State 3 A & B }; // void Set_Outputs(int State) { if (State == 2 || State == 3) { digitalWrite(StrobeA, HIGH); // Set Strobe A high since bit 1 is set } else { digitalWrite(StrobeA, LOW); } if (State == 1 || State == 3) { digitalWrite(StrobeB, HIGH); // Set Strobe B high, since bit 0 is set } else { digitalWrite(StrobeB, LOW); } } void setup() { counter = div_ratio / 2; // Set counter to initial value State = 0; pinMode(StrobeA, OUTPUT); pinMode(StrobeB, OUTPUT); digitalWrite(StrobeA, LOW); digitalWrite(StrobeB, LOW); pinMode(direction, OUTPUT); } void loop() { unsigned char result = r.process(); if (result) { dir = CCW; //digitalWrite(direction, LOW); //CCW = Logic LOW output on 'direction" pin if (result == DIR_CW) { dir = CW; //digitalWrite(StrobeA, LOW); // I think this is the bug !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 050818 Jim //digitalWrite(direction, HIGH); //CW = Logic HIGH output on 'direction" pin } digitalWrite(direction, dir); //Set 'direction' pin HIGH for CW, LOW for CCW if (dir == prev_direction) { counter--; // Decrement the counter if the encoder is turned in the same direction. } else { prev_direction = dir; counter = div_ratio / 2; // Set the counter to its initial value if the direction of rotation has been changed. } if (counter == 0) { State = FSM[State].Next[dir]; Set_Outputs(State); counter = div_ratio / 2; } } }