Arduino Locker I.
inštalácia externých knižníc, LCD displej, maticová klávesnica, zbernica I2C, stavový stroj
Video pre cvičenie
About
Počas tohto cvičenia vytvoríme jednoduchý elektronický zámok. Pomocou tlačidiel bude možné zadať kód, ktorý sa zobrazí na LCD displeji. Ak bude zadaný správny kód, zámok sa „odomkne“, inak zostane zamknutý. Stav zámku (odomknutý/zamknutý) budeme signalizovať pomocou LED diódy.
Počas cvičenia si ukážeme, ako pracovať s LCD displejom, ako nainštalovať rozširujúce knižnice, ako spracovať vstupy od používateľa a ako pomocou stavového stroja riadiť správanie celého zariadenia.
Objectives
Porozumieť základom práce zbernice I2C.
Naučiť sa pracovať s LCD displejom pomocou knižnice I2C_LCD
Naučiť sa pracovať s maticovou klávesnicou pomocou knižnice SimpleKeypad
Hardware Required
- prototypovacia doska Arduino UNO
- LCD displej s I2C kontrolérom
- maticová klávesnica
- 1x RGB LED dióda
Content
Introduction to I2C
Zbernica I²C (Inter-Integrated Circuit) poskytuje jednoduchý spôsob komunikácie medzi viacerými zariadeniami pomocou iba dvoch vodičov. Umožňuje napríklad pripojiť displej, senzory alebo iné moduly k mikrokontroléru bez potreby veľkého množstva pinov.
Komunikácia prebieha v režime master–slave:
- master (v našom prípade Arduino) riadi komunikáciu a posiela požiadavky
- slave (v našom prípade LCD displej) na tieto požiadavky reaguje
Zbernica používa dva signály:
- SDA (Serial Data) – slúži na prenos dát
- SCL (Serial Clock) – slúži ako hodinový signál, ktorý určuje tempo komunikácie
Ilustrácia toho, ako zbernica pracuje, sa nachádza na nasledujúcom obrázku:
V tomto kroku I2C zbernicu inicializujeme a zistíme adresu pripojeného LCD displeja.
Úloha
K doske Arduino UNO pripojte LCD displej s I2C kontrolérom.
I2C piny sú vyvedené na analógových pinoch A5 (pin SCL) a A4 (pin SDA), respektíve na digitálnych pinoch D19 (pin SCL) a D18 (pin SDA).
Pripojiť LCD displej k doske Arduino UNO môžete napr. takto:
Úloha
Inicializujte I2C zbernicu pomocou knižnice
Wire.h.
Aby bolo možné so zbernicou I2C pracovať, je potrebné ju
inicializovať. Na to slúži volanie Wire.begin() z knižnice
Wire.h. Zbernicu I2C teda inicializujeme čo
najskôr po štarte - po volaní funkcie init().
#include <Arduino.h>
#include <Wire.h>
int main(){
init(); // inicializácia hw mikrokontroléra pre Arduino SDK
Wire.begin(); // inicializácia zbernice i2c
}Poznámka
Niektoré knižnice inicializáciu I2C zbernice vykonávajú samé. Na to sa však netreba spoliehať a je vždy istejšie túto inicializáciu zabezpečiť explicitne.
Úloha
Identifikujte adresu LCD displeja na I2C zbernici.
Identifikáciu spravíme pomocou nasledujúceho fragmentu kódu, ktorý funguje ako tzv. I2C Scanner. Arduino UNO používa na adresovanie I2C zariadení 7 bitov. To znamená, že na zbernici môže byť maximálne 128 zariadení s rôznymi adresami. V praxi je to však omnoho menej - zhruba 112 použiteľných adries.
I2C Scanner sa pokúsi komunikovať s každým zariadením na I2C zbernici.
Vytvorte aj súbor config.h, v ktorom sa budú nachádzať
makrá, napr. pre rýchlosť prenosu na sériovej linke (makro
BAUD_RATE).
#include <Arduino.h>
#include <Wire.h>
#include "config.h"
int main(){
init();
// i2c initialization
Wire.begin();
// serial initialization
Serial.begin(BAUD_RATE);
while (!Serial);
Serial.println("I2C Scanner");
Serial.println("Scanning...");
uint8_t found = 0;
for (uint8_t addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
uint8_t error = Wire.endTransmission();
if (error == 0) {
Serial.print("Device found at 0x");
if (addr < 16) Serial.print("0");
Serial.println(addr, HEX);
found++;
}
}
if (found == 0)
Serial.println("No I2C devices found.");
else
Serial.print(found), Serial.println(" device(s) found.");
delay(1000);
}Program sa vykoná raz a potom skončí. Jeho výstup v prípade, ak je pripojený len LCD displej, môže vyzerať napríklad takto:
I2C Scanner
Scanning...
Device found at 0x27
1 device(s) found.
Z výstupu vyplýva, že adresa LCD displeja je 0x27 alebo
v desiatkovej sústave 39. Do súboru config.h
pridáme makro LCD_I2C_ADDRESS s adresou:
#define LCD_I2C_ADDRESS 0x27Okrem toho vytvoríme ešte dve makrá opisujúce vlastnosti LCD displeja:
LCD_ROWS- počet riadkov displeja, aLCD_COLS- počet stĺpcov displeja.
Súbor config.h teda ubsahovať o displeji tieto
makrá:
#define LCD_I2C_ADDRESS 0x27
#define LCD_ROWS 2
#define LCD_COLS 16Liquid Crystal Display
Dôležitý komponent bude LCD displej. Nainštalujeme ho.
Úloha
Nainštalujte knižnicu I2C_LCD pre podporu LCD displeja.
[env:uno]
lib_deps = robtillaart/I2C_LCD@^0.2.6Poznámka
Samozrejme existujú aj iné knižnice, pomocou ktorých viete ovládať LCD displeje. Tá najznámejšia je zrejme LiquidCrystal I2C. Problémom však je, že táto knižnica sa na rozdiel od knižnice I2C_LCD už ďalej nevyvíja.
Úloha
Vypíšte na displej na prvom riadku a nultom stĺpci text
"Hello, world!".
Jednoduchý výpis textu na displej môže vyzerať takto:
int main(){
// setup/init
init();
Wire.begin();
// init lcd display
I2C_LCD lcd(LCD_I2C_ADDRESS);
lcd.begin(LCD_COLS, LCD_ROWS);
// print
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Hello world!");
}Poznámka
Mnohé knižnice obyčajne obsahujú aj priečinok s príkladmi použitia. Príklady, ako používať knižnicu I2C_LCD nájdete tu.
Matrix Keypad
Maticová klávesnica je jednoduché vstupné zariadenie, ktoré sa často používa v mikrokontrolérových projektoch na zadávanie údajov používateľom. Tlačidlá nie sú zapojené samostatne, ale sú usporiadané do riadkov a stĺpcov, čím sa výrazne znižuje počet potrebných pinov na ich pripojenie.
Pri stlačení tlačidla sa prepojí konkrétny riadok so stĺpcom, čo umožňuje mikrokontroléru zistiť, ktoré tlačidlo bolo stlačené. Tento spôsob zapojenia sa nazýva maticové skenovanie a patrí medzi bežné techniky používané napríklad v kalkulačkách, telefónoch alebo rôznych ovládacích paneloch.
V tomto kroku si ukážeme, ako takúto klávesnicu pripojiť k doske Arduino UNO a ako čítať stlačené tlačidlá v programe.
Úloha
Pripojte klávesnicu k doske Arduino UNO.
Rozloženie jednotlivých pinov klávesnice sa nachádza na nasledujúcom obrázku:
Mapovanie pinov z klávesnice a doskou Arduino UNO je opísané nasledujúcou tabuľkou:
| pin na klávesnici | pin na Arduino UNO | význam | tlačidlá |
|---|---|---|---|
R1 |
D2 | riadok | S4, S8, S12,
S16 |
R2 |
D3 | riadok | S3, S7, S11,
S15 |
R3 |
D4 | riadok | S2, S6, S10,
S14 |
R4 |
D5 | riadok | S1, S5, S9,
S13 |
C1 |
D6 | stĺpec | S4, S3, S2,
S1 |
C2 |
D7 | stĺpec | S8, S7, S6,
S5 |
C3 |
D8 | stĺpec | S12, S11, S10,
S9 |
C4 |
D9 | stĺpec | S16, S15, S14,
S13 |
Úloha
Do projektu pridajte knižnicu SimpleKeypad.
Knižnicu pridajte a nainštalujte podľa toho, aké IDE používate.
Po nainštalovaní knižnice sa v prostredí PlatformIO aktualizujú závislosti v
súbore platformio.ini:
[env:uno]
lib_deps =
robtillaart/I2C_LCD @ ^0.2.6
maximebohrer/SimpleKeypad@^2.0.0Úloha
Inicializujte klávesnicu.
Pre inicializáciu klávesnice je potrebné nastaviť nasledovné:
- rozloženie klávesnice - ktoré klávesy, resp. znaky, sa budú nachádzať na ktorých tlačítkach
- zoznam pinov, ku ktorým sú pripojené riadky
- zoznam pinov, ku ktorým sú pripojené stĺpce
V našom prípade môže inicializácia klávesnice vyzerať napríklad takto:
// rozloženie klávesnice
char kb_layout[KB_ROWS][KB_COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
// piny riadkov a stĺpcov
byte kb_row_pins[KB_ROWS] = {9, 8, 7, 6};
byte kb_col_pins[KB_COLS] = {5, 4, 3, 2};
// vytvorenie novej klávesnice
SimpleKeypad keypad((char*)kb_layout, kb_row_pins, kb_col_pins, KB_ROWS, KB_COLS);Úloha
Otestujte správnosť vášho riešenia.
Pre otestovanie môžete použiť nasledujúci fragment kódu, ktorý do sériovej linky vypíše stlačený kláves:
while(true){
char key = keypad.getKey();
if (key != 0) {
Serial.println(key);
}
}Locker as a State Machine
- stavovy stroj pre locker
- stavy budeme volat obrazovky, teda
screens - zoznam stavov:
INIT_SCR- na inicializaciu hwIDLE_SCR- bude cakat na stlacenie klavesyINPUT_SCR- pouzivatel zadava kodCHECK_SCR- overenie kodu a rozhodnutie, ci dobre alebo nieOPEN_SCR- otvorenieDENIED_SCR- odmietnutie pristupu
- vsetky stavy sa budu nachadzat v priecinku
screens - kazdy stav bude reprezentovany samostatnou funkciou, ktora sa bude
nachadzat v samostnom subore v priecinku
screens- funkcia reprezentujuca stav bude mat parameter typu referencie na kontext
- navratovou hodnotou bude novy stav
Úloha
V hlavičkovom súbore context.h vytvorte štruktúru
context, ktorá bude obsahovať referencie na LCD displej a
maticovú klávesnicu.
struct context {
I2C_LCD *lcd;
SimpleKeypad *keypad;
};Úloha
V hlavičkovom súbore screens.h vytvorte enumaračný typ
screen, ktorý bude obsahovať všetky stavy.
enum screen {
INIT_SCR,
IDLE_SCR,
INPUT_SCR,
CHECK_SCR,
OPEN_SCR,
DENIED_SCR
}Úloha
V priečinku src/screens/ vytvorte súbor
init.cpp, v ktorom sa bude nachádzať funkcia
init_screen().
Každý stav, resp. obrazovka, bude reprezentovaná samostatnou funkciou. O tejto funkcii bude platiť:
- bude sa nachádzať v samostatnom súbore v priečinku
src/screens/ - bude mať jeden parameter, ktorým bude referencia na kontext,
- bude vracať nový stav, a
- deklarácia funkcie sa bude nachádzať v hlavičckovom súbore
screens.h.
enum screen init_screen(struct context *ctx){
init();
// i2c init
Wire.begin();
// serial init
Serial.begin(BAUD_RATE);
while(!Serial);
Serial.println("> Init Screen");
// init lcd display
ctx->lcd = new I2C_LCD(LCD_I2C_ADDRESS);
ctx->lcd->begin(LCD_COLS, LCD_ROWS);
// rozloženie klávesnice
char kb_layout[KB_ROWS][KB_COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
// piny riadkov a stĺpcov
byte kb_row_pins[KB_ROWS] = {9, 8, 7, 6};
byte kb_col_pins[KB_COLS] = {5, 4, 3, 2};
// vytvorenie novej klávesnice
ctx->keypad = new SimpleKeypad(
(char*)kb_layout,
kb_row_pins, kb_col_pins,
KB_ROWS, KB_COLS
);
return IDLE_SCR;
}Úloha
V súbore src/screens/idle.cpp vytvorte funkciu
idle_screen(), ktorá bude reprezentovať správanie
zariadenia v stave IDLE_SCR.
Na tejto obrazovke len vypíšte text Press any key a
čakajte na stlačenie ľubovoľného klávesu. Po stlačení klávesy prejdite
do stavu INPUT_SCR.
enum screen idle_screen(struct context *ctx){
// on enter
Serial.println("> Idle Screen");
// main
ctx->lcd->clear();
ctx->lcd->setCursor(0, 1);
ctx->lcd->print("Press any key...");
while(true){
char key = ctx->keypad->getKey();
if (key != 0) {
break;
}
}
// on leave
return INPUT_SCR;
}Úloha
Vo funkcii main() vyriešte prepínanie obrazoviek.
int main(){
struct context context;
enum screen screen = INIT_SCR;
while(true){
switch(screen){
case INIT_SCR:
screen = init_screen(&context);
break;
case IDLE_SCR:
screen = idle_screen(&context);
break;
}
}
}Additional Tasks
- asdf
Additional Resources
Interface an I2C LCD with Arduino - Kompletný návod, ako pripojiť LCD displej k doske Arduino UNO cez I2C kontrolér.
I2C_LCD - Arduino library for I2C LCD displays e.g.
20x4SimpleKeypad - Arduino library for using matrix keypads.
Co je to I2C sběrnice? - V tomto článku se vám pokusím vysvětlit, co to I2C sběrnice je, a hlavně si ukážeme, proč ji u Arduina využíváme.