Vyhledávání

#4 - Pokročilejší struktury jazyka Wiring

23.12.2013 14:27

Pokročilejší struktury jazyka Wiring

V tomto díle navážeme na informace z minula a ukážeme si další možnosti jazyka Wiring. Na začátku si řekneme, co jsou to konstanty a jak je používat. Poté si ukážeme, jak pracovat s analogovým vstupem a výstupem, pomocí něhož se dají získávat data z různých analogových senzorů. Nakonec se dostaneme k velmi důležité součásti jakéhokoliv programovacího jazyka, kterou jsou podmínky.


Konstanty

Konstanty si můžeme představit jako proměnné, které mají přednastavenou hodnotu, definovanou tvůrci Arduina. Mají za úkol zpřehlednit práci a přiblížit kód lidskému jazyku. My jsme s některými z nich pracovali již v minulém dílu. Můžeme je rozdělit do tří skupin.


Logické konstanty

Jsou pouze dvě hodnoty, a to pravda a nepravda. V programování jim odpovídají konstanty true a false. Používají se tam, kde je třeba rozhodovat pouze mezi dvěma stavy.

  • false
    • Konstanta false má hodnotu 0.
  • true
    • U konstanty true je situace trochu komplikovanější. Mohlo by se zdát, že má hodnotu 1, ale není to úplně přesné. Při logických operacích totiž jazyk Wiring vnímá jakékoliv nenulové číslo typu integer jako true.

 


Typ digitálního pinu

V minulém díle jsme při určování, zda se bude pin chovat jako vstup, nebo jako výstup, používali ve funkci pinMode() dvě konstanty - OUTPUT a INPUT. Dnes si k nim přidáme ještě třetí možnost INPUT_PULLUP.

  • OUTPUT
    • Při použití této konstanty je pin nastaven jako výstup. Ten snese proud do 40 mA. Při stavu HIGH tedy tento výstup může poskytnout proud do 40 mA a při stavu LOW může stejně velký proud přijmout.
  • INPUT
    • Nastaví pin jako vstup. Ten se používá ke čtení hodnot z digitálních senzorů (nejjednodušší jsou tlačítka), ale i ke komunikaci. Použití s tlačítkem jsme si ukázali v minulém dílu. V jeho zapojení si všimněme, že je tento pin stále připojen ke GND přes 10k ohm resistor. Při nezmáčknutém tlačítku je tedy výsledek funkce digitalRead() hodnota LOW. Po zmáčknutí tlačítka dojde k připojení k +5V a změny hodnoty funkce na HIGH.Pouziti-tlacitka-s-INPUT.
  • INPUT_PULLUP
    • Funguje podobně, jako INPUT. Rozdíl je v tom, že dojde k připojení interního rezistoru. Ten je uvnitř čipu zapojen mezi digitálním vstupem a +5V. Výchozí hodnota funkce digitalRead() je tedy HIGH. Když chceme hodnotu změnit, musíme vstup připojit na GND. Při použití příkladu s tlačítkem má tedy funkce hodnotu HIGH, když je tlačítko uvolněno a LOW, když je zmáčknuto.Pouziti-tlacitka-s-INPUT_PULLOUT.

 


Hodnota proudu na pinu

Jsou pouze dvě možné hodnoty, jaké může mít proud při čtení a zápisu pomocí funkcí digitalRead() a digitalWrite(). Jsou to hodnoty LOW a HIGH.

  • HIGH
    • Při čtení pomocí funkce digitalRead() je vyhodnocena hodnota napětí jako HIGH, pokud je větší než 3V. Když použijeme funkci digitalWrite(pin, HIGH), na výstupu bude právě 5V.
  • LOW
    • Při čtení je stav napětí vyhodnocen jako LOW, pokud je jeho velikost menší než 2V. Při zápisu je hodnota 0V. Fakticky ale může "přijmout" napětí do velikosti 5V(což u HIGH nelze).

 


Analogový vstup a výstup

S digitálním vstupem a výstupem jsme se setkali už v minulém článku. Co když ale potřebujeme pracovat i s analogovými hodnotami? Na to má Arduino ve výbavě užitečné funkce. Ke čtení a zápisu se zde používají funkce analogRead() a analogWrite(). Ty jsou však limitovány pro použití pouze na určených pinech. Pojďme si je postupně představit.


analogWrite()

Jak už z názvu vyplývá, jedná se o funkci sloužící k nastavení "analogové" hodnoty na pinu. Můžeme ji použít pouze na pinech označených PWM (u Arduina UNO jsou to piny: 3, 5, 6, 9, 10, 11). Používá se u ní syntaxe digitalWrite(číslo_pinu, hodnota), kdy hodnota může být v rozsahu 0 až 255. Slovo analogové jsem dal do uvozovek, protože se ve skutečnosti o žádné analogové hodnoty nejedná. Pokud bychom chtěli skutečně analogovou hodnotu v rozsahu například 0-5V, museli bychom použít externí D/A převodník. Tato funkce totiž na vybraných pinech generuje PWM signál, což je jakási digitální "náhražka" analogového signálu. Ta v praxi funguje tak, že rychle střídá 0 a 5V. To se projeví sníženou 'účinností'. LED svítí slaběji (ve skutečnosti rychle bliká a střídá pouze dva stavy napětí a snížená intenzita je způsobena setrvačností oka), motor se točí pomaleji atd. Podle poměru času, ve kterém je na výstupu +5V ku stavu 0V se pak odvíjí intenzita svícení LED diody a podobně. Při volání funkce analogWrite(pin, 127) je tedy přibližně 50% času nastaveno napětí +5V a 50% času 0V. Průběh napětí při různých hodnotách můžete vidět na obrázku. PWM


analogRead()

Funkce analogRead() slouží ke čtení analogové hodnoty na vstupech k tomu určeným. Jsou to tedy piny označené písmenem A (například A2). Čtení analogových hodnot je užitečné u různých senzorů (teplota, vlhkost atd.). Většina desek Arduina má rozlišení 10 bitů, což odpovídá hodnotám od 0 do 1023. Například u Arduino DUE se ale můžeme setkat až s 12-bitovým rozlišením. Zde se dá nastavit požadované rozlišení pomocí funkce analogReadResolution(). My se ale budeme zabývat obyčejným Arduinem. Syntaxe je jednoduchá: proměnná = analogRead(pin). Nejjednodušším příkladem použití je měření hodnot na potenciometru. Pokud bychom chtěli měřit například stav fotoresistoru, museli bychom ho zapojit do děliče napětí s vhodným resistorem. Použití obou analogových funkcí si ukážeme na zapojení s LED diodou a potenciometrem.


Příklad

Jako příklad si ukážeme zapojení, ve kterém budeme regulovat jas LED diody pomocí potenciometru.
Budeme potřebovat:

  1. Deska Arduino
  2. Nepájivé kontaktní pole s vodiči
  3. LED dioda
  4. potenciometr
  5. 330 ohm resistor

Na trhu nalezneme celou řadu potenciometrů. Nejčastěji se používají ty s odporem kolem 10k ohm s lineárním průběhem. Pokud máme všechny komponenty připravené, můžeme je zapojit podle následujícího schématu: V programu si musíme dát pozor na hodnoty, se kterými funkce pracují. Z funkce analogRead() vychází hodnoty 0 až 1023, kdežto analogWrite() čeká na rozsah hodnot 0 až 255. Musíme tedy zajistit převod hodnot. To je v tomto případě jednoduché, protože 256 (28) se vejde do 1024 (210) čtyřikrát. Nejjednodušším způsobem je tedy vydělení hodnot z analogRead() čtyřmi. Kód tohoto příkladu bude také velmi jednoduchý. Měření budeme provádět v těle funkce loop().

Poznámka: Existuje i elegantnější způsob převodu hodnot, který si ukážeme v některém z budoucích článků.

byte led = 6; //pin s LED diodou
byte pot = A0; //pin s připojeným potenciometrem
int val; //proměnná připravená k uchování hodnot

void setup() {
  //sem nic nepíšeme
}

void loop() {
  val = analogRead(pot)/4; 
  //čtení hodnoty na A0 a úprava rozsahu
  analogWrite(led, val); 
  //generování PWM
}

 


Podmínky

Pokud chceme, aby se určitá část kódu provedla pouze v určitých případech, přicházejí na řadu podmínky. Existují tři základní struktury, které rozdělují program podle zadaných podmínek. V lidské řeči by se daly vyjádřit jako:

  1. Pokud platí podmínka, udělej to a to.
  2. Pokud platí podmínka, udělej to a to. Pokud neplatí, udělej to a to.
  3. Pokud je hodnota proměnné xy, udělej to a to. Pokud je yz, udělej to a to. Pokud je xz, udělej to a to...

Než se však pustíme do psaní podmínek, musíme se podívat na způsob, jakým se dají v jazyce Wiring zadávat.

 


Porovnávací operátory

Porovnávací operátory slouží k zápisu podmínek. Jedná se o systém značek, které jsou pro počítač srozumitelné. Výsledkem porovnávací operace je logická hodnota true, nebo false. Rozlišujeme šest operátorů.

  • A == B - A je rovno B
    • Vrátí hodnotu true, pokud A má stejnou hodnotu, jako B.
  • A != B - A není rovno B
    • Vrátí hodnotu true, pokud má A jinou hodnotu než B.
  • A < B - A je menší než B
    • Vrátí hodnotu true, pokud je A menší než B.
  • A > B - A je větší než B
    • Vrátí true, pokud je A větší než B.
  • A <= B - A je menší nebo rovno B
    • Vrátí true, pokud je A menší nebo rovno B.
  • A >= B - A je větší nebo rovno B
    • Vrátí true, pokud je A větší nebo rovno B.
10 == 5 //není pravda
10 != 5 //je pravda
10 < 5 //není pravda
10 > 5 //je pravda
10 <= 5 //není pravda
10 >= 5 //je pravda

 


Složené podmínky

Někdy dospějeme do situace, ve které je potřeba pracovat s nějakou složitější podmínkou. K tomuto účelu slouží tzv. logické operátory. Můžeme si je představit jako definici vztahu mezi více porovnávacími operátory.

  • X && Y - a (konjunkce)
    • Výsledkem je true pouze v případě, když jsou true X i Y.
  • X || Y - nebo (disjunkce)
    • Výsledkem je true v případě, kdy je alespoň jedna z X a Y true.
  • !X - negace
    • Výsledkem je true, pokud je X false a naopak.
(1 == 2) && (2 == 2) //false
(1 == 1) && (2 == 2) //true

(1 == 2) || (2 == 3) //false
(1 == 2) || (2 == 2) //true
(2 == 2) || (2 == 3) //true
(2 == 2) || (3 == 3) //true

!(1 == 1) //false
!(1 == 2) //true
!(false) //true	

 


if()

Ve většině programovacích jazyků se pro zápis podmínek používá slovo if. V jazyce Wiring je možné použít několik způsobů zápisu. Ty ale vždy začínají: if(podmínka).

//podmínky s jedním příkazem

if(x > 120) digitalWrite(LEDpin, HIGH); 

if(x > 120)
digitalWrite(LEDpin, HIGH); 

if(x > 120){ digitalWrite(LEDpin, HIGH); } 

//podmínky s více příkazy - je nutné použít složené závorky
if(x > 120){ 
  digitalWrite(LEDpin1, HIGH);
  digitalWrite(LEDpin2, HIGH); 
  ...
}

 


else if()

Pokud chceme do podmínky přidat více možností, používá se zápis else if().

if (A < 800){
	//příkazy
}
else if ((A < 500) && (A > 200)){
	//příkazy
}

 


else

K části else se nepíší další podmínky. Slouží k určení příkazů, které se provedou, pokud ani jedna z předchozích podmínek není splněna.

if (A < 800){
	//příkazy
}
else if ((A < 500) && (A > 200)){
	//příkazy
}
else{
	//příkazy
}

 


Switch

Switch je speciální druh podmínky. Speciální je v tom, že se zabývá pouze proměnnou a její hodnotou. Program prochází každou větev konstrukce switch a testuje hodnotu proměnné. Další rozdíl je v tom, že se může provést i více větví (což u if nelze). Pokud ale chceme, aby po provedení větve program pokračoval až za koncem konstrukce switch, musíme použít na konci větve příkaz break;
Syntaxe je následující:

switch (proměnná){
	case 1:
		//pokud je hodnota proměnné 1, provede se tato část kódu
		break; //po provedení této části konstrukce switch končí
	case 2:
		//pokud je hodnota proměnné 2, provede se tato část kódu
		break;
	default: 
		/* pokud se hodnota proměnné nerovná žádné z nabízených možností,
		provede se tato část */
  }

 


Příklad

Na závěr si trochu pohrajeme s podmínkami. Vytvoříme aplikaci, která bude číst hodnotu z potenciometru a podle ní vybere led diodu. K tomuto příkladu budeme potřebovat stejné vybavení, jako u toho minulého, jen s větším počtem LED diod a resistorů. Pro předváděcí účely jsem zvolil pět diod. Kód vyhodnocující data z potenciometru by mohl vypadat takto:

byte led[] = {0,1,2,3,4}; //pole s piny připojených LED diod
byte pot = A0;
int val;
 
void setup() {
	pinMode(led[0], OUTPUT);
	pinMode(led[1], OUTPUT);
	pinMode(led[2], OUTPUT);
	pinMode(led[3], OUTPUT);
	pinMode(led[4], OUTPUT);
}
 
void loop() {
	val = analogRead(pot);

	if(val > 800){
		digitalWrite(led[0],HIGH);
	}
	else if(val > 600){
		digitalWrite(led[1],HIGH);
	}
	else if(val > 400){
		digitalWrite(led[2],HIGH);
	}
	else if(val > 200){
		digitalWrite(led[3],HIGH);
	}
	else{
		digitalWrite(led[4],HIGH);
	}
        
	delay(250);
	digitalWrite(led[0],LOW);
	digitalWrite(led[1],LOW);
	digitalWrite(led[2],LOW);
	digitalWrite(led[3],LOW);
	digitalWrite(led[4],LOW);
}

Když se nyní podíváte na kód, jsou zde vidět opakování, ve kterých se mění pouze jedno číslo. Jak si v takovýchto případech ulehčit práci si ukážeme v příštím dílu.

 


Zdroje obrázků

[Digital Read - INPUT]
[Digital Read - INPUT_PULLUP]
[PWM]


<--#3 - Základní struktury jazyka Wiring||#5 - Sériová komunikace a Cykly-->

Zpět

Diskusní téma: #4 - Pokročilejší struktury jazyka Wiring

Datum
Vložil
Titulek

proud / napeti

Hodnota proudu na pinu

Jsou pouze dvě možné hodnoty, jaké může mít proud při čtení a zápisu pomocí funkcí digitalRead() a digitalWrite(). Jsou to hodnoty LOW a HIGH.

Zde snad patri , hodnota NAPETI na pinu .

Datum
Vložil
Titulek

chyba ?

v popisu funkce analogWrite je chybně uvedeno v druhém řádku textu : Používá se u ní syntaxe digitalWrite(číslo_pinu, ......

Datum
Vložil
Titulek

Re: chyba ?

zrovna jsem to sem chtěl napsat :)

Datum
Vložil
Titulek

frekvence čitače PWM

Existuje funkce kterou lze měnit frekvenci čítače PWM? Nevím jestli je tořečeno technicky správně, tak to zkusím ještě laicky. Potřeboval bych aby jeden cyklus trval 2 sekundy, tzn. když nastavím výstup na 50%, bude 1s. HIGH a 1s. LOW, když na 25% tak 0,5s. HIGH a 1,5s. LOW, 10%=0,2s. HIGH/1,8s.LOW, atd .....
Potřebuji řídit ohřev nádrže a v současnosti mám k regulaci použitý IO T2117, který právě tímto periodickým způsobem řídí výkon do topné spirály. IO se bohužel před nedávnem přestal prodávat. S takto nízkou frekvencí spínání to při použití SSR relé se spínáním v nule neprodukuje prakticky žádné vf rušení.

Datum
Vložil
Titulek

Re: frekvence čitače PWM

Tak PWM není věcí kontroleru, ale funkce analog.write.
Napiš si prostě svoji v C, místo toho balastu z andrujna.

Datum
Vložil
Titulek

Re: Re: frekvence čitače PWM

jo jinak podle zvuku pískání těch motorků to bude 4 kHz :-)

Datum
Vložil
Titulek

Re: Re: Re: frekvence čitače PWM

To lze odstranit = nastavit vyšší frekvenci pro PWM. Třeba takto:

// set timer 1 divisor to 256 for PWM frequency of 122.55 Hz
TCCR1B = TCCR1B & B11111000 | B00000100;

Datum
Vložil
Titulek

chybka?

Datum
Vložil
Titulek

Re: chybka?

Tady v tom příkladu ta prostřední větev (else if) asi nemá smysl ne?

if (A < 800){
//příkazy
}
else if ((A < 500) && (A > 200)){
//příkazy
}
else{
//příkazy
}

Datum
Vložil
Titulek

Re: Re: chybka?

Pravda. Děkuji.

Lepší by bylo v prvním if mít (A < 800) && (A > 500)

1 | 2 >>

© 2015 Všechna práva vyhrazena.

www.hwkitchen.com