IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

Zapisovátko morzeovky s Arduino

V minulej lekcii, Arduino a analógový pin , sme si povedali niečo o analógovom pinu a ako ho možno využiť na meranie elektrického odporu a napätia.

Zapisovátko morzeovky, ktoré som na Arduino vytvoril, využíva tri tlačidlá (čiarka, bodka a oddeľovač) a vypisuje text na dvojriadkový display.

Na prvom riadku je zapisované text, na druhom buffer tónov, teda aktuálne naťukané čiarky a bodky. Tlačidlom oddeľovača sa buffer ukončí a napíše sa zodpovedajúce písmeno. Ak je stlačený oddeľovač 2x po sebe, do textu sa zapíše medzera. Okrem čísel a písmen anglickej abecedy sú definované špeciálne znaky pre zmazanie písmená (6x bodka) a slová (6x čiarka).

Morseova abeceda je určená pre prenos informácií s pomocou niekoľkých symbolov. Mohlo by sa zdať, že symboly sú dva - bodka a čiarka. Avšak informáciu prenáša ešte rôzne dlhá medzera, najkratšia pre oddelenie písmen, dlhšie pre slová a najdlhšiu pre vety. Symbolov tak máme päť a všetky je možné vytvoriť pomocou jedného tlačidla. Ja som pre zjednodušenie použil tri. Ako wikipédie hovorí, morzeovky môžeme prenášať rýchlosťou 60 - 250 znakov za minútu, rýchlosť reči je približne päťnásobná.

Hardvér nie je nijako zložitý, postačí Arduino (testované na UNO R3), LCD display (ja som použil celkom bežný, dvojriadkový display s radičom hd44780 a I2C zbernicou), 3 tlačidlá, k nim 3 odpory a pár drôtov.

Sketch, ktorý to celé riadi, je na 170 riadkov a to vrátane definície 36 znakové abecedy. Kód popíšem po jednotlivých logických blokoch, celistvý sketch je k stiahnutiu nižšie.

Najprv je potrebné spísať pár počiatočných riadkov:

Importovať nevyhnutné knižnice.

#include <Wire.h> // pro práci s I2C
#include <LiquidCrystal_I2C.h> // pro práci s displayem

Definovať PINy, s ktorými pracujú tlačidlá, definovať veľkosť displaya a tento display nastaviť.

#define CARKABUTTONPIN 12
#define TECKABUTTONPIN 8
#define ODDELBUTTONPIN 10
#define DISPLAY_NUMOFCOLUMNS 16 //Pracuji s displayem 16x2
LiquidCrystal_I2C lcd(0x27, DISPLAY_NUMOFCOLUMNS, 2);

Vytvoriť premenné pre ukladanie aktuálneho a predchádzajúceho stavu tlačidiel, tak aby sa zabezpečilo, že sa tón pri stlačení tlačidla zapíše len raz.

int carkaButtonState = 0;
int carkaButtonLastState = 0;
int teckaButtonState = 0;
int teckaButtonLastState = 0;
int oddelButtonState = 0;
int oddelButtonLastState = 0;

Vytvoriť premenné pre ukladanie aktuálne sekvencie tónov a aktuálneho textu. Tónom mám na mysli čiarku, bodku, alebo oddeľovač. Symbol je v tomto programe číslo alebo písmeno. Zo symbolov sa skladá zobrazovaný text.

String tonesBuffer;
String text;

A posledná inicializovaná premenná je samotná abeceda symbolov, ktorú som uložil do dvojrozmerného poľa.

String symbolsAlphabet[][2] =
{
    { ".-","A" },
    { "-...","B" },
    { "-.-.","C" },
    { "-..","D" },
    { ".","E" },
    { "..-.","F" },
    { "--.","G" },
    { "....","H" },
    { "..","I" },
    { ".---","J" },
    { "-.-","K" },
    { ".-..","L" },
    { "--","M" },
    { "-.","N" },
    { "---","O" },
    { ".--.","P" },
    { "--.-","Q" },
    { ".-.","R" },
    { "...","S" },
    { "-","T" },
    { "..-","U" },
    { "...-","V" },
    { ".--","W" },
    { "-..-","X" },
    { "-.--","Y" },
    { "--..","Z" },
    { ".----","1" },
    { "..---","2" },
    { "...--","3" },
    { "....-","4" },
    { ".....","5" },
    { "-....","6" },
    { "--...","7" },
    { "---..","8" },
    { "----.","9" },
    { "-----","0"}
};

Vo funkcii setup (), ktorá sa spúšťa pri štarte, sa inicializuje display, zapne sa podsvietenie, zobrazí sa nápis a jednoduchá nápoveda. Tiež tu musíme nastaviť pinMode na INPUT pre digitálnu komunikáciu s tlačidlami.

void setup() {
    lcd.init();
    lcd.backlight();
    lcd.print("Morseovkovnitko");
    lcd.setCursor(0, 1);
    lcd.print("6x.Smaze1 6x-Vse");

    pinMode(CARKABUTTONPIN, INPUT);
    pinMode(TECKABUTTONPIN, INPUT);
    pinMode(ODDELBUTTONPIN, INPUT);
}

Nekonečná slučka, teda funkcie loop (), začína čítaním stavov tlačidiel a volaním funkcie getToneFromBut­tonStates ().

void loop() {
    //načtení stavů tlačítek
    carkaButtonState = digitalRead(CARKABUTTONPIN);
    teckaButtonState = digitalRead(TECKABUTTONPIN);
    oddelButtonState = digitalRead(ODDELBUTTONPIN);
    char tone = getToneFromButtonStates(); //zjistí jestli a jaké tlačítko je stisklé

Funkcia getToneFromBut­tonStates () z rôzneho stavu tlačidiel vyčíta ktoré (a ak nejaké) bolo stlačené a vráti daný tón. Za stlačení sa v skutočnosti považuje uvoľnení tlačidla, teda chvíľa, kedy tlačidlo v predchádzajúcom okamihu bolo stlačené a teraz nie je. Ak takýto okamih nenastane, vráti sa prázdny char.

char getToneFromButtonStates()
{
    //vrátí v případě uvolnění tlačítka
    //tedy když nynější stav je 0, předchozí 1

    if (!carkaButtonState&& carkaButtonLastState)
        return '-';
    if (!teckaButtonState && teckaButtonLastState)
        return '.';
    if (!oddelButtonState && oddelButtonLastState)
        return ' ';

    return (char)0;
}

Vo funkcii loop () nasleduje kontrola tónu, ak je prázdny (užívateľ nestlačil tlačidlo), nič sa nedeje, len sa na konci prepíše predchádzajúci stav stlačení tlačidiel tým aktuálnym. Ak tón nie je prázdny, prichádza ďalšia kontrola, program sa vetví na časť "stlačený oddeľovač" a "stlačený iný tón (bodka alebo čiarka)". Obsahy týchto blokov sú popísané v ďalších častiach.

if (tone != (char)0) {
    if (tone == ' ')//ukončuji sekvenci tónů, hledám symbol
    {
    //Zdejší kód je níže
    }
    else//čárka nebo tečka
    {
    //Zdejší kód je ještě nížeji
    }

    //psaní na display se provádí pouze v případě, že bylo zmačknuté nějaké tlačítko
    lcd.clear();//vyčistí se display
    lcd.print(text);//napíše se text
    lcd.setCursor(0, 1);
    lcd.print(tonesBuffer);//napíše se sled tónů
}

//aktualizuje se předchozí stav
carkaButtonLastState = carkaButtonState;
teckaButtonLastState = teckaButtonState;
oddelButtonLastState = oddelButtonState;

Ak je stlačeným symbolom medzera, znamená to, že ukončujem sekvenciu naťukaných tónov a chcem z nich vytvoriť symbol, na konci bloku sa vymaže tonesBuffer.

if (tone == ' ') { //ukončuji sekvenci tónů, hledám symbol
    char symbol = getSymbolFromBuffer();

    if (symbol != (char)0) { //Sled tónů nalezl nějaký symbol, zapíše se do textu
        text += symbol;
        if (text.length() > DISPLAY_NUMOFCOLUMNS) { //Pokud přesáhne počet znaků velikost displaye,
            // napíše se nový znak na první místo. Ostatní se vymažou.
            text = (String)symbol;
        }
    } else { //Sled tónů nedává žádný symbol, ale možná nějakou akci (například vymazání      znaku)
        extractActionFromTonesBuffer();
    }
    tonesBuffer = ""; //vymaže se buffer (čárky a tečky)
}

Funkcia getSymbolFromBuffer () vracia jedu z troch možností. Pokiaľ užívateľ stlačí raz tlačidlo oddeľovača, iba sa ukončí buffer. Ak je buffer ukončený (prázdny) a je stlačený oddeľovač, funkcia getSymbolFromBuffer () vráti medzeru, pokiaľ buffer prázdny nie je, prehľadá sa abeceda a vráti sa nájdený symbol. V prípade nenájdenia symbolu sa vráti prázdny char.

char getSymbolFromBuffer()
{
    if (tonesBuffer == "")
        return ' '; //udělá mezeru, pokud předtím nejsou žádné znaky

    for (int i = 0; i < sizeof symbolsAlphabet / sizeof symbolsAlphabet[0]; i++)
        //Projdu všechny symboly a porovnávám buffer s abecedou
        if (tonesBuffer == symbolsAlphabet[i][0])
            return symbolsAlphabet[i][1][0];//pokud se rovna vrátím daný symbol

    //Buffer neodpovídá žádnému symbolu, pošlu tedy nic
    return (char)0;
}

Vrátenie prázdneho charu zapríčiní volanie funkcie extractAction­FromTonesBuffer (). Táto funkcia znovu porovnáva buffer a pýta sa, Či jeho obsah nezodpovedá nejakej akcii, ktorú už je v tomto prípade mazania symbolu, či celého textu.

void extractActionFromTonesBuffer()
{
    if (tonesBuffer == "......") //6x tečka
        text.remove(text.length() - 1, 1); //umaže jedno písmeno
    if (tonesBuffer == "------") //6x čárka
        text = "";//smaže celý text
}

Vyššie popísané bloky kódu sa vykonávajú, ak používateľ stlačil oddeľovač, ak používateľ stlačil iné tlačidlo (bodku alebo čiarku), tak sa tón pripíše k bufferu a vykoná sa overenie, či veľkosť buffera nepresahuje veľkosť display. V tom prípade sa buffer iba prepíše na stlačený tón.

else { //čárka nebo tečka
    tonesBuffer += tone;
    if (tonesBuffer.length() > DISPLAY_NUMOFCOLUMNS) { //pokud je tónů více než velikost displaye, vymaže se buffer
        tonesBuffer = (String)tone;
    }
}

Toť všetko!

Kompletné spustiteľný sketch je v priloženom súbore.

V budúcej lekcii, Tvorba vlastnej Arduino knižnice - Dokončenie , si vytvoríme našu plnohodnotnú Arduino knižnicu.


 

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 109x (4.19 kB)
Aplikácia je vrátane zdrojových kódov

 

Predchádzajúci článok
Arduino a analógový pin
Všetky články v sekcii
Arduino
Preskočiť článok
(neodporúčame)
Tvorba vlastnej Arduino knižnice - Dokončenie
Článok pre vás napísal tesař.tech
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje dýchání přibližně celý život
Aktivity