ATtiny85 a rotačný enkodér

Zápisník experimentátora

Hierarchy: Rotačný enkodér

V tomto článku využijeme mikrokontrolér ATtiny85 a rotačný enkodér na ovládanie jasu LED diódy. Pomocou rotačného enkodéra budeme nastavovať úroveň jasu, ktorú bude mikrokontrolér pomocou PWM modulácie používať na ovládanie LED. Úroveň jasu budeme transformovať tak, aby malo oko pocit lineárnej zmeny.

Budeme vychádzať z článku na Technoblogy, ktorý mi poslúžil za základ kódu. Pôvodný kód som ale upravil do čitateľnejšej podoby a zmenil som ovládanie LED diódy, aby netrpela drobným poblikávaním, ktoré spôsobujú zákmity na rotačnom enkodéri.

Súčiastky

Budeme potrebovať:

  • ATtiny85 - Tento malý mikrokontrolér má síce len 8 pinov, ale s veľkosťou pamäte 8k je na väčšinu malých projektov dostačujúci. O jeho používaní som písal veľa na pôvodných stránkach.
  • Rotačný enkodér - Napríklad tento z Banggood alebo z Ebay. Keď som kupoval ja, najvýhodnejšie sa javilo kúpiť 5 kusov na Ebay. Tie s tlačidlom sú drahšie, ale máte zase funkciu naviac, ktorá sa dá aj využiť.
  • Skúšobné pole - Zastrčenie enkodéra je trošku problematické. Musel som na ňom odštiknúť dva bočné pliešky, ktoré sa používajú na pevnejšie uchytenie enkodéra do plošného spoja. A piny na enkodéri sú trochu hrubšie.

Schéma

V programe budeme používať interné pull-up rezistory, preto si to môžeme dovoliť zapojiť takto. Tieto rezistory nám zodvihnú napätie na bodoch A a B na 5 V. Pri otáčaní hriadeľom sa budú skratovať na GND a dávať nám signály pre Arduino.

Nenašiel som vo Fritzingu model rotačného enkodéra s tlačidlom, preto je v schéme tlačidlo zakreslené extra.

Zákmity

Toto je dobrý príklad projektu, pri ktorom zákmity na kontaktoch nevadia.

  • Tlačidlo ovláda polovičný jas. Zaujíma nás v programe len to, či je stlačené alebo nie.
  • Otáčanie hriadeľom spôsobuje v programe zmenu premennej, podľa ktorej nastavujeme PWM pre LED diódu. Premenná môže nadobúdať hodnoty 0-255. Prípadné zákmity majú nepatrný vplyv na výsledný jas, pretože v najhoršom prípade nám dokážu posunúť obsah tejto premennej iba o pár hodnôt naľavo alebo napravo. Ľudské oko by to mohlo zbadať iba pri nízkych hodnotách, kde sme v blízkosti nuly. Tam by sme mohli vidieť blikanie, pretože rozdiel čistej tmy a jemného jasu ľudské oko dobre rozozná. Pretože ale používame lineárnu zmenu jasu, ktorú si vyberáme z pripravenej tabuľky, posuny v indexe o pár miest v blízkosti nuly dodajú rovnakú výslednú hodnotu jasu.

Programovanie

Program je uverejnený v skrátenej podobe. Plnú verziu si môžete stiahnuť v hyperlinku na konci článku.

Pôvodný program som zmodifikoval na viacerých miestach. Upravil som PWM signál tak, aby sa oku javilo stmievanie lineárne. Na to je potrebné mať zadefinované LINEAR_BRIGHTNESS. Bez neho je stmievanie v pôvodnom tvare a vtedy sa najmä pri nízkom jase prejavuje poblikávanie zo zákmitov.

Reakcia celého programu prichádza zo spracovania prerušenia PCINT0.To je reakcia na prerušenie pin change, o ktorom som písal v súvislosti s Arduinom na inom mieste. Celé nastavenie je vo funkcii setup.

const int LED = 0;
const int EncoderA = 1;
const int EncoderB = 2;
const int EncoderSwitch = 3;

// table of exponential values
// generated for values of i from 0 to 255 -> x=round( pow( 2.0, i/32.0) - 1);
const byte table[] PROGMEM = {
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 ...
180, 184, 188, 192, 196, 201, 205, 210, 214, 219, 224, 229, 234, 239, 244, 250
};

// Global - lamp brightness
volatile int Brightness = 3*16;

#define LINEAR_BRIGHTNESS

// Pin change interrupt service routine
ISR (PCINT0_vect) {
  static int Laststate = 0;
  int Gray = (PINB & (1<<EncoderA | 1<<EncoderB))>>EncoderA; // Read PB1 and PB2
  int State = (Gray>>1) ^ Gray;              // Convert from Gray code to binary
  if (State != Laststate) {
    int Value = ((Laststate-State) & 3) - 2; // Gives -1 or +1
    ChangeValue(Value);
    Laststate=State;
  } else
    ChangeSwitch((PINB & 1<<EncoderSwitch)>>EncoderSwitch);     // Gives 0 or 1
  GIFR = 1<<PCIF;                       // Clear pin change interrupt flag.
}

// Called when encoder switch is pressed; On is 0 (down) or 1 (up)
void ChangeSwitch (int On) {
  int b = On ? Brightness : Brightness/2;
  #if defined(LINEAR_BRIGHTNESS)
  b = pgm_read_byte(&table[b]);
  #endif
  analogWrite(0, b);
}

// Called when encoder is rotated; Change is -1 (anticlockwise) or 1 (clockwise)
void ChangeValue (int Change) {
  Change = constrain(Change, -1, 1);
  Brightness = constrain(Brightness+Change, 0, 255);
  int b = Brightness;
  #if defined(LINEAR_BRIGHTNESS)
  b = pgm_read_byte(&table[b]);
  #endif
  analogWrite(0, b);
}
  
void setup() {
  pinMode(LED, OUTPUT);
  pinMode(EncoderA, INPUT_PULLUP);
  pinMode(EncoderB, INPUT_PULLUP);
  pinMode(EncoderSwitch, INPUT_PULLUP);
  
  ChangeValue(0); // default brightness

  // Configure pin change interrupts on PB1, PB2, and PB3
  PCMSK |= 1<<PCINT1 | 1<<PCINT2 | 1<<PCINT3;
  GIMSK = 1<<PCIE;                // Enable pin change interrupts
  GIFR = 1<<PCIF;                 // Clear pin change interrupt flag.
}

// Everything done under interrupt!
void loop() {
}

Video

Vo videu je vidno, ako sa pri otáčaní hriadeľom postupne mení intenzita jasu. Pri stlačení tlačidla sa intenzita jasu mení na polovičnú úroveň.

Zdrojový kód

Zdrojové texty sú na GitHub.



Download

24.12.2015


Menu