ATtiny85 - Tlačítka

Zápisník experimentátora

Hierarchy: ATtiny85

Tlačítka jsou jednoduché součástky, pomocí kterých můžete komunikovat s mikrokontrolérem. Obvykle se využívají mikrospínače, které najdete i v běžné spotřební elektronice. V dnešním článku si vysvětlíme základní použití tlačítek a naprogramujeme si i jednoduchý stavový automat, ve kterém budeme muset ošetřit zákmity tlačítek.

Jak funguje tlačítko

Tlačítko je jednoduchá součástka. Stisknutím tlačítka se mezi sebou vodivě propojí dva vývody. V mikrokontroléru ATtiny85 víme na pinu zjistit, zda se na něm nachází logická nula nebo jednotka. Kdybychom ale tlačítko napřímo připojili, jeden konec na pin a druhý na GNG nebo VCC, nedokázali bychom spolehlivě rozlišit, zda je na tlačítku v rozpojeném stavu nějaká definovaná úroveň napětí. Proto se využívá pull-up rezistor, který nám tlačítko v rozpojeném stavu přidrží na úrovni VCC. V praxi se pak často namísto externího rezistoru využívá interní pull-up rezistor, který je přímo v mikrokontroléru.

Protože v mikrokontroléru ATtiny85 máme pouze interní pull-up rezistory, obvykle budeme tlačítko připojovat tak, jak je nakresleno ve schématu. Stisknuté tlačítko bude na pinu signalizovat logickou nulu a nestlačené tlačítko logickou jednotku. Obvyklá hodnota pro rezistor je 10k. Pokud použijeme interní rezistor, jeho hodnota je přibližně 50k. Tato hodnota není kritická a pouze ve výjimečném případě (například při zvýšeném riziku výskytu rušivých signálů) by se mohla použít jiná hodnota.

Indikace stisknutí tlačítka pomocí LED

Nejjednodušším příkladem je rozsvícení LED diody při stisknutí tlačítka. Zapojení je podle přiloženého schématu. Rezistor při tlačítku má hodnotu 10k, rezistor při LED diodě má hodnotu 1k. Abychom mohli přečíst logickou hodnotu na pinu, musíme pin definovat jako vstup pomocí funkce pinMode. Funkcí digitaRead si přečteme logickou hodnotu na pinu.

Protože je stisknutí tlačítka detekováno jako logická nula, musíme logickou hodnotu negovat, aby LED dioda svítila při stisknutém tlačítku. To bychom mohli udělat pomocí funkce if a else, ale na takové jednoduché úkoly je vhodné používat i podmíněný tříčlenný operátor (conditional ternary operator), který vyhodnotí logickou hodnotu prvního výrazu a podle výsledku dosadí druhý nebo třetí výraz. Zdrojový kód button_state ? LOW : HIGH znamená, použij LOW li button_state true a HIGH li button_state false.

const int led = 0;
const int button = 1;
int button_state = LOW;

void setup() {
  pinMode(led, OUTPUT);
  pinMode(button, INPUT);
}

void loop() {
  button_state = digitalRead(button);
  digitalWrite(led, button_state ? LOW : HIGH);
}

Interní pull-up rezistor

Zmínil jsem, že můžeme použít i interní rezistor a ušetřit si tak jeden externí rezistor. Program je skoro identický, pouze do funkce pinMode použijeme jako druhý parametr INPUT_PULLUP. Zapojení je podle prvního obrázku.

const int led = 0;
const int button = 1;
int button_state = LOW;

void setup() {
  pinMode(led, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop() {
  button_state = digitalRead(button);
  digitalWrite(led, button_state ? LOW : HIGH);
}

Zapnutí a vypnutí jedním tlačítkem

Druhým příkladem, kterému se budeme věnovat je stavový automat, který bude mít dva stavy. První stav představuje vypnutou LED diodu. Druhý stav představuje zapnutou LED diodu.

Asi vás hned napadne možné řešení problému. Budete sledovat změnu stavu na pinu a podle toho přepnete stav LED diody. Má to ale drobný problém. Kontakty v tlačítku nefungují dokonale a každé sepnutí kontaktů je doprovázeno drobnými zákmity. Během několika milisekund se kontakty vícekrát sepnou a rozepnou, dokud se stabilizují v sepnutém stavu. Výsledkem bude přepínání stavu LED diody, které někdy zareaguje správně a jindy ne. Závisí to na tom, jak rychle dokáže váš program zaznamenat změnu stavu. A mikrokontrolér ATtiny85 je i na frekvenci 1 MHz schopen velmi rychle sledovat změny a vícekrát přepnout stav LED diody během jednoho stisku. Příklad takového nespolehlivého programu je v následujícím kódu.

const int led = 0;
const int button = 1;
int button_state = LOW;
int led_state = LOW;

void setup() {
  pinMode(led, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop() {
  button_state = digitalRead(button);
  if(button_state == LOW)
    led_state = !led_state;
  digitalWrite(led, led_state);
}

K odstranění tohoto problému se využívá následující kód. Po zjištění změny stavu se čeká několik milisekund a pokud změna stavu je stále stejná, je to považováno za stisknutí tlačítka.

const int led = 0;
const int button = 1;
int led_state = LOW;

// Button states and debounce
int buttonState = 0;
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;

void setup() {
  pinMode(led, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop() {
  int reading = digitalRead(button);
  if (reading != lastButtonState)
    lastDebounceTime = millis();

  if ((millis() - lastDebounceTime) > 50) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == LOW) {
        led_state = !led_state;
      }
    }
  }

  lastButtonState = reading;

  digitalWrite(led, led_state);
}

Pokud budete mít pouze jedno tlačítko, předchozí kód bude fungovat dobře. Pokud budete používat více tlačítek, je vhodné kód ke zpracování zákmitú přesunout do samostatné třídy a využívat jej v podobě objektu. Takový kód si nemusíte psát sami a je vhodné, pokud sáhnete po existující knihovně. Například knihovna Bounce2 vám poskytne dostatek funkcí pro vyřešení nejrůznějších situací. Předchozí příklad bude pomocí této knihovny vypadat takto.

#include <Bounce2.h>

const int led = 0;
const int button = 1;
int led_state = LOW;

Bounce debouncer;

void setup() {
  pinMode(led, OUTPUT);
  pinMode(button, INPUT_PULLUP);
  debouncer.attach(button);
  debouncer.interval(5);
}

void loop() {
  debouncer.update();
  if (debouncer.fell())
    led_state = !led_state;

  digitalWrite(led, led_state);
}

Tlačítka a ATtiny85

V několika příkladech jsme si ukázali, jak se ovládají tlačítka pomocí mikrokontroléru ATtiny85. Příklady jsou napsány univerzální, proto by měly bez problémů fungovat i pro Arduino.

Zdrojový kód

Zdrojový kód se nachází na serveru GitHub.


26.02.2018


Menu