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.
Budeme potrebovať:
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.
Toto je dobrý príklad projektu, pri ktorom zákmity na kontaktoch nevadia.
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() {
}
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é texty sú na GitHub.
24.12.2015