05. Mit ne használjunk Arduino projektekben - Külső prellmentesítés rotary-enkóderhez

Számos esetben lehet látni, hogy kapacitással és/vagy logikai IC-vel kezelik a prellt a rotary enkóderek esetén. A rotary enkóderek két pint-t használnak, az órajel és az elmozdulás-kivezetést. A kondenzátor és a felhúzóellenállás egy késleltető tagot alkot, így történik meg a prellmentesítés. 

Ennek a megoldásnak a hátránya, hogyha gyors enkóderjel érkezik, akkor az impulzusok kimaradhatnak, vagy a lassú felfutó jel miatt akár hibás eredményt is kaphatunk. A kondenzátor és a felhúzó ellenállás értékeit nem lehet ilymódon ökölszabályok alapján beültetni, hogy a felhúzó 4k7...10k, a kondenzátor meg 100nF legyen. Sőt, akár a belső felhúzó is lehet, hogy elég....


A szofveres prellmentesítés sokkal egyszerűbb és még forrasztani sem kell. Külön előny, hogy többféle enkóderhez könnyen illeszthető - függően a prell hosszától.

Az enkóderek kezelése során elegendő 4 állapot megkülönböztetése. Ebből a forgásirány könnyen meghatározható. Ha a prellmentsítés szoftverből kerül megvalósításra az egyes különféle prellhosszúságú enkóderek is könnyen illeszthetővé válnak, nem kell az elektronika hardware részében semmit sem módosítani. Az enkóder két kimenettel rendelkezik, mely az Arduino két lábát foglalja el. A bekötése egyszerű (mint az előző ábra - csak a prellmentesítő kondenzátorok nélkül).

Fontos! A külső felhúzóellenállások szkséges értéke 1...10kohm. Ha csak a belső felhúzóellenállásokat használjuk, a rendszer zavarérzékeny lesz!

Az enkóder működési diagrammja:


A legegyszerűbb enkóder kezelő Arduino kód:

 
// Class to interface Arduino to rotary encoders
// D Crocker, Escher Technologies Limited, October 2011.
// This code may be freely used for any purpose
// but is supplied without warranty.
//
// Declare a rotary encoder like this:
//
// RotaryEncoder encoder(leftPin, rightPin, pulsesPerClick);
//
// where pulsesPerClick is normally 4.
// Every 1 millisecond or so, call:
//
// encoder.poll();
//
// To find how much the encoder has moved since you last asked, do this:
//
// int movement = encoder.getChange();
class RotaryEncoder
{
  unsigned int state;
  int pin0, pin1;
  int ppc;
  int change;
unsigned int readState()
{
  return (digitalRead(pin0) == HIGH ? 1u : 0u)
       | (digitalRead(pin1) == HIGH ? 2u : 0u);
}
public:
  RotaryEncoder(int p0, int p1, int pulsesPerClick) :
  pin0(p0), pin1(p1), ppc(pulsesPerClick), change(0), state(0) {}
  void init();
  void poll();
  int getChange();
};
void RotaryEncoder::init()
{
  pinMode(pin0, INPUT);
  pinMode(pin1, INPUT);
  digitalWrite(pin0, 1);  // enable internal pullup
  digitalWrite(pin1, 1);  // enable internal pullup
  change = 0;
  state = readState();
}
void RotaryEncoder::poll()
{
  // State transition table
  static int tbl[16] =
  { 0, +1, -1, 0,
    // position 3 = 00 to 11, can't really do anythin, so 0
    -1, 0, -2, +1,
    // position 2 = 01 to 10, assume a bounce, should be 01 -> 00 -> 10
    +1, +2, 0, -1,
    // position 1 = 10 to 01, assume a bounce, should be 10 -> 00 -> 01
    0, -1, +1, 0
    // position 0 = 11 to 10, can't really do anything
  };
  unsigned int t = readState();
  int movement = tbl[(state << 2) | t];
  if (movement != 0)
  {
    change += movement;
    state = t;
  }
}
int RotaryEncoder::getChange()
{
  int r;
  noInterrupts();
  if (change >= ppc - 1)
  {
    r = (change + 1)/ppc;
  }
  else if (change <= 1 - ppc)
  {
    r = -((1 - change)/ppc);
  }
  else
  {
    r = 0;
  }
  change -= (r * ppc);
  interrupts();
  return r;
}

TavIR-Facebook