Project:Arduino Rotary Encoder Menu System

From Nottinghack Wiki
Revision as of 23:10, 29 July 2012 by Msemtd (talk | contribs)
Jump to navigation Jump to search

I have recovered a number of ALPS rotary encoders from discarded industrial CRT monitors. I'm working on building a user interface menu system that makes use of the rotary encoders as the sole input technique.

Rotary Encoder Test Sketch With Interrupts (non-PWM)

#define PIN_ENC1 2
#define PIN_ENC2 3
#define PIN_EBTN 4
#define PIN_LED1 13
static boolean moving=false;
volatile unsigned int encValue = 0;
unsigned int encValueTracking = 1;
boolean enc1 = false;              
boolean enc2 = false;

// Here I'm messing around with button press durations - we could go to town here!
enum pressDuration { reallyQuickPress, shortPress, normalPress, longPress, veryLongPress };
long presses[] = { 40, 150, 300, 800, 1400 };
char* pressText[]={"really quick press!", "short press", "normal press", "long press", "very looooooooong press"};

void setup() 
{
  pinMode(PIN_ENC1, INPUT); 
  pinMode(PIN_ENC2, INPUT); 
  pinMode(PIN_EBTN, INPUT);
  pinMode(PIN_LED1, OUTPUT);
  digitalWrite(PIN_ENC1, HIGH);
  digitalWrite(PIN_ENC2, HIGH);
  digitalWrite(PIN_EBTN, HIGH);
  Serial.begin(9600);
  menuIntro();
  attachInterrupt(0, intrEncChange1, CHANGE);
  attachInterrupt(1, intrEncChange2, CHANGE);
}

void intrEncChange1()
{
  if(moving) 
    delay(1);
  if(digitalRead(PIN_ENC1) == enc1)
    return;
  enc1 = !enc1;
  if(enc1 && !enc2) 
    encValue += 1;
  moving = false;
}

void intrEncChange2()
{
  if(moving) 
    delay(1);
  if(digitalRead(PIN_ENC2) == enc2)
    return; 
  enc2 = !enc2;
  if(enc2 && !enc1) 
    encValue -= 1;
  moving = false;
}

void loop() 
{ 
  static unsigned long btnHeld = 0;
  moving = true;
  if(encValueTracking != encValue){
    Serial.print("encValue: ");
    Serial.println(encValue, DEC);
    encValueTracking = encValue;
  }
  // Upon button press...
  if((digitalRead(PIN_EBTN) == LOW) && !btnHeld){
    btnHeld = millis();
    digitalWrite(PIN_LED1, HIGH);
    Serial.print("pressed selecting: ");
    Serial.println(encValue, DEC);
  }
  // Upon button release...
  if((digitalRead(PIN_EBTN) == HIGH) && btnHeld){
    long t = millis();
    t -= btnHeld;
    digitalWrite(PIN_LED1, LOW);
    int dur = veryLongPress;
    for(int i = 0; i<= veryLongPress; i++){
      if(t > presses[i])
         continue;
      dur = i;
      break;
    }
    
    Serial.print("released selecting: ");
    Serial.print(encValue, DEC);    
    Serial.print(" (after ");
    Serial.print(t, DEC);
    Serial.print(" ms = ");
    Serial.print(pressText[dur]);
    Serial.println(")");
    btnHeld = 0;
  }
}

void menuIntro()
{
  Serial.println("Encoder Menu - blah, blah, blah");
}

multiple encoders

Try out http://code.google.com/p/adaencoder/ and PinChangeInt library (http://code.google.com/p/arduino-pinchangeint/) see...

http://arduino.cc/playground/Main/RotaryEncoders#Example14

See if it can cope with two encoders at rapid rate usage.

OK, working well --Michael Erskine 18:10, 29 July 2012 (EST)

When using the Raspberry Pi as the menu display system we need to do a few things to a stock raspbian install...

  • auto login and start X: use option in raspi-config
  • switch off screen blanking: /etc/lightdm/lightdm.conf in SeatDefaults section "xserver-command=X -s 0 -dpms"
  • auto start application

moving the cursor with Perl Tk