From d9e196338e8f6e5cf54d8eb7a315fe2bb1519399 Mon Sep 17 00:00:00 2001 From: "Michal, OK1WMR" <ok1wmr@gmail.com> Date: Sun, 10 Apr 2011 06:33:14 +0200 Subject: [PATCH] =?UTF-8?q?P=C5=99id=C3=A1n=20=C4=8Dl=C3=A1nek=20AVR=20-?= =?UTF-8?q?=20LED=20panel=20-=20#6=20Program?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (Autoexportován z Joomly) --- articles/2011/avr-led-panel-6-program.md | 568 +++++++++++++++++++++++ 1 file changed, 568 insertions(+) create mode 100644 articles/2011/avr-led-panel-6-program.md diff --git a/articles/2011/avr-led-panel-6-program.md b/articles/2011/avr-led-panel-6-program.md new file mode 100644 index 0000000..f3a8017 --- /dev/null +++ b/articles/2011/avr-led-panel-6-program.md @@ -0,0 +1,568 @@ ++++ + +title = "AVR - LED panel - #6 Program" +perex_e = " + +KompatibilnĂ zapojenĂ: LED panel s ATmega8 + +Ke staĹľenĂ: LED_006.c == LED_006.pdf == LED_006.htm +. +. +" +tags = ["ÄŚlánek"] ++++ + + + +KompatibilnĂ zapojenĂ: LED panel s ATmega8 + +Ke staĹľenĂ: LED_006.c == LED_006.pdf == LED_006.htm +. +. + +* * * + +<title>Untitled</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="generator" content="SynEdit HTML exporter"> <style type="text/css">&amp;amp;amp;lt;!-- body { color: #000000; background-color: #FFFFFF; } .cpp1-assembler { } .cpp1-brackets { } .cpp1-comment { color: #008000; font-style: italic; } .cpp1-float { color: #000080; } .cpp1-hexadecimal { color: #000080; } .cpp1-character { } .cpp1-identifier { } .cpp1-illegalchar { } .cpp1-number { color: #000080; } .cpp1-octal { color: #0000FF; } .cpp1-preprocessor { } .cpp1-reservedword { font-weight: bold; } .cpp1-space { color: #008080; } .cpp1-string { color: #800000; } .cpp1-symbol { } --&amp;amp;amp;gt;</style> + +``` +/* +V minulĂ©m programu jsme si ukázali, jak pomocĂ tlaÄŤĂtka ovlivĹovat bÄ›h programu. +Tento program však mÄ›l jeden velkĂ˝ nedostatek. KdyĹľ jsme totiĹľ pomocĂ konstanty +"RYCHLOST" zvýšili rychlost bÄ›hu hada, zvýšila se zároveĹ i rychlost, kterou program +"ÄŤetl" zda je stisknutĂ© tlaÄŤĂtko. Pokud jsme tedy nastavili rychlost kupĹ™Ăkladu na +20 krokĹŻ za sekundu, tak program takĂ© 20x za jednu vteĹ™inu zjišťoval, jestli +nÄ›kdo nedržà stisknutĂ© tlaÄŤĂtko. Pak se stalo, Ĺľe bÄ›hem jednoho stisku tlaÄŤĂtka +(kterĂ˝ trvá asi 0,5 vteĹ™iny) program 10x zjistil, Ĺľe je tlaÄŤĂtko stisknutĂ© a +prodlouĹľil hada. PĹ™i vyššĂch rychlostech bylo tedy tĂ©měř nemoĹľnĂ© pĹ™esnÄ› nastavit +dĂ©lku hada. +PotĹ™ebovali bychom tedy, aby se tyto dva dÄ›je (bÄ›h hada a testovánĂ tlaÄŤĂtka) +odehrávaly nezávisle na sobÄ›. Tento problĂ©m lze vyĹ™ešit pomocĂ ÄŤasovaÄŤe. +ÄŚasovaÄŤ je zaĹ™ĂzenĂ, kterĂ© běžà nezávisle na bÄ›hu programu a jednou za urÄŤitĂ˝ ÄŤas +vygeneruje pĹ™erušenĂ. PĹ™erušenĂ je vlastnÄ› takovĂ© upozornÄ›nĂ pro procesor, Ĺľe je +tĹ™eba nÄ›co udÄ›lat. Jakmile procesor obdržà poĹľadavek o pĹ™erušenĂ, tak dokoná právÄ› +rozdÄ›lanou instrukci, a "odskoÄŤĂ si" udÄ›lat co je potĹ™eba. PotĂ© co vykoná vše +potĹ™ebnĂ©, se program opÄ›t vrátĂ k rozdÄ›lanĂ© práci a pokraÄŤuje v normálnĂm bÄ›hu. +Pro nás to znamená, Ĺľe náš program mĹŻĹľe bĂ˝t kdykoli v jakĂ©mkoli mĂstÄ› pĹ™erušen. +Z tohoto dĹŻvodu je potĹ™eba obsluhu pĹ™erušenĂ (to co má program vykonat, kdyĹľ jej +ÄŤasovaÄŤ pĹ™erušĂ) psát co nejkratšĂ, aby co nejmĂ©nÄ› ovlivĹovala bÄ›h hlavnĂho programu. +*/ + +/* +MikrokontrolĂ©r ATmega8 má zabudovanĂ© dva osmibitovĂ© a jeden šestnáctibitovĂ˝ +ÄŤĂtaÄŤ/ÄŤasovaÄŤ. ÄŚĂtaÄŤe/ÄŤasovaÄŤe se nazĂ˝vajĂ proto, Ĺľe se dajĂ pouĹľĂt nejen k pĹ™esnĂ©mu +ÄŤasovánĂ programu, ale takĂ© mohou slouĹľit jako ÄŤĂtaÄŤ vnÄ›jšĂch impulzĹŻ. +ÄŚasovaÄŤ funguje tak, Ĺľe je do nÄ›j pĹ™iveden hodinovĂ˝ signál, kterĂ˝ si lze pĹ™edstavit +jako obdĂ©lnĂkovĂ© pulzy. ÄŚasovaÄŤ s kaĹľdĂ˝m pulzem zvýšà hodnotu ve svĂ©m registru o 1. +VlastnÄ› funguje jako ÄŤĂtaÄŤ hodinovĂ©ho signálu (poÄŤĂtá pulzy). NejdĹŻleĹľitÄ›jšà ale je, +Ĺľe jakmile tento ÄŤĂtaÄŤ dojde ke svĂ© maximálnĂ hranici (pĹ™eteÄŤe), vyvolá pĹ™erušenĂ, +vynuluje se, a poÄŤĂtá zase od začátku. MaximálnĂ hodnota, ke kterĂ© mĹŻĹľe ÄŤĂtaÄŤ dojĂt, +je dána velikostĂ jeho registru. Pro osmibitovĂ˝ ÄŤĂtaÄŤ je to ÄŤĂslo 255 a pro +16\. bitovĂ˝ je to ÄŤĂslo 65535\. +Toto ÄŤĂslo se nacházĂ v registru TCNT. Podle ÄŤĂsla pouĹľitĂ©ho ÄŤasovaÄŤe se pak mÄ›nĂ +koncovka jeho názvu - TCNT0 = ÄŤasovaÄŤ 0, TCNT1 = ÄŤasovaÄŤ 1 a TCNT2 je ÄŤasovaÄŤ 2. +Pokud tedy chceme nastavit ÄŤas, za jakĂ˝ nám registr ÄŤasovaÄŤe pĹ™eteÄŤe a vyvolá +pĹ™erušenĂ, staÄŤĂ pouze do registru TCNT zapsat nÄ›jakĂ© ÄŤĂslo. ÄŚasovaÄŤ pak nepoÄŤĂtá od +nuly, ale od tohoto ÄŤĂsla, a pĹ™eteÄŤe tedy dĹ™Ăv. +Jako zdroj hodinovĂ©ho signálu vÄ›tšinou sloužà vlastnĂ hodinovĂ˝ signál procesoru. +ProtoĹľe však hodinovĂ˝ signál procesoru kmitá miliĂłnkrát za vteĹ™inu (1 MHz), +pĹ™etekl by ÄŤasovaÄŤ tĂ©měř 4 000x za jednu vteĹ™inu. ProtoĹľe však potĹ™ebujeme nastavit +mnohem delšà časy, musĂme pouĹľĂt takzvanou pĹ™eddÄ›liÄŤku. +PĹ™eddÄ›liÄŤka je zaĹ™azená mezi zdrojem hodinovĂ©ho signálu a samotnĂ˝m ÄŤasovaÄŤem. +Jak jiĹľ jejĂ název napovĂdá, pĹ™eddÄ›liÄŤka sloužà k tomu, aby hodinovĂ˝ signál pro +ÄŤasovaÄŤ vydÄ›lila nÄ›jakĂ˝m ÄŤĂslem. Funguje to tak, Ĺľe napĹ™Ăklad pĹ™eddÄ›liÄŤka osmi +propustĂ kaĹľdĂ˝ osmĂ˝ impulz, pĹ™eddÄ›liÄŤka 64 propustĂ kaĹľdĂ˝ 64\. impulz, atd. +K Ĺ™ĂzenĂ ÄŤasovaÄŤe a pĹ™eddÄ›liÄŤky se pouĹľĂvá registr TCCR (opÄ›t na konci opatĹ™en +ÄŤĂslem ÄŤasovaÄŤe). PodĂvejme se nynĂ, jak se nastavuje napĹ™Ăklad ÄŤasovaÄŤ 0: +*/ +/* +TCCR0 = 0 - ÄŤĂtaÄŤ je vypnut +TCCR0 = 1 - ÄŤĂtaÄŤ je zapnut, a pracuje pĹ™Ămo s hodinovĂ˝m signálem (bez pĹ™eddÄ›liÄŤky) +TCCR0 = 2 - ÄŤĂtaÄŤ je zapnut s pĹ™eddÄ›liÄŤkou osmi (hodinovĂ˝ signál/8) +TCCR0 = 3 - ÄŤĂtaÄŤ je zapnut s pĹ™eddÄ›liÄŤkou 64 +TCCR0 = 4 - ÄŤĂtaÄŤ je zapnut s pĹ™eddÄ›liÄŤkou 256 +TCCR0 = 5 - ÄŤĂtaÄŤ je zapnut s pĹ™eddÄ›liÄŤkou 1024 +*/ +/* +NynĂ tedy umĂme zapnout ÄŤasovaÄŤ a nastavit mu pĹ™eddÄ›liÄŤku (TCCR). Dokážeme takĂ© +jemnÄ› nastavit ÄŤas, za kterĂ˝ nám ÄŤasovaÄŤ pĹ™eteÄŤe. To dÄ›láme pomocĂ registru ÄŤasovaÄŤe +(TCNT), do kterĂ©ho nahrajeme hodnotu, od kterĂ© má zaÄŤĂt poÄŤĂtat. +JedinĂ© co tedy potĹ™ebujeme ještÄ› udÄ›lat, je povolit pĹ™erušenĂ od ÄŤasovaÄŤe. MusĂme +vlastnÄ› procesoru Ĺ™Ăct, aby toto pĹ™erušenĂ akceptoval. ImplicitnÄ› je totiĹľ +mikrokontrolĂ©r nastaven tak, Ĺľe všechna pĹ™erušenĂ (kromÄ› resetu) ignoruje. Atmega8 +má totiĹľ 19 rĹŻznĂ˝ch moĹľnĂ˝ch zdrojĹŻ pĹ™erušenĂ jako: reset, ÄŤĂtaÄŤe, vnÄ›jšà pĹ™erušenĂ, +A/D pĹ™evodnĂk, sĂ©riovĂ© kanály a dalšĂ. Všechna tato zaĹ™ĂzenĂ mohou vyvolat pĹ™erušenĂ. +K povolovánĂ nebo zakazovánĂ pĹ™erušenĂ od ÄŤasovaÄŤĹŻ sloužà registr TIMSK. +NastavenĂm nÄ›kterĂ˝ch bitĹŻ v registru TIMSK na "1" lze povolit pĹ™erušenĂ od +jednotlivĂ˝ch ÄŤasovaÄŤĹŻ: +*/ +/* +bit TIMSK: ÄŤasovaÄŤ: vektor: + 0 ÄŤasovaÄŤ 0 ISR(TIMER0_OVF_vect) + 2 ÄŤasovaÄŤ 1 ISR(TIMER1_OVF_vect) + 6 ÄŤasovaÄŤ 2 ISR(TIMER2_OVF_vect) + +Nakonec je ještÄ› potĹ™eba nastavit 7\. bit registru SREG. Tento bit sloužà ke globálnĂmu +povolenĂ nebo zakázánĂ všech pĹ™erušenĂ najednou. +*/ +/* +Vektor je mĂsto, kam program pĹ™eskoÄŤĂ, kdyĹľ je aktivováno pĹ™erušenĂ. Zápis je +následujĂcĂ: + +ISR(TIMER0_OVF_vect) + { + pĹ™Ăkazy obsluhy pĹ™erušenĂ; + } + +Po provedenĂ pĹ™ĂkazĹŻ obsluhy pĹ™erušenĂ se program vrátĂ zpÄ›t na mĂsto, odkud byl +pĹ™erušen, a pokraÄŤuje v normálnĂ ÄŤinnosti. +*/ +/* +NynĂ bychom se tedy mohli pustit do psanĂ programu, ale jak jiĹľ bylo minule patrnĂ©, +ÄŤĂm delšà program pĂšeme, tĂm je mĂ©nÄ› pĹ™ehlednĂ˝.Proto je lĂ©pe si jej rozloĹľit na +jednotlivĂ© dĂlÄŤĂ problĂ©my, a ty pak zapsat pomocĂ funkcĂ. +NapĹ™Ăklad program: +*/ +/* +... +PORTB = 0xff; //nastav všechny bity portu "B" na "1" +waitms(5); //poÄŤkej 5 milisekund + +PORTD = 0b00000001; //nastav nultĂ˝ bit portu "D" na "1" +waitms(2); //poÄŤkej 2 milisekundy +PORTD = 0b00000010; //nastav prvnĂ bit portu "D" na "1" + +PORTB = 0x00; //nastav všechny bity portu "B" na "0" +waitms(5); //poÄŤkej 5 milisekund +... +*/ +/* +Tento program by šel pĹ™epsat jednodušeji a pĹ™ehlednÄ›ji takto: +*/ +/* +... +zapni_portb(); //nastav všechny bity portu "B" na "1" a poÄŤkej 5 milisekund +prepni_portd(); //pĹ™epni prvnĂ a druhĂ˝ bit portu "D" s prodlevou 2 milisekundy +vypni_portb(); //nastav všechny bity portu "B" na "0" a poÄŤkej 5 milisekund +... +*/ +/* +Program je nynĂ jednoduššĂ. Ĺada pĹ™ĂkazĹŻ byla nahrazena jednoduchĂ˝mi funkcemi. +Aby však program mohl fungovat, musĂme tyto funkce nadefinovat. Definice funkce +se provádĂ tak, Ĺľe napĂšeme hlaviÄŤku funkce (jmĂ©no funkce a typy hodnot, kterĂ© +funkce pĹ™ijĂmá, popĹ™ĂpadÄ› vracĂ. Definice funkce vypadá takto: + +typ_navratove_hodnoty nazev_funkce (definice promÄ›nnĂ˝ch, kterĂ© funkce pĹ™ijĂmá) +{ +tÄ›lo funkce +} + +ProtoĹľe nynĂ pro náš pĹ™Ăklad nepotĹ™ebujeme pĹ™edávat žádnĂ© parametry, napĂšeme mĂsto +návratovĂ© hodnoty a pĹ™ijĂmanĂ˝ch hodnot slovo "void". +Definice našich novĂ˝ch funkcĂ je tedy následujĂcĂ: +*/ +/* +void zapni_portb(void) //hlaviÄŤka funkce "zapni_portb" + { //začátek tÄ›la funkce + PORTB = 0xff; //nastav všechny bity portu "B" na "1" + waitms(5); //poÄŤkej 5 milisekund + } //konec tÄ›la funkce +*/ +/* +NynĂ máme nadefinovanou funkci "zapni_portb". Pokud tedy v hlavnĂm programu +napĂšeme: + +zapni_portb(); + +//spustĂ se tato funkce, a provede pĹ™Ăkazy ve svĂ©m tÄ›le: + +PORTB = 0xff; //nastav všechny bity portu "B" na "1" +waitms(5); //poÄŤkej 5 milisekund + +//po provedenĂ tÄ›chto pĹ™ĂkazĹŻ se program vrátĂ zpÄ›t a pokraÄŤuje dalšĂm pĹ™Ăkazem, +//tedy: + +prepni_portd() + +//Tuto funkci zatĂm ale nemáme definovanou. JejĂ definice by vypadala takto: +*/ +/* +void prepni_portd(void) //hlaviÄŤka + { + PORTD = 0b00000001; //nastav nultĂ˝ bit portu "D" na "1" + waitms(2); //poÄŤkej 2 milisekundy + PORTD = 0b00000010; //nastav prvnĂ bit portu "D" na "1" + } +*/ +/* +PodobnĂ˝m zpĹŻsobem by se nadefinovala i funkce "vypni_portb". Tento program by se +pak choval stejnÄ›, jako pĹŻvodnĂ program bez funkcĂ. +*/ +/* +NynĂ se podĂváme na to, jak by se zapisovala funkce, která pĹ™ebĂrá a pĹ™edává +parametry: +MÄ›jme promÄ›nnĂ© "cislo1", "cislo2" a "vysledek": + +unsigned char cislo1, cislo2, vysledek; + +NynĂ si pĹ™edstavme, Ĺľe v programu budeme potĹ™ebovat vykonat tuto operaci: + +vysledek = (cislo1 + cislo2) * cislo1; //do promÄ›nnĂ© "vysledek" se uložà souÄŤet + //promÄ›nnĂ˝ch "cislo1" a "cislo2" vynásobenĂ˝ + //promÄ›nnou "cislo1" + +Tuto operaci mĹŻĹľeme nahradit funkcĂ: + +vysledek = funkce_vypocet(); + +ProtoĹľe však potĹ™ebujeme, aby tato funkce poÄŤĂtala s nÄ›jakĂ˝mi promÄ›nnĂ˝mi ("cislo1" +a "cislo2") musĂme jĂ tyto promÄ›nnĂ© pĹ™edat jako parametry: + +vysledek = funkce_vypocet(cislo1, cislo2); + +Tento pĹ™Ăkaz by se nynĂ vykonal následovnÄ›: +Program zjistĂ, Ĺľe má nÄ›co pĹ™iĹ™adit do promÄ›nnĂ© "vysledek" jde tedy do prava, a +narazĂ na funkci s parametry. Zapamatuje si tedy tyto 2 parametry ("cislo1", "cislo2") +a pĹ™eskoÄŤĂ do funkce "funkce_vypocet()". TĂ©to funkci pĹ™edá oba parametry a funkci +vykoná. Na konci funkce obdržà jedno ÄŤĂslo (návratovou hodnotu). Tuto hodnotu si +zapamatuje, a skoÄŤĂ zpátky k našemu pĹ™Ăkazu: + +vysledek = funkce_vypocet(cislo1, cislo2); + +NynĂ jiĹľ má ale funkci vypoÄŤtenou, a má v pamÄ›ti uloĹľenou jejĂ návratovou hodnotu. +NahradĂ tedy pĹŻvodnĂ zápis: "funkce_vypocet(cislo1, cislo2)" pouze návratovou +hodnotou a vznikne: + +vysledek = navratova_hodnota; + +Tento pĹ™Ăkaz pak vyĹ™ešà jako prostĂ© pĹ™iĹ™azenĂ - zapĂše do promÄ›nnĂ© "vysledek" +návratovou hodnotu funkce. +TakĹľe pĹ™Ăkaz: + +vysledek = funkce_vypocet(cislo1, cislo2); + +se vykoná stejnÄ› jako pĹ™Ăkaz: + +vysledek = (cislo1 + cislo2) * cislo1; +*/ +/* +NynĂ si ale musĂme našà funkci ještÄ› nadefinovat: +NapĂšeme zase hlaviÄŤku funkce, a blok pĹ™ĂkazĹŻ do tÄ›la funkce: + +char funkce_vypocet(char vstup1, char vstup2); + { + char vystup; //nadefinujeme si vĂ˝stupnĂ promÄ›nnou (sem budeme ukládat vĂ˝sledek) + + vystup = (vstup1 + vstup2) * vstup1; //do promÄ›nnĂ© "vystup" vypoÄŤteme operaci + + return vystup; //a Ĺ™ekneme, Ĺľe se má jako návratová hodnota pouĹľĂt hodnota + //promÄ›nnĂ© "vystup" + } +*/ +/* +NynĂ si rozebereme hlaviÄŤku funkce: +Slovo "char" pĹ™ed názvem funkce Ĺ™Ăká, jakĂ©ho typu bude návratová hodnota (kolik +mĂsta zabere v pamÄ›ti - char = 8 bitĹŻ) Pak následuje název funkce "funkce_vypocet" +(to je název, pomocĂ kterĂ©ho funkci voláme v programu). Za názvem následujĂ v +závorkách parametry funkce. +Zápis: + +char funkce_vypocet(char vstup1, char vstup2); + +Ĺ™Ăká, Ĺľe funkce oÄŤekává 2 parametry typu char a vracĂ ÄŤĂslo typu char. +TÄ›lo funkce je vytvoĹ™eno stejnÄ›, jako tomu bylo v minulĂ˝ch pĹ™Ăpadech. Jedinou novinkou +je pĹ™Ăkaz "return", za kterĂ˝ se napĂše, co má funkce vrátit. Tento pĹ™Ăkaz zároveĹ +funkci ukonÄŤuje. +*/ +/* +NynĂ uĹľ tedy vĂme, jak pouĹľĂvat ÄŤasovaÄŤ a jak rozepsat program do jednotlivĂ˝ch funkcĂ. +JeštÄ› by se hodila jedna poznámka, a to Ĺľe kaĹľdá funkce musĂ bĂ˝t pĹ™ed svĂ˝m pouĹľitĂm +definovaná. V opaÄŤnĂ©m pĹ™ĂpadÄ› hlásĂ pĹ™ekladaÄŤ chybu, Ĺľe tuto funkci nezná. ProzatĂm +to tedy vyĹ™ešĂme tak, Ĺľe všechny funkce budeme definovat ještÄ› pĹ™ed hlavnĂ funkcĂ +("main"). Funkce main (ve kterĂ© budeme naše nadefinovanĂ© funkce pouĹľĂvat) bude tedy +nadefinovaná aĹľ jako poslednĂ (na konci zdrojovĂ©ho kĂłdu). +*/ +/* +MĹŻĹľeme se tedy pustit do psanĂ programu. Náš program by mÄ›l umÄ›t blikat ledkami v +rĹŻznĂ˝ch reĹľimech a rychlostech. ReĹľimy blikánĂ by mohly bĂ˝t: +- jednoduchĂ© blikánĂ (svĂtĂ nesvĂtĂ) +- stroboskopickĂ© blikánĂ (rozsvĂcenĂ ledek na velmi krátkou dobu) +- maják (ledky dvakrát rychle po sobÄ› krátce bliknou) +- běžĂcĂ svÄ›tlo (nÄ›co podobnĂ©ho, jako mÄ›l KIT - svÄ›tlo bÄ›há zleva + doprava a zprava doleva) +- had (náš starĂ˝ známĂ˝) + +Program by se mÄ›l ovládat pomocĂ 2 tlaÄŤĂtek (PD2 a PD3), pĹ™iÄŤemĹľ jednĂm tlaÄŤĂtkem by +se mÄ›nil reĹľim blikánĂ, a druhĂ˝m rychlost. +Program by mÄ›l fungovat tak, jednotlivĂ© reĹľimy blikánĂ budou uloĹľeny jako samostatnĂ© +funkce. HlavhĂ smyÄŤka pak zjistĂ, jakĂ˝ reĹľim blikánĂ je vybrán, a podle toho spustĂ +poĹľadovanou funkci. Funkce pak provede jeden krok (posunutĂ hada, bliknutĂ, atd.) +a skonÄŤĂ. ÄŚekánĂ mezi jednotlivĂ˝mi kroky bude zajišťovat hlavnĂ smyÄŤka. +MezitĂm se bude pomocĂ ÄŤasovaÄŤe0 provádÄ›t testovánĂ klávesnice, a pĹ™ĂpadnĂ© nastavovánĂ +promÄ›nnĂ˝ch "rychlost" a "rezim". +*/ +//Náš program by tedy mohl vypadat takto: + +#define F_CPU 1000000UL // 1 MHz (základnĂ frekvence) kvĹŻli delay.h + +#include <avr/io.h> //Knihovna vstupĹŻ a vĂ˝stupĹŻ (PORT, DDR, PIN) +#include <util/delay.h> //Knihovna ÄŤekacĂch funkcĂ +#include <avr/interrupt.h> //Knihovna pĹ™erušenĂ (kvĹŻli vektoru ISR(TIMER0_OVF_vect)) + +#define RYCHLOST_MIN 2 //MinimálnĂ poÄŤet krokĹŻ (bliknutĂ) za sekundu +#define RYCHLOST_MAX 100 //MaximálnĂ poÄŤet krokĹŻ (bliknutĂ) za sekundu + +#define POCET_REZIMU 15 //poÄŤet reĹľimĹŻ (reĹľimĹŻ je 5, zbylĂ© reĹľimy sloužà k + //prodluĹľovánĂ hada) + +#define BLIKANI 0b00010111 //urÄŤuje, kterĂ© ledky se majĂ stĹ™Ădat pĹ™i reĹľimu + //jednoduchĂ©ho blikánĂ + +#define STROBO_CAS 10 //(ms) - UrÄŤuje, kolik milisekund budou svĂtit ledky pĹ™i + //strobo efektu. VyuĹľĂvá se i v reĹľimu "maják". + +#define MAJAK 50 //definuje, kolik milisekund je mezi dvojicĂ bliknutĂ ve funkci + //maják + +//VytvoĹ™Ăme si tzv. globálnĂ promÄ›nnĂ© (jsou deklarovanĂ© mimo všechny funkce, +//dĂky ÄŤemuĹľ jsou ve všech funkcĂch "viditelnĂ©" +//Běžná promÄ›nná totiĹľ platĂ jen mezi sloĹľenĂ˝mi závorkami {}, mezi kterĂ˝mi byla +//vytvoĹ™ena (to znamená pouze uvnitĹ™ funkce). + +unsigned char rychlost; //globálnĂ promÄ›nná - rychlost blikánĂ +unsigned char rezim; //globálnĂ promÄ›nná - reĹľim blikánĂ +unsigned char zmena; //globálnĂ promÄ›nná - Sem budeme ukládat informaci, Ĺľe byl + //právÄ› zmÄ›nÄ›n reĹľim blikánĂ (nÄ›kterĂ© funkce se budou pĹ™i + //svĂ©m prvnĂm spuštÄ›nĂ potĹ™ebovat inicializovat(nastavit + //základnĂ hodnoty) +//Tyto promÄ›nnĂ© musejĂ bĂ˝t globálnĂ, protoĹľe se nastavujĂ ve vektoru pĹ™erušenĂ, +//a ÄŤtou se v hlavnĂ funkci. MusejĂ tedy bĂ˝t pĹ™ĂstupnĂ© z obou tÄ›chto mĂst. + +//nynĂ si tedy nadefinujeme jednotlivĂ©funkce, kterĂ© pak budeme v hlavnĂ funkci volat: + +/*****************************/ +/* Vektor pĹ™erušenĂ */ +/*****************************/ +ISR(TIMER0_OVF_vect) + { + static unsigned char tlacitko; //statická promÄ›nná - uchovává si hodnotu mezi + //jednotlivĂ˝mi volánĂmi funkce + //Pro nás sloužà jako informace, Ĺľe minule bylo + //stisknuto tlaÄŤĂtko (abychom pĹ™edešli nechtÄ›nĂ©mu + //pĹ™eÄŤtenĂ jednoho stisku 2x) + + TCNT0=157; //ÄŚasovaÄŤ zaÄŤne poÄŤĂtat od 157 (255-157=98) pĹ™eddÄ›liÄŤka je 1024. + //HodinovĂ˝ kmitoÄŤet procesoru je 1MHz. TakĹľe: + //1 000 000 / 1024 / 98 = 10 Hz (klávesnice se kontroluje pĹ™ibliĹľnÄ› + //10x za vteĹ™inu) + if (tlacitko) //pokud bylo minule stisknuto tlaÄŤĂtko... + { + tlacitko=0; //...tak promÄ›nnou "tlacitko" vynulujeme... + return; //...a pro jistotu ukonÄŤĂme cyklus (uĹľivatel by mohl tlaÄŤĂtko + } //stále drĹľet) + + if (!(PIND&0b00000100)) //pokud je stisknutĂ© tlaÄŤĂtko 1 (reĹľim) + { + rezim++; //zmÄ›nĂme reĹľim + zmena=1; //právÄ› jsme provedli zmÄ›nu reĹľimu + tlacitko=1; //uloĹľĂme si informaci, Ĺľe bylo stisknuto tlaÄŤĂtko + } + + if (!(PIND&0b00001000)) //pokud je stisknutĂ© tlaÄŤĂtko 2 (rychlost) + { + rychlost*=2; //pĹ™idáme rychlost (2x zrychlĂme je to totĂ©Ĺľ jako: rychlost<<1;) + tlacitko=1; //uloĹľĂme si informaci, Ĺľe bylo stisknuto tlaÄŤĂtko + } + + if (rezim>POCET_REZIMU) //pokud jsme jiĹľ pĹ™ekroÄŤili povolenĂ˝ poÄŤet reĹľimĹŻ... + { + rezim=1; //...zaÄŤneme zase od začátku (1\. reĹľim) + } + + if (rychlost>RYCHLOST_MAX) //pokud jsme jiĹľ pĹ™ekroÄŤili maximálnĂ rychlost... + { + rychlost=RYCHLOST_MIN; //...nastavĂme rychlost zpátky na minimum + } + + }//Konec vektoru pĹ™erušenĂ - program se mĹŻĹľe vrátit zpÄ›t ke svĂ© práci. + +/*****************************/ +/*funkce jednoduchĂ©ho blikánĂ*/ +/*****************************/ +void blik (void) + { + if (zmena) //pokud je funkce spuštÄ›na poprvĂ© + { + PORTB= BLIKANI; //nastav do portu "B" počáteÄŤnĂ hodnotu + zmena=0; //vynuluj promÄ›nnou "zmena" (přÚtÄ› uĹľ to nebude poprvĂ©) + } + else //pokud to nenĂ poprvĂ©... + { + PORTB=~PORTB; //do poru "B" dáme jeho bitovĂ˝ komplement - vymÄ›nĂme "0" za "1" + } + } // konec funkce "blik" + +/*****************************/ +/* funkce stroboskopu */ +/*****************************/ +void strobo (void) + { + PORTB=0xff; //rozsvĂtĂme všechny ledky... + _delay_ms(STROBO_CAS); //...poÄŤkáme malou chvilku... + PORTB=0; //...a zhasneme všechny ledky + } + +/*****************************/ +/* Maják */ +/*****************************/ +void majak (void) + { + for(char n=0;n<2;n++) //cyklus o 2 opakovánĂch: + { + PORTB=0xff; //rozsvĂtĂme všechny ledky... + _delay_ms(STROBO_CAS); //...chvilku poÄŤkáme... + PORTB=0; //...zhasneme všechny ledky... + _delay_ms(MAJAK); //...a poÄŤkáme delšà chvilku (50 ms) + } + + } //konec funkce "majak" + +/*****************************/ +/* BěžĂcĂ svÄ›tlo */ +/*****************************/ +void semtam (void) + { + static unsigned char pozice; //statická promÄ›nná - uchovává si hodnotu mezi + //jednotlivĂ˝mi volánĂmi funkce + //nám bude slouĹľit jako ukazatel, kde zrovna je ledka + //1-8 = 1.-8\. ledka. 9-15 = 6.-1\. ledka (jede zpátky) + if (zmena) //pokud je funkce volána poprvĂ© + { + PORTB=1; //zhasneme všechny ledky a rozsvĂtĂme pouze jednu (PB0)... + pozice=1; //...a nastavĂme pozici na začátek (1.ledka) + zmena=0; //vynuluj promÄ›nnou zmena (přÚtÄ› uĹľ to nebude poprvĂ©) + return; //ukonÄŤĂme funkci (1\. ledka uĹľ svĂtĂ, přÚtÄ› ji budeme posouvat + } + if (pozice<8) //pokud pozice ještÄ› nenĂ 8 (ještÄ› jsme nedošli k 8\. ledce) + { + PORTB<<=1; //posuĹ ledku o 1 doleva. + } + else //pozice je vÄ›tšà nebo rovna 8, (uĹľ jsme dojeli k levĂ©mu kraji) + { + PORTB>>=1; //posuĹ ledku o 1 doprava (jedeme zase na začátek) + } + + pozice++; //posunuli jsme ledku, tak musĂme takĂ© posunout ukazatel + if(pozice>=15) //pokud je ledka na 15\. pozici (zpátky na začátku) + { + pozice=1; //pĹ™epĂšeme ukazatel na "1" (začátek) + } + } //konec funkce "semtam" + +/*****************************/ +/* Had */ +/*****************************/ +void had (unsigned char delka) //náš starĂ˝ známĂ˝ had + { //Funkce "had" pĹ™ebĂrá parametr dĂ©lka. PĹ™i volánĂ funkce tedy + //mĹŻĹľeme (nebo spĂš musĂme) zadat dĂ©lku hada. + + static unsigned char pozice; //statická promÄ›nná - ukazatel na pozici hada + //(stejnÄ› jako u běžĂcĂho svÄ›tla) + + if (zmena) //pokud je funkce volána poprvĂ© (stejnÄ› jako u běžĂcĂho svÄ›tla) + { + PORTB=0; //zhasneme všechny ledky ... + pozice=0; //...a nastavĂme pozici na začátek (1.ledka) + zmena=0; //vynuluj promÄ›nnou "zmena" (přÚtÄ› uĹľ to nebude poprvĂ©) + } +//Dosavadnà část je vlastnÄ› stejná, jako byla pouĹľita ve funkci "BěžĂcĂ svÄ›tlo" +//NásledujĂcà část funkce "had" je vĂcemĂ©nÄ› stejná, jako v našem minulĂ©m programu. + + if (pozice<delka) //pokud jsme rozsvĂtili mĂ©nÄ› ledek neĹľ je dĂ©lka hada + { + PORTB <<=1; //pĹ™idáme ÄŤlánek hada (bity se posunou doleva a + //vpravo se doplnĂ "0" + + PORTB ++; //pĹ™iÄŤteme "1" (nastavĂme nultĂ˝ bit na "1") + } + else //pokud nenĂ poÄŤet opakovánĂ menšà neĹľ dĂ©lka hada + { //to znamená, Ĺľe hada uĹľ jsme nakreslili.. + + PORTB <<=1; //pouze posuneme bity (hada) doleva a doplnĂ se nula... + } + + pozice++; //posunuli jsme ledku, tak musĂme takĂ© posunout ukazatel + + if(pozice>(delka+8)) //pokud had dolezl na konec (poslednĂ ÄŤlánek uĹľ zmizel, + { + pozice=0; //pĹ™epĂšeme ukazatel na "0" (začátek) + } + + } //konec funkce "had" + +/************************************************/ + /*****************************/ + /** HlavnĂ funkce **/ + /*****************************/ +int main (void) +{ +DDRB = 0xff; //NastavĂme port "B" jako vĂ˝stupnĂ +TIMSK|=1; //nastavĂme nultĂ˝ bit na "1" a ostatnĂ necháme (povolĂme pĹ™erušenĂ + //od ÄŤasovaÄŤe "0") +TCCR0 = 5; //Zapneme ÄŤasovaÄŤ "0" s pĹ™eddÄ›liÄŤkou 1024. + +SREG |= (1<<7); //povolenĂ pĹ™erušenĂ (nastavĂme 7\. bit registru SREG) + +rezim=1; //nastavĂme reĹľim blikánĂ na 1\. moĹľnost (jednoduchĂ© blikánĂ) +zmena=1; //nastavĂme, jako Ĺľe jsme právÄ› zmÄ›nili reĹľim (funkce blik bude spuštÄ›na + //poprvĂ©) + +rychlost=RYCHLOST_MIN; //nastavĂme rychlost na minimum + +// nynĂ máme vše potĹ™ebnĂ© nastaveno, a mĹŻĹľeme spustit hlavnĂ smyÄŤku: + +for(;;) //hlavnĂ smyÄŤka + { //Tato smyÄŤka bude pouze zajišťovat vĂ˝bÄ›r správnĂ© funkce (podle nastavenĂ©ho + //reĹľimu blikánĂ, a ÄŤekánĂ mezi jednotlivĂ˝mi kroky. + + //VĂ˝bÄ›r správnĂ© funkce provedeme pomocĂ pĹ™Ăkazu "switch".Switch je vlastnÄ› + //nÄ›co jako vĂcenásobnĂ˝ "if" + + switch (rezim) //budeme rozhodovat podle toho, co je v promÄ›nnĂ© "rezim"... + { + case 1: //...v pĹ™ĂpadÄ› Ĺľe je to ÄŤĂslo "1"... + blik(); //...zavoláme funkci "blik()" (1\. reĹľim)... + break; //...a vyskoÄŤĂme z pĹ™Ăkazu switch (jinak by se provedly všechny + //následujĂcĂ instrukce - switch by uĹľ dalšà podmĂnky netestoval. + + case 2: //...v pĹ™ĂpadÄ› Ĺľe je to ÄŤĂslo "2"... + strobo(); //...zavoláme funkci "strobo()" (2\. reĹľim)... + break; + + case 3: //...v pĹ™ĂpadÄ› Ĺľe je to ÄŤĂslo "3"... + majak();//...zavoláme funkci "majak()" + break; + + case 4: //...v pĹ™ĂpadÄ› Ĺľe je to ÄŤĂslo "4"... + semtam();//...zavoláme funkci "semtam()" + break; + + default: //Pokud nevyhovoval ani jeden z pĹ™edchozĂch pĹ™ĂpadĹŻ - zbĂ˝vá uĹľ + //jen funkce "had" (5\. a vyššà reĹľim) + + had(rezim-4); //zavoláme funkci "had" a jako parametr jĂ pĹ™edáme ÄŤĂslo + //reĹľimu bez 4\. To znamená, Ĺľe funkce mĹŻĹľe obdrĹľet ÄŤĂslo + //jedna aĹľ nÄ›co, kterĂ© pak pouĹľije k nastavenĂ dĂ©lky hada + } //konec pĹ™Ăkazu switch + + //ĂşspěšnÄ› jsme tedy vybrali jakou funkci má program provĂ©st a nynĂ nám uĹľ zbĂ˝vá + //jen poÄŤkat poĹľadovanou dobu, neĹľ se program pustĂ do dalšĂho kroku: + + _delay_ms (1000/rychlost); //ÄŚekánĂ (1000 ms = 1 sekunda) + + } //konec hlavnĂ smyÄŤky + +} //konec funkce main + +//Pro radioklub OK1KVK naspal Vašek Král + +``` \ No newline at end of file -- GitLab