I have been recently trying to get a rotary encoder to work and I found this to be the easiest way for me. It uses interrupts, thus no need for pin polling. If you are not familiar with interrupts you might need to educate yourself.
Can be used with any interrupt available, you just need to change the interrupt vector and PCMSK. Suitable for external interrupts as well. You might need to delete that if statement when detecting LOW state on CLK_PIN.
// Needs an RC low-pass filter on inputs: R = 33 kohm, C = 100 nF (104)
// Simple and working.
// Triggers when not a full step is made -> usable for GUI
// -> NOT usable for close loop motion control,...
// define pins
#define DT_PIN 7 // data pin
#define CLK_PIN 6 // clock pin
//demo variable
volatile int state = 0;
void setup() {
// setup pin change interrupt on pin 6 (PCINT22)
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT22);
Serial.begin(9600);
}
void loop() {
}
ISR(PCINT2_vect) {
// pin is normaly HIGH, trigger on falling edge, pin is LOW after pin change interrupt
if (!digitalRead(CLK_PIN)) {
//if data pin is HIGH when triggered due to phase shift, increment variable
if (digitalRead(DT_PIN)) {
state++;
}
// if data pin is low when triggered due to phase shift, decrement variable
else {
state--;
}
//print result
Serial.println(state);
}
}
Serial.println() inside of an ISR? How does that work for you?
groundFungus:
Serial.println() inside of an ISR? How does that work for you?
Not well at all...
Encoders are a topic that have been beaten to death and I find it curious why people feel the need to reinvent the wheel over and over again, investing time and gaining nothing in the end. Interrupt driven encoders have already been done and done well.
https://www.pjrc.com/teensy/td_libs_Encoder.html
The KY-040 is normally turned by humans. You don't need interrupts for this, it makes software debouncing harder (you obviously had problems with contact bounce considering the mention of 100 nF caps on the inputs, which in case of software debounce are redundant).
groundFungus:
Serial.println() inside of an ISR? How does that work for you?
The "Serial.println()" is within the ISR because I did not need to put it elsewhere. It is there just to report the status (9600 baudrate).
wvmarle:
The KY-040 is normally turned by humans. You don't need interrupts for this, it makes software debouncing harder (you obviously had problems with contact bounce considering the mention of 100 nF caps on the inputs, which in case of software debounce are redundant).
It is not really software debouncing. If the capacitors hadn't been there, the interrupt would have been triggered multiple times. (Did not test it myself.)
WattsThat:
Not well at all...
Encoders are a topic that have been beaten to death and I find it curious why people feel the need to reinvent the wheel over and over again, investing time and gaining nothing in the end. Interrupt driven encoders have already been done and done well.
Encoder Library, for Measuring Quadarature Encoded Position or Rotation Signals
Yes, I am aware of reinventing the wheel, but I would rather reinvent something simple by myself and learn from it than to be trying to solve complex problems (I have stepper acceleration and deceleration in mind) and "gain nothing in the end". Yes I could copy and paste code from others (or use a library) but that is pointless if I need to learn something and implement it somewhere, where perhaps the microchip is too bussy to be constantly checking a pin change.
I want to learn and understand stuff and not just glue things together without understanding its function. This way I will understand the code and I can change it whenever I want.
I just thought someone might find it useful.
P.S. Eventhough it says I am a newbie, I have been using Arduino for 3-4 years. However I am still grateful for any helpful answers and opportunities to learn.
Serial.print() uses interrupts to work. In an ISR interrupts are disabled. See the problem? Sure, printing in an ISR may work this time but it will not always work and can be a hard to find bug in a larger program.
Better to set a (volatile) flag in the ISR and, in loop(), print if the flag is set, then clear the flag.
groundFungus:
Serial.print() uses interrupts to work. In an ISR interrupts are disabled. See the problem? Sure, printing in an ISR may work this time but it will not always work and can be a hard to find bug in a larger program.
Better to set a (volatile) flag in the ISR and, in loop(), print if the flag is set, then clear the flag.
Yes, I know that. I guess I should have written it there. My bad. I could have also used cli() and sei().
MStarha:
If the capacitors hadn't been there, the interrupt would have been triggered multiple times. (Did not test it myself.)
Which is again why you shouldn't use interrupts in the first place...
As I said, it is just what I was testing and what I learned. It is definetely not the only way to do it, but it is what I will probably need in the future.
If such posts do not belong to this thread (or forum), feel free to correct me. I'd be happy to learn something new.