Arduino Locker II.
EPROM, perzistencia dát, práca s RGB LED diódou
Videá pre cvičenie
About
Objectives
Naučiť sa pracovať s RGB LED diódou.
Naučiť sa pracovať s perzistentnou pamäťou EEPROM pomocou knižnice
EEPROM.h
Helper Functions
Poznámka
Nakoľko je Arduino SDK napísané v jazyku C++,
budeme používať tzv. camel case pre tvorbu identifikátorov. To
znamená, že ak sa názov skladá z viacerých slov, každé ďalšie slovo
začne v identifikátore veľkým začiatočným písmenom, napr.:
thisIsAFunction(), getName() a pod.
Úloha
Do modulu helpers presuňte funkciu
waitForKey().
Túto funkciu použíjeme na viacerých miestach.
char waitForKey(SimpleKeypad *keypad){
while(true){
char key = keypad->getKey();
if(key != 0){
return key;
}
delay(50);
}
}Úloha
Vytvorte funkciu printAt(), ktorá vypíše na LCD displej
text na zadanú pozíciu.
Funkcia bude mať nasledujúce parametre:
lcd- referencia na LCD displejcol- číslo stĺpca na displejirow- číslo riadku na displejitext- referencia na reťazec, ktorý má byť vypísaný
Funkcia nič nevracia.
void printAt(I2C_LCD *lcd, int col, int row, char* text){
lcd->setCursor(col, row);
lcd->print(text);
}Status (RGB) LED
Najjednoduchší spôsob, ako poskytovať spätnú väzbu, je pomocou LED diódy. Keďže na zámok sa môžeme pozerať ako na zamknutý a odomknutý, budeme na tieto dva stavy reagovať dvoma farbami:
- ak bude zámok zamknutý, stavová LED dióda bude svietiť na červeno
- ak bude zámok odomknutý, stavová LED dióda bude svietiť na zeleno
Úloha
Červenú LED diódu pripojte na digitálny pin 15 a zelenú LED diódu pripojte na
digitálny pin 14 a
inicializujte ich v stave INIT_SCR.
Po pripojení nezabudnite aktualizovať aj konfiguračný súbor
config.h.
// config.h
#define RGB_RED_PIN 15
#define RGB_GREEN_PIN 14Oba digitálne piny budú inicializované vo funkcii
init_screen() pomocou funkcie pinMode():
// init status led
pinMode(RGB_GREEN_PIN, OUTPUT);
pinMode(RGB_RED_PIN, OUTPUT);Úloha
Aktualizujte kód tak, aby LED dióda vždy pri zamknutí alebo odomknutí zmenila farbu.
LED diódu rozsvietite alebo zhasnete pomocou funkcie digitalWrite().
Úloha
Overte správanie zariadenia.
Changing the Secret Pin
Zámok, ktorého kód sa nedá zmeniť, nie je veľmi bezpečný. V tomto
kroku teda rozšírime jeho funkcionalitu o možnosť zmeniť kód na nový.
Pre jednoduchosť vytvoríme samostatný stav s názvom
CHANGE_PIN_SCR, do ktorého sa používateľ dostane stlačením
tlačidla * po odomknutí zámku.
Úloha
V súbore change_pin.cpp vytvorte funkciu
change_pin_screen(), ktorá bude reprezentovať stav
CHANGE_PIN_SCR.
Na zmenu pinu vytvoríme funkciu change_pin_screen(),
ktorá bude čiastočnou úpravou funkcie input_screen(). Nový
načítaný kód sa uloží do premennej ctx->buffer a až po
prečítaní 4 znakov sa jej obsah uloží do premennej
ctx->secret.
enum screen change_pin_screen(struct context *ctx){
// on enter
ctx->lcd->clear();
printAt(ctx->lcd, 0, 0, "New PIN:");
printAt(ctx->lcd, 0, 1, "____");
// read new code
ctx->lcd->setCursor(0, 1);
for(int idx = 0; idx < PIN_LENGTH; idx++){
char key = wait_for_key(ctx->keypad);
ctx->buffer[idx] = key;
ctx->lcd->print("*");
}
// copy new pin from buffer to secret
Serial.println(ctx->secret);
for(int idx = 0; idx < PIN_LENGTH; idx++){
ctx->secret[i] = ctx->buffer[i];
}
// on exit
ctx->lcd->clear();
printAt(ctx->lcd, 0, 0, "Pin has changed");
delay(5 * 1000);
return IDLE_SCR;
}Úloha
Zabezpečte, aby bolo možné do tohto stavu prejsť stlačením tlačidla
* po odomknutí zámku.
Na tento účel upravíme funkciu open_screen():
ctx->lcd->clear();
printAt(ctx->lcd, 0, 0, "You Shall Pass");
printAt(ctx->lcd, 0, 1, "Press * to Change Pin");
// loop / job
int timeout = 5 * 1000;
while(timeout > 0){
char key = ctx->keypad->getKey();
if(key != 0){
Serial.println(key);
if(key == '*')
return CHANGE_PIN_SCR;
}
delay(50);
timeout -= 50;
}Úloha
Overte správnosť svojej implementácie.
Ak ste postupovali správne, tak po odomknutí zámku bude možné stlačiť
tlačidlo *, po stlačení ktorého bude možné zmeniť číselnú
kombináciu zámku pre jej odomknutie. Po úspešnej zmene bude možné zámok
odomknúť zadaním novej kombinácie.
Persistence with EEPROM
Vytvorený elektronický zámok má aktuálne jeden vážny problém. Tým je, že číselná kombinácia na odomknutie zámku sa vynuluje pri reštartovaní dosky. To je dané tým, že kód udržavame v dočasnej pamäti SRAM, ktorá sa zmaže pri resetovaní alebo odpojení dosky od napájania.
Doska Arduino UNO používa Harvardskú architektúru, ktorá sa vyznačuje najmä tým, že pamäť programu je oddelená od pamäte dát. Organizácia pamäte tejto dosky je zobrazená na nasledujúcom obrázku.
Ak teda chceme zabezpečiť, aby zmena číselnej kombinácia prežila
reštart dosky, musíme ju uložiť mimo pamäte SRAM. A presne na
temto účel slúži pamäť EEPROM. Na doske Arduino UNO má
veľkosť 1kB. Limitom je však počet zápisov na jedno
pamäťové miesto - tento limit je zhruba ~100000 zápisov. Na
čítanie sa žiadne obmedzenie nevzťahuje.
Na prácu s pamäťou EEPROM je možné použiť knižnicu EEPROM.h,
ktorá je súčasťou Arduino SDK. V tomto kroku pomocou tejto
knižnice zabezpečíme, aby bola číselná kombinácia na odomknutie zámku
uložená v pamäti EEPROM, čím sa tento údaj stane trvácnym.
Úloha
Upravte funkciu change_pin_screen() tak, aby nový
číselný kód uložila do pamäte EEPROM od adresy
0.
Do konfiguračného súboru config.h uložíme adresu, na
ktorej bude uložený číselný kód zámku. Táto adresa sa bude nachádať v
makre PIN_ADDR:
// config.h
#define PIN_ADDR 0Následne môžeme upraviť implementáciu funkcie, kde po úspešnom načítaní nového číselného kódu tento uložíme do pamäte EEPROM:
// change_pin.cpp
for(int i = 0; i < PIN_LENGTH; i++){
EEPROM.update(PIN_ADDR + i, ctx->buffer[i]);
}Úloha
Upravte funkciu check_screen() tak, aby skontrolovala
zadanú číselnú kombináciu od používateľa s tou, ktorá je uložená v
pamätei EEPROM.
// check.cpp
for(int i = 0; i < PIN_LENGTH; i++){
if(ctx->buffer[i] != EEPROM.read(PIN_ADDR + i)){
return DENIED_SCR;
}
}Úloha
Overte správnosť vašej implementácie.
Aktuálne je možné spraviť aj refaktoring a teda odstrániť napríklad
položku .secret zo štruktúry context, ktorá už
nie je potrebná.
Additional Tasks
Pridajte k zariadeniu aj bzučiak a vymyslite, ako bude pípať vzhľadom na to, či bol kód zadaný správne alebo nie. Napr. tiež môže poskytovať akustickú späťnú väzbu pri stlačení klávesy.
Vytvorte samostatný stav
LOCKOUT_SCR, ktorý zamkne zariadenie po troch neúspešných pokusoch.Zabezpečte exponential backoff pri neúspešnom zadaní kódu. To znamená, že čakanie na opätovné zadanie kódu sa bude po každom neúspešnom pokuse postupne predlžovať.
Zabezpečte, aby pri zmene číselnej kombinácie bolo možné zadať len číslice. Akýkoľvek iný znak nech je ignorovaný.
Additional Resources
Arduino Memory Guide - Learn about the built-in memory blocks of Arduino boards in this article.