Paralelní procesy Arduino. Arduino: Paralelní a sériové připojení slave zařízení ke sběrnici SPI. Ovládání LED a piezo bzučáku pomocí operátoru Delay().

Obecně řečeno, Arduino nepodporuje skutečnou paralelizaci úloh nebo multithreading. Ale je to možné s každým opakováním cyklu smyčka() dejte mikrokontroléru, aby zkontroloval, zda je čas na provedení nějaké další úlohy na pozadí. V tomto případě se uživateli bude zdát, že se současně provádí několik úkolů.

Blikejme například LED na dané frekvenci a současně vydávajme stoupající a klesající zvuky jako siréna z piezozářiče. Jak LED, tak piezo emitor jsme k Arduinu připojili více než jednou. Sestavíme obvod, jak je znázorněno na obrázku.

Pokud připojíte LED na jiný digitální pin než "13", nezapomeňte na 220 ohmový proudový omezovací odpor.

2 Ovládání LED a piezo bzučáku pomocí operátoru delay().

Pojďme napsat tento náčrt a nahrát jej do Arduina.

Const int soundPin = 3; /* deklaruje proměnnou s číslem pinu, ke kterému je piezoelektrický prvek připojen */ const int ledPin = 13; // deklaruje proměnnou s číslem pinu LED void setup()( pinMode(soundPin, OUTPUT); // deklarovat pin 3 jako výstup. pinMode(ledPin, OUTPUT); // deklarovat pin 13 jako výstup. } void loop() (// Ovládání zvuku: tone(soundPin, 700); // vydá zvuk o frekvenci 700 Hz delay(200); tón (soundPin, 500); // při 500 Hz zpoždění(200); tón (soundPin, 300); // při 300 Hz zpoždění(200); tón (soundPin, 200); // při 200 Hz zpoždění(200); // LED ovládání: digitalWrite(ledPin, HIGH); // zpoždění požáru(200); digitalWrite(ledPin, LOW); // zhasnutí zpoždění(200); }

Po zapnutí je vidět, že náčrt není proveden přesně tak, jak bychom potřebovali: dokud nebude siréna plně zpracovaná, LED nebude blikat a my bychom chtěli, aby LED blikala během zvuk sirény. co je tady za problém?

Faktem je, že tento problém nelze vyřešit běžným způsobem. Úkoly jsou prováděny mikrokontrolérem přísně sekvenčně. Operátor zpoždění() zpozdí provádění programu o zadanou dobu a dokud tato doba neuplyne, následující příkazy programu nebudou provedeny. Z tohoto důvodu nemůžeme pro každý úkol ve smyčce nastavit jinou dobu provádění. smyčka() programy. Proto je potřeba nějak simulovat multitasking.

3 Paralelní procesy bez operátoru "delay()".

Možnost, ve které bude Arduino plnit úkoly pseudoparalelně, navrhují vývojáři Arduina. Podstatou metody je, že s každým opakováním cyklu smyčka() zkontrolujeme, zda je čas zablikat LED (provést úlohu na pozadí) nebo ne. A pokud ano, pak převrátíme stav LED. Jedná se o druh operátora bypassu zpoždění().

Const int soundPin = 3; // proměnná s číslem pinu piezoelektrického prvku const int ledPin = 13; // proměnná s LED číslem pinu const long ledInterval = 200; // Interval blikání LED, ms. int ledState = NÍZKÁ; // počáteční stav LED bez znaménka long previousMillis = 0; // uložení času předchozího záblesku LED void setup()( pinMode(soundPin, OUTPUT); // nastavení pinu 3 jako výstupu. pinMode(ledPin, OUTPUT); // nastavení pinu 13 jako výstupu. } void loop() (// Ovládání zvuku: tone(soundPin, 700); zpoždění(200); tón (soundPin, 500); zpoždění(200); tón (soundPin, 300); zpoždění(200); tón (soundPin, 200); zpoždění(200); // Blikající LED: // čas od zapnutí Arduina, ms: unsigned long currentMillis = millis(); // Pokud je čas blikat, if (currentMillis - previousMillis >= ledInterval) ( previousMillis = currentMillis; // pak uložte aktuální čas if (ledState == LOW) ( // a invertujte stav LED ledState = HIGH; ) else ( ledState = LOW; ) digitalWrite(ledPin, ledState); // přepnutí stavu LED ) }

Významnou nevýhodou této metody je, že část kódu před řídicím blokem LED musí být provedena rychleji než časový interval blikání LED „ledInterval“. V opačném případě bude blikat méně často, než je nutné, a nedosáhneme efektu paralelního provádění úloh. Konkrétně v našem náčrtu je doba trvání změny zvuku sirény 200+200+200+200 = 800 ms a interval blikání LED jsme nastavili na 200 ms. Ale LED bude blikat s periodou 800 ms, což je 4krát víc, než jsme nastavili.

Obecně platí, že pokud kód používá operátor zpoždění(), v tomto případě je obtížné simulovat pseudoparalelismus, proto je žádoucí se mu vyhnout.

V tomto případě by bylo nutné, aby řídicí jednotka zvuku sirény také zkontrolovala, zda nadešel čas, a nepoužila zpoždění(). To by ale zvýšilo množství kódu a zhoršilo čitelnost programu.

4 Použití knihovny ArduinoThread k vytvoření paralelních vláken

K vyřešení problému použijeme nádhernou knihovnu Arduino vlákno, který umožňuje snadno vytvářet pseudoparalelní procesy. Funguje to podobným způsobem, ale umožňuje vám nepsat kód pro kontrolu času - musíte úkol v tomto cyklu dokončit nebo ne. To snižuje množství kódu a zlepšuje čitelnost náčrtu. Pojďme se podívat na knihovnu v akci.


Nejprve si stáhněte archiv knihovny z oficiálních stránek a rozbalte jej do adresáře knihovny/ Vývojové prostředí Arduino IDE. Poté složku přejmenujte Arduino Thread-master v Arduino vlákno.

Schéma zapojení zůstane stejné. Změní se pouze kód programu.

#zahrnout // připojení knihovny ArduinoThread const int soundPin = 3; // proměnná s číslem pinu piezoelektrického prvku const int ledPin = 13; // proměnná s číslem pinu LED Thread ledThread = Thread(); // vytvoření vlákna pro ovládání LED Thread soundThread = Thread(); // vytvořit řídicí tok pro sirénu void setup()( pinMode(soundPin, OUTPUT); // deklarovat pin 3 jako výstup. pinMode(ledPin, OUTPUT); // deklarovat pin 13 jako výstup. ledThread.onRun(ledBlink); // přiřazení úkolu vláknu ledThread.setInterval(1000); // nastavení intervalu odezvy, ms soundThread.onRun(sound); // přiřazení úkolu vláknu soundThread setInterval(20); // nastavení intervalu odezvy, ms } void loop() (// Zkontrolujte, zda je čas přepnout LED: if (ledThread.shouldRun()) ledThread.run(); // spusťte vlákno // Zkontrolujte, zda je čas změnit tón sirény: if (soundThread.shouldRun()) soundThread.run(); // spuštění vlákna } // tok LED: void ledBlink() ( static bool ledStatus = false; // Stav LED Zapnuto/Vypnuto ledStatus = !ledStatus; // invertuje stav digitalWrite(ledPin, ledStatus); // zapnutí/vypnutí LED } // Stream sirény: void sound() ( statický int tón = 100; // tón zvuku, tón Hz(soundPin, tón); // zapněte sirénu na "ton" Hz if (ton )

V programu vytvoříme dvě vlákna - ledThread a soundThread, každý provádí svou vlastní operaci: jeden bliká LED, druhý ovládá zvuk sirény. V každé iteraci smyčky pro každé vlákno kontrolujeme, zda nastal čas pro jeho provedení či nikoliv. Pokud dorazí, spustí se k provedení pomocí metody běh(). Hlavní je nepoužívat operátora zpoždění(). Podrobnější vysvětlení jsou uvedena v kódu.


Načtěte kód do paměti Arduina a spusťte jej. Nyní vše funguje přesně tak, jak má!

A uvedeme příklad použití funkce Arduino připojitInterrupt().

Přerušení je signál, který informuje procesor o výskytu nějaké události, která vyžaduje okamžitou pozornost. Procesor musí na tento signál reagovat přerušením provádění aktuálních instrukcí a předáním řízení obsluze přerušení (ISR, Interrupt Service Routine). Obslužná rutina je běžná funkce, kterou si sami napíšeme a vložíme do ní kód, který má na událost reagovat.

Po obsluze přerušení ISR funkce ukončí svou práci a procesor se vesele vrátí k přerušeným činnostem - pokračuje ve vykonávání kódu z místa, kde se zastavil. To vše se děje automaticky, takže naším úkolem je pouze napsat obsluhu přerušení, aniž bychom cokoli porušili a aniž bychom nutili procesor, aby nás příliš často rozptyloval. Budete potřebovat pochopení obvodu, principů fungování připojených zařízení a představu o tom, jak často lze volat přerušení, jaké jsou vlastnosti jeho výskytu. To vše je hlavní potíž při práci s přerušeními.

Hardwarová a softwarová přerušení

Přerušení v Arduinu lze rozdělit do několika typů:

  • Hardwarové přerušení. Přerušení na úrovni architektury mikroprocesoru. K samotné události může dojít v produktivním okamžiku z externího zařízení – například stisknutí tlačítka na klávesnici, pohyb počítačové myši atd.
  • Softwarová přerušení. Spouštějí se uvnitř programu pomocí speciální instrukce. Používá se k volání obsluhy přerušení.
  • Interní (synchronní) přerušení. K vnitřnímu přerušení dochází v důsledku změny nebo narušení provádění programu (například při přístupu na neplatnou adresu, neplatný operační kód a další).

Proč potřebujeme hardwarová přerušení

Hardwarová přerušení nastávají v reakci na externí událost a pocházejí z externího hardwarového zařízení. V Arduinu existují 4 typy hardwarových přerušení. Všechny se liší signálem na kolíku přerušení:

  • Kontakt je přitažen k zemi. Obsluha přerušení se provádí tak dlouho, dokud je pin přerušení LOW.
  • Změna signálu na kontaktu. V tomto případě Arduino spustí obsluhu přerušení, když dojde ke změně signálu na pinu přerušení.
  • Změna signálu z LOW na HIGH na pinu - při změně z nízkého na vysoký se provede obsluha přerušení.
  • Změna signálu z HIGH na LOW na pinu - když se signál změní z vysokého na nízký, bude provedena obsluha přerušení.

Přerušení jsou užitečná v programech Arduino, protože pomáhají řešit problémy s časováním. Například při práci s UART vám přerušení umožňují nesledovat příchod každé postavy. Externí hardwarové zařízení vydá signál přerušení, procesor okamžitě zavolá obsluhu přerušení, která znak včas zachytí. To šetří čas CPU, který by bez přerušení strávil kontrolou stavu UART, místo toho všechny potřebné akce provádí obsluha přerušení, aniž by to ovlivnilo hlavní program. Od hardwarového zařízení nejsou vyžadovány žádné speciální schopnosti.

Hlavní důvody pro volání přerušení jsou:

  • Určení změny stavu výstupu;
  • Přerušení časovače;
  • Přerušení dat přes SPI, I2C, USART;
  • Analogový na digitální převod;
  • Ochota používat EEPROM, flash paměť.

Jak jsou v Arduinu implementována přerušení

Když je přijat signál přerušení, operace je pozastavena. Začne provádění funkce, která je deklarována jako spuštěná při přerušení. Deklarovaná funkce nemůže přijmout vstupní hodnoty a vrátit hodnoty po dokončení. Přerušení neovlivňuje samotný kód v hlavní smyčce programu. Pro práci s přerušeními v Arduinu se používá standardní funkce připojitInterrupt().

Rozdíl mezi implementací přerušení v různých deskách Arduino

V závislosti na hardwarové implementaci konkrétního modelu mikrokontroléru existuje několik přerušení. Deska Arduino Uno má 2 přerušení na druhém a třetím pinu, ale pokud jsou vyžadovány více než dva výstupy, deska podporuje speciální režim „výměny pinů“. Tento režim funguje změnou vstupu pro všechny piny. Rozdíl v režimu přerušení změny vstupu spočívá v tom, že přerušení lze generovat na kterémkoli z osmi pinů. Zpracování v tomto případě bude složitější a delší, protože budete muset sledovat poslední stav na každém z kontaktů.

Na ostatních deskách je počet přerušení vyšší. Deska má například 6 pinů, které zvládnou externí přerušení. U všech desek Arduino je při práci s funkcí attachmentInterrupt (přerušení, funkce, režim) argument Inerrupt 0 spojen s digitálním pinem 2.

Přerušení v jazyce Arduino

Nyní přejděme k procvičování a promluvme si o tom, jak používat přerušení ve vašich projektech.

AttachInterrupt() Syntaxe

Pro práci s přerušeními slouží funkce attachmentInterrupt. Slouží k připojení externího přerušení k handleru.

Syntaxe volání: attachmentInterrupt(přerušení, funkce, režim)

Argumenty funkce:

  • přerušení - číslo volaného přerušení (standardně 0 - pro 2. pin, pro desku Arduino Uno 1 - pro 3. pin),
  • funkce - název volané funkce při přerušení (důležité - funkce by neměla přijímat ani vracet žádné hodnoty),
  • režim je podmínkou pro spuštění přerušení.

Lze nastavit následující podmínky spouštění:

  • LOW - provádí se na nízké úrovni signálu, kdy má kontakt nulovou hodnotu. Přerušení se může cyklicky opakovat – například při stisku tlačítka.
  • ZMĚNA - na přední straně k přerušení dochází při změně signálu z vysokého na nízký nebo naopak. Provádí se jednou při jakékoli změně signálu.
  • RISING - Proveďte přerušení jednou, když se signál změní z LOW na HIGH.
  • FALLING - Proveďte přerušení jednou, když se signál změní z HIGH na LOW.4

Důležité poznámky

Při práci s přerušeními je třeba vzít v úvahu následující důležitá omezení:

  • Spuštění funkce handleru by nemělo trvat příliš dlouho. Jde o to, že Arduino nedokáže zpracovat více přerušení současně. Během provádění funkce manipulátoru budou všechna ostatní přerušení ignorována a můžete zmeškat důležité události. Pokud potřebujete udělat něco velkého, stačí předat zpracování událostí v hlavní smyčce loop(). V handleru můžete nastavit pouze příznak události a ve smyčce můžete příznak zkontrolovat a zpracovat.
  • S proměnnými musíte být velmi opatrní. Inteligentní kompilátor C++ může „znovu optimalizovat“ váš program odstraněním proměnných, které nepotřebuje. Kompilátor prostě neuvidí, že některé proměnné nastavujete v jedné části a používáte je v jiné. Chcete-li tuto možnost v případě základních datových typů eliminovat, můžete použít klíčové slovo volatile, například: volatile boolean state = 0. Tato metoda však nebude fungovat se složitými datovými strukturami. Takže musíte být stále ve střehu.
  • Nedoporučuje se používat velký počet přerušení (zkuste nepoužívat více než 6-8). Velké množství různých událostí vyžaduje vážnou komplikaci kódu, a proto vede k chybám. Kromě toho musíte pochopit, že v systémech s velkým počtem přerušení nemůže být řeč o žádné časové přesnosti provádění - nikdy přesně nepochopíte, jaký je interval mezi voláními příkazů, které jsou pro vás důležité.
  • Delay() se nesmí používat v obslužných programech. Mechanismus pro určování intervalu zpoždění používá časovače a fungují také na přerušeních, která váš handler zablokuje. Výsledkem je, že každý na každého počká a program bude viset. Ze stejného důvodu nelze použít komunikační protokoly založené na přerušení (jako je i2c).

příklady připojení přerušení

Pojďme si procvičit a zvážit nejjednodušší příklad použití přerušení. V příkladu definujeme funkci handleru, která při změně signálu na pinu 2 Arduina Uno přepne stav pinu 13, ke kterému tradičně připojíme LED.

#define PIN_LED 13 volatile boolean actionState = LOW; void setup() ( pinMode(PIN_LED, OUTPUT); // Nastavení přerušení // Funkce myEventListener bude volána, když // se změní signál na pinu 2 (přerušení 0 je připojeno k pinu 2) // se změní signál (ne záleží, kterým směrem) attachmentInterrupt (0, myEventListener, CHANGE); ) void loop() ( // Ve funkci loop neděláme nic, protože veškerý kód pro zpracování událostí bude ve funkci myEventListener) void myEventListener() ( actionState != actionState; // / / Dělejte další věci, jako je zapínání nebo vypínání LED digitalWrite(PIN_LED, actionState); )

Podívejme se na některé příklady složitějších přerušení a jejich obsluhy: pro časovač a tlačítka.

Tlačítko proti odskoku se přeruší

Když dojde k přerušení – než se kontakty při stisknutí tlačítka pevně dotknou, rozkmitají se a vygenerují několik operací. Jsou dva způsoby, jak se s klepáním vypořádat – hardwarově, tedy připájením kondenzátoru k tlačítku, a softwarově.

Pomocí funkce se můžete zbavit drnčení - umožňuje zjistit dobu, která uplynula od prvního stisknutí tlačítka.

If(digitalRead(2)==HIGH) ( //když je tlačítko stisknuto //Pokud od předchozího stisknutí uplynulo více než 100 milisekund if (millis() - previousMillis >= 100) ( //Zapamatujte si čas první operace previousMillis = millis(); if (led==oldled) ( // kontroluje, zda se stav tlačítka nezměnil led=!led; )

Tento kód umožňuje odstranit chatrování a neblokuje provádění programu, jako je tomu u funkce zpoždění, která není povolena v přerušeních.

Časovač přeruší

Časovač je čítač, který počítá na určité frekvenci získané z procesoru 16 MHz. Můžete nakonfigurovat dělič frekvence, abyste získali požadovaný režim počítání. Můžete také nakonfigurovat čítač tak, aby generoval přerušení při dosažení dané hodnoty.

A časovač přerušení umožňuje provést přerušení jednou za milisekundu. Arduino má 3 časovače – Timer0, Timer1 a Timer2. Timer0 se používá ke generování přerušení jednou za milisekundu, čímž se aktualizuje čítač, který je předán funkci millis(). Tento časovač je osmibitový a počítá od 0 do 255. Přerušení je generováno, když je hodnota 255. Ve výchozím nastavení se používá dělič hodin po 65 pro získání frekvence blízké 1 kHz.

Porovnávací registry slouží k porovnání stavu na časovači a uložených dat. V tomto příkladu kód vygeneruje přerušení, když čítač dosáhne 0xAF.

TIMSK0 |= _BV(OCIE0A);

Je nutné definovat obsluhu přerušení pro vektor přerušení časovače. Vektor přerušení je ukazatel na umístění instrukce, která bude provedena při volání přerušení. Několik vektorů přerušení je sloučeno do tabulky vektorů přerušení. Časovač v tomto případě bude mít název TIMER0_COMPA_vect. V tomto handleru budou provedeny stejné akce jako ve smyčce ().

SIGNAL(TIMER0_COMPA_vect) ( bez znaménka dlouhý currentMillis = millis(); sweeper1.Update(currentMillis); if(digitalRead(2) == HIGH) ( sweeper2.Update(currentMillis); led1.Update(currentMillis); ) led2.Update( currentMillis); led3.Update(currentMillis); ) // Funkce loop() zůstane prázdná. void loop() ( )

Shrnutí

Přerušení v Arduinu je poměrně komplikované téma, protože musíte přemýšlet o celé architektuře projektu najednou, představit si, jak se kód provádí, jaké události jsou možné, co se stane, když je hlavní kód přerušen. Nekladli jsme si za cíl odhalit všechny rysy práce s tímto jazykovým konstruktem, hlavním cílem bylo představit hlavní případy použití. V dalších článcích budeme o přerušeních pokračovat podrobněji.

Ahoj Andrey. Váš přístup k předávání zavazadel znalostí a zkušeností, které jste nasbíral, je velmi zajímavý. Do začátku to hodně pomáhá. No, já, když začínám ovládat arduino, mám touhu postupovat. Navíc s pomocí zvenčí to zvládnu rychleji. Takže: mým úkolem bylo nejprve přimět robota pohybujícího se po lince. Povedlo se - vše je v pořádku. Ale dále, když mu byly poskytnuty další možnosti, nechápal, proč přestal správně reagovat na linku. Narazil jsem na tento článek a pochopil jsem proč.

Nyní mám pro vás otázku: v náčrtu níže a připraven, vzhledem k problémům se zpožděním, musím přepnout na milis všude, kde je tato funkce přítomna? Pokud ano, pak chápu, že se bude muset předělat téměř celý náčrt? A není úplně jasné, jak používat milis při měření vzdálenosti? Děkuji.

//Robot s funkcí sledování bílé čáry

// ********************* Nastavit vodiče motoru ********************* *

int MotorLeftSpeed ​​​​= 5; // Vlevo (A) OTÁČKY motoru - ENA

int MotorLeftForward = 4; // Levý (A) motor VPŘED - IN1

int MotorLeftBack = 3; // Levý (A) Motor BACK - IN2

int MotorRightForward = 8; // Pravý (B) Motor VPŘED - IN3

int MotorRightBack = 7; // Pravý (B) Motor BACK - IN4

int MotorRightSpeed ​​​​= 9; // Pravý (B) motor SPEED - ENB

// ********************* Nainstalujte výstupy ultrazvukových senzorů******************** **** *

inttrigPinL = 14; // nastavení výstupního čísla levého trig ultrazvukového senzoru

int echoPinL = 15; // nastavení výstupního čísla levého echo ultrazvukového senzoru

inttrigPinC = 10; // nastavení výstupního čísla centrálního trig ultrazvukového senzoru

int echoPinC = 11; // nastavení výstupního čísla centrálního echo ultrazvukového senzoru

inttrigPinR = 12; // nastavení výstupního čísla pravého trig ultrazvukového senzoru

int echoPinR = 13; // nastavení výstupního čísla pravého echo ultrazvukového senzoru

// ********************* Nastavení výstupů linkových snímačů *******************

const int LineSensorLeft = 19; // vstup senzoru levého řádku

const int LineSensorRight = 18; // vstup pravého linkového senzoru

intSL; // stav levého senzoru

intSR; // stav pravého senzoru

// ********************* Nastavení výstupu světelných a zvukových alarmů ****************

int Světlo = 2; // nastavení výstupního čísla světelného signálu

int Zumm = 6; // nastavení výstupního čísla bzučáku

int ledState = NÍZKÁ; // nastaví stav LED na tuto proměnnou

dlouho předchozíMillis = 0; // uložení času posledního sepnutí LED

dlouhý interval = 300; // interval mezi zapnutím / vypnutím LED (0,3 sekundy)

// ********************* Měření proměnné vzdálenosti pomocí senzorů***************

unsigned int impulseTimeL=0;

unsigned int impulsTimeC=0;

unsigned int impulseTimeR=0;

dlouhý distL=0; // vzdálenost měřená levým ultrazvukovým senzorem

dlouhý distC=0; // vzdálenost měřená centrálním ultrazvukovým senzorem

dlouhý distR=0; // vzdálenost měřená pravým Uz senzorem

// ********************************** NASTAVENÍ ********* ***** ***************

Serial.begin(9600); // spuštění sériového portu (rychlost 9600)

//*************** Nastavit kontakty motoru********************

pinMode(MotorRightBack, OUTPUT); // Vpravo (B) Motor ZPĚT

pinMode(MotorRightForward, OUTPUT); // Vpravo (B) Motor VPŘED

pinMode(MotorLeftBack, OUTPUT); // Levý (A) Motor ZPĚT

pinMode(MotorLeftForward, OUTPUT); // Levý (A) Motor VPŘED

zpoždění (trvání);

//*************** Nastavte kontakty proužkového senzoru******************

pinMode(LineSensorLeft, INPUT); // definování pinu levého linkového senzoru

pinMode(LineSensorRight, INPUT); // definování pinu pravého linkového senzoru

// ***************Nastavení výstupních režimů ultrazvukových senzorů*************************

pinMode(trigPinL, OUTPUT); // nastavení pracovního režimu výstupu levého trig ultrazvukového snímače

pinMode(echoPinL, INPUT); // nastavení pracovního režimu výstupu levého echo ultrazvukového senzoru

pinMode(trigPinC, OUTPUT); // nastavení pracovního režimu výstupu centrálního trig ultrazvukového senzoru

pinMode(echoPinC, INPUT); // nastavení pracovního režimu výstupu centrálního echo ultrazvukového senzoru

pinMode(trigPinR,OUTPUT); // nastavení pracovního režimu výstupu pravého trig ultrazvukového senzoru

pinMode(echoPinR, INPUT); // nastavení výstupního režimu výstupu pravého echo ultrazvukového senzoru

// *************** Nastavení kontaktů pro světelné a zvukové alarmy************************ *************

pinMode(Zumm,VYSTUP); // nastavení provozního režimu výstupu bzučáku

pinMode(Světlo,VÝSTUP); // nastavení pracovního režimu výstupu světelné signalizace

// ******************** Základní pohybové příkazy ******************

void forward (int a, int sa) // FORWARD

analogWrite(MotorRightSpeed, sa);

analogWrite(MotorLeftSpeed, sa);

void right (int b, int sb) // OTOČIT DOPRAVA (jedna strana)

digitalWrite(MotorRightBack, LOW);

digitalWrite(MotorLeftBack, LOW);

digitalWrite(MotorLeftForward, HIGH);

analogWrite(MotorLeftSpeed, sb);

void left (int k, int sk) // OTOČENÍ DOLEVA (jedna strana)

digitalWrite(MotorRightBack, LOW);

digitalWrite(MotorRightForward, HIGH);

analogWrite(MotorRightSpeed, sk);

digitalWrite(MotorLeftBack, LOW);

void stop(int f) // STOP

digitalWrite(MotorRightBack, LOW);

digitalWrite(MotorRightForward, LOW);

digitalWrite(MotorLeftBack, LOW);

digitalWrite(MotorLeftForward, LOW);

// ******************************* Měření vzdálenosti************************* *

void izmdistL () // měření vzdálenosti levým ultrazvukovým senzorem

digitalWrite(trigPinL, HIGH);

digitalWrite(trigPinL, LOW); // Puls 10mS na spouštěcí výstup ultrazvukového senzoru pro měření vzdálenosti

impulseTimeL = pulseIn(echoPinL, HIGH); // čtená vzdálenost od ultrazvukového senzoru

distL=impulsTimeL/58; // Převod na centimetry

void izmdistC () // měření vzdálenosti centrálním ultrazvukovým senzorem

digitalWrite(trigPinC, HIGH);

digitalWrite(trigPinC, LOW); // Puls 10mS na spouštěcí výstup ultrazvukového senzoru pro měření vzdálenosti

impulseTimeC = pulseIn(echoPinC, HIGH); // čtená vzdálenost od ultrazvukového senzoru

distC=impulseTimeC/58; // Převod na centimetry

void izmdistR () // měření vzdálenosti centrálním ultrazvukovým senzorem

digitalWrite(trigPinR, HIGH);

digitalWrite(trigPinR, LOW); // Puls 10mS na spouštěcí výstup ultrazvukového senzoru pro měření vzdálenosti

impulseTimeR = pulseIn(echoPinR, HIGH); // čtená vzdálenost od ultrazvukového senzoru

distR=impulsTimeR/58; // Převod na centimetry

// ********************************** SMYČKA ********** ***** *******************

// ********************* Režim sledování LINE ********************* ***

// ******************** světelná a zvuková signalizace*******************

tón (Zumm, 900); // zapnout zvuk na 900 Hz

tón (Zumm, 900); // zapnout zvuk na 800 Hz

unsigned long currentMillis = millis();

if (currentMillis - previousMillis > interval) // kontrola, zda uplynul požadovaný interval, pokud uplynul, pak

předchozíMillis = aktuálníMillis; // uložení času posledního přepnutí

if (ledState == LOW) // pokud LED nesvítí, tak ji rozsvítíme a naopak

ledState = VYSOKÁ;

digitalWrite(Světlo, ledState); // nastavení výstupních stavů pro zapnutí nebo vypnutí LED

// ******************************* Měření vzdálenosti************************* ********

Serial.println(distL);

Serial.println(distC);

Serial.println(distR);

if (distL>50 && distC>50 && distR>50) // pokud je naměřená vzdálenost větší než 50 centimetrů - jít

SL=digitalRead(LineSensorLeft); // přečte signál z levého snímače jízdního pruhu

SR=digitalRead(LineSensorRight); // čtení signálu z pravého snímače jízdního pruhu

// ************************* Po černé čáře ******************* ****

// ROBOT na pruhu - jedeme rovně

if (SL == LOW & SR == LOW) // BÍLÁ - BÍLÁ - jděte ROVNĚ

vpřed(10, 100);// VPŘED(čas, rychlost)

// ROBOT se začíná řadit z pruhu - pojíždíme

else if (SL == NÍZKÁ & SR == VYSOKÁ) // ČERNO - BÍLÁ - odbočte DOLEVA

doleva (10, 100);// otočit DOLEVA (čas, rychlost)

else if (SL == HIGH & SR == LOW) // BÍLÁ - ČERNÁ - odbočte DOPRAVA

doprava (10, 100); // otočte DOPRAVA (čas, rychlost)

// FINISH - ROBOT vidí jízdní pruh s oběma senzory

else if (SL == HIGH & SR == HIGH) // BLACK - BLACK - STOP

stop(50); // STOP

else // pokud je naměřená vzdálenost menší nebo rovna minimu, zastavte se