Jul 172011
Potentiometers are the easiest way to get an analog value into the Arduino. Nice for e.g. volume control or setting the speed of a fan or the brightness of a lamp.
A more digital way is to use rotary encoder instead which return pulses or even absolute positions. I found one here and it works as expected. Without using interrupts I was able to decode it just fine, but this really should be done via interrupts, but I never used interrupts before, so I checked via Google and found this. Works well and does not need a polling loop. The rotary encoder even looks identical to the one I bought.
For reference here the short test program:
/**
* A simple incremental Rotary Encoder decoder example
* andrew@rocketnumbernine.com
* http://www.rocketnumbernine.com/2010/03/06/decoding-a-rotary-encoder/
* use freely
*/
#include <util/delay.h>
volatile uint8_t pinValues[2] = {0,0};
volatile int position = 0;
const int APin=2;
const int BPin=3;
void setup()
{
Serial.begin(38400);
pinMode(APin, INPUT); // 2 Encoder pins as inputs
pinMode(BPin, INPUT);
digitalWrite(APin, HIGH); // use internal pull-ups
digitalWrite(BPin, HIGH);
// enable interrupts on those two pins:
// Depends on APin=2 and BPin=3
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();
}
ISR(PCINT2_vect)
{
_delay_ms(1);
int pin0 = digitalRead(APin);
int pin1 = digitalRead(BPin);
if (pin0 != pinValues[0]) {
rotary_encoder_change(0, pin0);
} else if (pin1 != pinValues[1]) {
rotary_encoder_change(1, pin1);
}
}
void rotary_encoder_change(uint8_t changedPin, uint8_t value)
{
pinValues[changedPin] = value;
position += ((pinValues[0] == pinValues[1]) ^ changedPin) ? 1 : -1;
}
void loop()
{
Serial.println(position);
delay(200);
}
Small addition: Arduino Playground has some more info.