Operácie

Odpočítavacie hodiny na riadenie diskusie: Rozdiel medzi revíziami

Z SensorWiki

(Algoritmus a program)
(Analýza)
 
(18 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 32: Riadok 32:
 
== Analýza ==
 
== Analýza ==
  
7-segmentový displej bude riadený procesorom ATMEL ATMEGA 328P, ktorý je súčasťou vývojovej dosky ARDUINO DUEMILANOVE. Táto doska má 14 digitálnych vstupno/výstupných pínov, z ktorých môžem šesť použiť ako PWM výstupy, šesť analógových vstupov a 16 MHz kryštál. Pre pripojenie je možné využiť napájací konektor a USB pripojenie.
+
7-segmentový displej bude riadený procesorom ATMEL ATMEGA 328P, ktorý je súčasťou vývojovej dosky ARDUINO DUEMILANOVE. Táto doska má 14 digitálnych vstupno/výstupných pinov, z ktorých môžem šesť použiť ako PWM výstupy, šesť analógových vstupov a 16 MHz kryštál. Všetky vstupy/výstupy sú zreteľne označené na doske. Pre pripojenie je možné využiť napájací konektor a USB pripojenie.
K tejto doske je pripojená vývojová doska so 7-segmentovým displejom podľa uvedenej schémy zapojenia uvedenej v ''Popise riešenia''.  
+
K tejto doske je pripojená vývojová doska so 7-segmentovým displejom podľa schémy zapojenia uvedenej v ''Popise riešenia''.  
  
 
Ostatné informácie o vývojovej doske ARDUINO DUEMILANOVE sú podrobne vypísané na nasledujúcej adrese http://arduino.cc/en/Main/arduinoBoardDuemilanove.
 
Ostatné informácie o vývojovej doske ARDUINO DUEMILANOVE sú podrobne vypísané na nasledujúcej adrese http://arduino.cc/en/Main/arduinoBoardDuemilanove.
Riadok 42: Riadok 42:
 
             '''''Vývojová doska ARDUINO DUEMILANOVE'''''
 
             '''''Vývojová doska ARDUINO DUEMILANOVE'''''
  
[[Súbor:Duemilanove.jpg|400px|thumb|center|Vývojová doska ARDUINO DUEMILANOVE.]]
+
[[Súbor:Duemilanove.jpg|300px|thumb|center|Vývojová doska ARDUINO DUEMILANOVE.]]
  
  
Riadok 75: Riadok 75:
  
  
Vyberte podstatné časti zdrojového kódu, použite na to prostredie ''source'':
+
Zdrojový kód pre našu aplikáciu vyzerá nasledovne:
  
 
<source lang="c">
 
<source lang="c">
/* A nezabudnite zdroják hojne komentovať  */
+
#define F_CPU 16000000UL //Takt procesora 16MHz
 
 
#define F_CPU 16000000UL //Takt procesora 16MHz
 
 
#include <util/delay.h>
 
#include <util/delay.h>
 
#include <avr/io.h>
 
#include <avr/io.h>
Riadok 126: Riadok 124:
 
#define SEG_DIGIT_A4 0
 
#define SEG_DIGIT_A4 0
  
#define SEG_INIT() bits_set(DDR(SEG_PORT),(bit(SEG_a)|bit(SEG_b)|bit(SEG_c)|bit(SEG_d)|bit(SEG_e)|bit(SEG_f)|bit(SEG_g)|bit(SEG_dp)));bits_set(DDR(SEG_DIGIT_PORT),(bit(SEG_DIGIT_A1)|bit(SEG_DIGIT_A2)|bit(SEG_DIGIT_A3)|bit(SEG_DIGIT_A4)))
+
#define SEG_INIT() bits_set(DDR(SEG_PORT),(bit(SEG_a)|bit(SEG_b)|bit(SEG_c)|bit(SEG_d)|bit(SEG_e)|bit(SEG_f)|bit(SEG_g)|bit(SEG_dp)));bits_set(DDR(SEG_DIGIT_PORT),
 +
(bit(SEG_DIGIT_A1)|bit(SEG_DIGIT_A2)|bit(SEG_DIGIT_A3)|bit(SEG_DIGIT_A4)))
  
 
//Bzuciak
 
//Bzuciak
Riadok 142: Riadok 141:
 
//Premenne su typu volatile, co znamena ze ich kompilator skompiluje a hodnoty sa v obsluhach preruseni budu spravne spracovavat
 
//Premenne su typu volatile, co znamena ze ich kompilator skompiluje a hodnoty sa v obsluhach preruseni budu spravne spracovavat
 
volatile int8_t sec_jed,sec_des,min_jed,min_des; //znamienkove 8 bitove premenne obsahujuce hodnoty casomiery
 
volatile int8_t sec_jed,sec_des,min_jed,min_des; //znamienkove 8 bitove premenne obsahujuce hodnoty casomiery
volatile uint16_t delay,dlho; //neznamienkove 16 bitove premenne  
+
volatile uint16_t delay,dlho; //neznamienkove 16 bitove premenne  
volatile uint8_t kratko; //neznamienkova 8bitova premenna pre funkciu tlacidla
+
volatile uint8_t kratko; //neznamienkova 8bitova premenna pre funkciu tlacidla
  
 
//Fukncia zobrazujuca cisla ja zvolenom mieste(sekundy, minuty..)
 
//Fukncia zobrazujuca cisla ja zvolenom mieste(sekundy, minuty..)
Riadok 177: Riadok 176:
 
// break;
 
// break;
 
}
 
}
SEG_DIGIT_PORT &= ~(1<<segment); //Zapne aktualny segment
+
SEG_DIGIT_PORT &= ~(1<<segment); //Zapne aktualny segment
 
 
 
//zvysenie svietivosti pomocou predlzenia doby aktivneho segmentu
 
//zvysenie svietivosti pomocou predlzenia doby aktivneho segmentu
 
for (uint8_t i=0;i<100;i++)
 
for (uint8_t i=0;i<100;i++)
 
{
 
{
segment++; //Pouzitie lokalnej premennej pre vytvorenie pauzy
+
segment++; //Pouzitie lokalnej premennej pre vytvorenie pauzy
 
}
 
}
 
 
Riadok 193: Riadok 192:
 
 
 
bit_set(BUZ_PORT,BUZ_PIN); //Zapnutie bzuciaka
 
bit_set(BUZ_PORT,BUZ_PIN); //Zapnutie bzuciaka
while(delay<dlzka); //Pauza
+
while(delay<dlzka);         //Pauza
bit_clear(BUZ_PORT,BUZ_PIN); //Vypnutie bzuciaka
+
bit_clear(BUZ_PORT,BUZ_PIN);         //Vypnutie bzuciaka
 
}
 
}
  
Riadok 200: Riadok 199:
 
void cas(void)
 
void cas(void)
 
{
 
{
cisla_segment(SEG_DIGIT_A2,10); //Zobrazenie bodky medzi minutami a sekundami
+
cisla_segment(SEG_DIGIT_A2,10); //Zobrazenie bodky medzi minutami a sekundami
 
cisla_segment(SEG_DIGIT_A4,sec_jed); //Jednotky sekund
 
cisla_segment(SEG_DIGIT_A4,sec_jed); //Jednotky sekund
 
cisla_segment(SEG_DIGIT_A3,sec_des); //Desiatky sekund
 
cisla_segment(SEG_DIGIT_A3,sec_des); //Desiatky sekund
Riadok 206: Riadok 205:
 
cisla_segment(SEG_DIGIT_A1,min_des); //Desiatky minut
 
cisla_segment(SEG_DIGIT_A1,min_des); //Desiatky minut
 
 
if(TCCR1B) //Ak casomiera bezi, testuju sa nasledovne podmienky
+
if(TCCR1B)                         //Ak casomiera bezi, testuju sa nasledovne podmienky
 
{
 
{
 
if (min_des == 0 && min_jed == 0 && sec_des > 0 && sec_jed > 0  ) //Ak je aktualny cas mensi ako minuta cislice budu blikat
 
if (min_des == 0 && min_jed == 0 && sec_des > 0 && sec_jed > 0  ) //Ak je aktualny cas mensi ako minuta cislice budu blikat
 
{
 
{
if (TCNT1<10000) //Tato podmienka zaruci aby sa bliknutie vykonalo iba raz za sekundu
+
if (TCNT1<10000) //Tato podmienka zaruci aby sa bliknutie vykonalo iba raz za sekundu
 
{
 
{
bit_set(SEG_DIGIT_PORT,SEG_DIGIT_A1); //Vypnutie prveho znaku postacuje kedze je to multiplexovana segmentovka
+
bit_set(SEG_DIGIT_PORT,SEG_DIGIT_A1); //Vypnutie prveho znaku postacuje kedze je to multiplexovana segmentovka
 
_delay_ms(20);
 
_delay_ms(20);
 
}
 
}
Riadok 219: Riadok 218:
 
if (min_des == 0 && min_jed == 0 && sec_des == 0 && sec_jed > 0  ) //Pri poslednych 10 sekundach cislice blikaju
 
if (min_des == 0 && min_jed == 0 && sec_des == 0 && sec_jed > 0  ) //Pri poslednych 10 sekundach cislice blikaju
 
{
 
{
if (TCNT1<5000) //Rychlejsie prebliknutie pri poslednych 10 sekundach
+
if (TCNT1<5000) //Rychlejsie prebliknutie pri poslednych 10 sekundach
 
{
 
{
bit_set(SEG_DIGIT_PORT,SEG_DIGIT_A1); //Vypnutie prveho znaku
+
bit_set(SEG_DIGIT_PORT,SEG_DIGIT_A1); //Vypnutie prveho znaku
 
_delay_ms(10);
 
_delay_ms(10);
 
}
 
}
Riadok 235: Riadok 234:
 
uint8_t akt_stav=0;
 
uint8_t akt_stav=0;
 
 
for(uint8_t i=0;i<5;i++) //Odstranenie zakmitov
+
for(uint8_t i=0;i<5;i++) //Odstranenie zakmitov
 
{
 
{
 
akt_stav = !bit_get(PIN(PB_PORT),PB_PIN); //Citanie logickeho stavu na pine tlacidla, pricom hodnota sa neguje
 
akt_stav = !bit_get(PIN(PB_PORT),PB_PIN); //Citanie logickeho stavu na pine tlacidla, pricom hodnota sa neguje
 
}
 
}
 
 
if (akt_stav) //Ak je tlacidlo stlacene inkrementuju sa premenne pre indikaciu dlheho a kratkeho stlacenia
+
if (akt_stav) //Ak je tlacidlo stlacene inkrementuju sa premenne pre indikaciu dlheho a kratkeho stlacenia
 
{
 
{
kratko++; //8bit premenna = hodnoty 0-255
+
kratko++; //8bit premenna = hodnoty 0-255
dlho++; //16bit premenna = hodnoty 0-65535
+
dlho++; //16bit premenna = hodnoty 0-65535
 
}
 
}
else dlho=0; //ak sa tlacidlo pustilo premenna indikujuca dlhe stlacenie sa vynuluje
+
else dlho=0; //ak sa tlacidlo pustilo premenna indikujuca dlhe stlacenie sa vynuluje
 
 
return akt_stav; //Vratenie vysledneho stavu tlacidla(stlacene/nestlacene)
+
return akt_stav; //Vratenie vysledneho stavu tlacidla(stlacene/nestlacene)
 
}
 
}
  
Riadok 254: Riadok 253:
 
{
 
{
 
sec_jed=0,sec_des=0,min_jed=0,min_des=1; //Globalne premenne obsahujuce hodnoty prednastavenej casomiery
 
sec_jed=0,sec_des=0,min_jed=0,min_des=1; //Globalne premenne obsahujuce hodnoty prednastavenej casomiery
ZOBRAZENIE_START(); //Spustenie casovaca pre zobrazenie znakov na segmentovke
+
ZOBRAZENIE_START(); //Spustenie casovaca pre zobrazenie znakov na segmentovke
CASOVAC_STOP(); //Pripadne zastavenie pocitadla sekund
+
CASOVAC_STOP(); //Pripadne zastavenie pocitadla sekund
 
 
 
//Cyklus na inkrementaciu a dekrementaciu casomiery po sekundach
 
//Cyklus na inkrementaciu a dekrementaciu casomiery po sekundach
Riadok 263: Riadok 262:
 
  do  
 
  do  
 
{
 
{
if (tlacidlo()&& !kratko) //V pripade ze je tlacidlo stlacene kratko (je stlacene a hodnota kratko pretecie raz => 0) casomiera sa inkrementuje o jednu sekundu
+
if (tlacidlo()&& !kratko)                       //V pripade ze je tlacidlo stlacene kratko (je stlacene a hodnota kratko pretecie  
 +
                                                                          raz => 0) casomiera sa inkrementuje o jednu sekundu
 
{
 
{
 
sec_jed++;
 
sec_jed++;
 
}
 
}
 
 
if (sec_jed>9) //Ak je viac ako 9 sekund,
+
if (sec_jed>9) //Ak je viac ako 9 sekund,
 
{
 
{
sec_jed=0; //Jednotky sekund sa vynuluju a
+
sec_jed=0; //Jednotky sekund sa vynuluju a
sec_des++; //Desiatky sekund sa inkrementuju o jedno
+
sec_des++; //Desiatky sekund sa inkrementuju o jedno
 
}
 
}
if (sec_des>5) //Ak je viac ako 59 sekund,
+
if (sec_des>5) //Ak je viac ako 59 sekund,
 
{
 
{
sec_des=0; //Desiatky sekund sa vynuluju a
+
sec_des=0; //Desiatky sekund sa vynuluju a
min_jed++; //Jednotky minut sa inkrementuju o jedno
+
min_jed++; //Jednotky minut sa inkrementuju o jedno
 
}
 
}
if (min_jed>9) //Ak je viac ako 9 minut,
+
if (min_jed>9) //Ak je viac ako 9 minut,
 
{
 
{
min_jed=0; //Jednotky minut sa vynuluju a
+
min_jed=0; //Jednotky minut sa vynuluju a
if (min_des<6) //V pripade ze je pocet desiatok minut mensi ako 6,
+
if (min_des<6) //V pripade ze je pocet desiatok minut mensi ako 6,
 
{
 
{
min_des++; //sa desiatky minut inkrementuju o jedno
+
min_des++; //Desiatky minut inkrementuju o jedno
 
}
 
}
else min_des=0; //Inak sa desiatky nuluju
+
else min_des=0; //Inak sa desiatky nuluju
 
}
 
}
 
} while (!(tlacidlo()&& dlho>2000)); //V pripad stlacenia tlacidla dlhsie ako 2s sa ukoncuje cyklus inkrementacie  
 
} while (!(tlacidlo()&& dlho>2000)); //V pripad stlacenia tlacidla dlhsie ako 2s sa ukoncuje cyklus inkrementacie  
dlho=0; //hodnota sa nuluje v pripade, ze je tlacidlo stlacene dlhsie ako 2s aby nedoslo k nechcenemu ukonceniu cykla
+
dlho=0; //hodnota sa nuluje v pripade, ze je tlacidlo stlacene dlhsie ako 2s aby nedoslo  
bzuciak(100); //Pre uzivatela sa vysle kratky signal bzuciakom potvrdenie ukoncenia cyklu
+
                                                                        k nechcenemu ukonceniu cyklu
 +
bzuciak(100);         //Pre uzivatela sa vysle kratky signal bzuciakom potvrdenie ukoncenia cyklu
 
 
 
//Cyklus dekrementacie casomiery po sekundach
 
//Cyklus dekrementacie casomiery po sekundach
 
do  
 
do  
 
{
 
{
if (tlacidlo()&& !kratko) //V pripade ze je tlacidlo stlacene kratko (je stlacene a hodnota kratko pretecie raz => 0)
+
if (tlacidlo()&& !kratko)         //V pripade ze je tlacidlo stlacene kratko (je stlacene a hodnota kratko pretecie raz => 0)
 
{
 
{
sec_jed--; //casomiera sa dekrementuje o jednu sekundu
+
sec_jed--; //casomiera sa dekrementuje o jednu sekundu
 
}
 
}
 
 
if (sec_jed < 0) //Ak je jednotiek sekund menej ako nula
+
if (sec_jed < 0) //Ak je jednotiek sekund menej ako nula
 
{
 
{
sec_des--; //Tak sa desiatky sekund dekrementuju
+
sec_des--; //Tak sa desiatky sekund dekrementuju
sec_jed = 9; //Pricom sa jednotky nastavia na 9
+
sec_jed = 9; //Pricom sa jednotky nastavia na 9
if (sec_des < 0) //Ak je desiatok sekund menej ako nula nastavia sa na hodnotu 5
+
if (sec_des < 0) //Ak je desiatok sekund menej ako nula nastavia sa na hodnotu 5
 
{
 
{
 
sec_des = 5;
 
sec_des = 5;
min_jed--; //Pricom sa jednotky minut dekrementuju o jedno
+
min_jed--; //Pricom sa jednotky minut dekrementuju o jedno
if (min_jed<0) //V pripade ze su jednotky minut mensie ako nula,
+
if (min_jed<0) //V pripade ze su jednotky minut mensie ako nula,
 
{
 
{
min_jed=9; //nastavia sa jednotky minut na hodnotu 9 a desiatky sa dekrementuju o jedno
+
min_jed=9; //nastavia sa jednotky minut na hodnotu 9 a desiatky sa dekrementuju o jedno
 
min_des--;
 
min_des--;
if(min_des<0) //Ak su desiatky minut mensie ako je zostavaju na nule
+
if(min_des<0) //Ak su desiatky minut mensie ako je zostavaju na nule
 
{
 
{
 
min_des=0;
 
min_des=0;
Riadok 319: Riadok 320:
 
}
 
}
 
} while (!(tlacidlo()&& dlho>2000)); //Pre ukoncenie cyklu dekrementacie je potrebne tlacidlo drzat dlhsie ako 2s
 
} while (!(tlacidlo()&& dlho>2000)); //Pre ukoncenie cyklu dekrementacie je potrebne tlacidlo drzat dlhsie ako 2s
bzuciak(100); //Kratkym tonom je uzivatel oboznameny s ukoncenym cyklu dekrementacie
+
bzuciak(100); //Kratkym tonom je uzivatel oboznameny s ukoncenym cyklu dekrementacie
 
} while (!(tlacidlo()&& dlho>2000)); //Neustalym drzanim tlacidla sa dostavame von z cykla inkrementacie a dekrementacie
 
} while (!(tlacidlo()&& dlho>2000)); //Neustalym drzanim tlacidla sa dostavame von z cykla inkrementacie a dekrementacie
 
 
bzuciak(300); //Dlhym tonom je oznamene ukoncenie cykla a start casomiery
+
bzuciak(300); //Dlhym tonom je oznamene ukoncenie cykla a start casomiery
CASOVAC_START(); //Start casovaca s periodou 1s
+
CASOVAC_START(); //Start casovaca s periodou 1s
 
}
 
}
  
Riadok 329: Riadok 330:
 
{
 
{
 
//Inicializacne makra
 
//Inicializacne makra
UART_DISABLE(); //Vypnutie alternativnej funkcie pinov(UARTu=RX,TX) PD0 a PD1
+
UART_DISABLE(); //Vypnutie alternativnej funkcie pinov(UARTu=RX,TX) PD0 a PD1
SEG_INIT(); //Nastavenie vystupov multiplexovanej 7 segmentovky
+
SEG_INIT(); //Nastavenie vystupov multiplexovanej 7 segmentovky
BUZ_INIT(); //Nastavenie vystupu bzuciaka
+
BUZ_INIT(); //Nastavenie vystupu bzuciaka
PB_INIT(); //Nastavenie vstupu tlacidla
+
PB_INIT(); //Nastavenie vstupu tlacidla
 
 
 
//Nastavenie masiek preruseni pre pouzite casovace
 
//Nastavenie masiek preruseni pre pouzite casovace
Riadok 349: Riadok 350:
 
nastavenie_casu();
 
nastavenie_casu();
 
      
 
      
while(1) //Nekonecna slucka
+
while(1)         //Nekonecna slucka
 
     {
 
     {
 
if (sec_des == 0 && sec_jed == 0 && min_des == 0 && min_jed == 5) //Pri 5. minute sa spusti kratky ton bzuciaka
 
if (sec_des == 0 && sec_jed == 0 && min_des == 0 && min_jed == 5) //Pri 5. minute sa spusti kratky ton bzuciaka
Riadok 363: Riadok 364:
 
if (sec_des == 0 && sec_jed == 0 && min_des == 0 && min_jed == 0) //Ked sa odpocet skonci,
 
if (sec_des == 0 && sec_jed == 0 && min_des == 0 && min_jed == 0) //Ked sa odpocet skonci,
 
{
 
{
bit_set(SEG_DIGIT_PORT,SEG_DIGIT_A1); //Segmentovka sa vypne
+
bit_set(SEG_DIGIT_PORT,SEG_DIGIT_A1); //Segmentovka sa vypne
 
ZOBRAZENIE_STOP();
 
ZOBRAZENIE_STOP();
bzuciak(5000); //Bzuciak vydava dlhy ton
+
bzuciak(5000); //Bzuciak vydava dlhy ton
CASOVAC_STOP(); //Casovac sekund sa vypne
+
CASOVAC_STOP(); //Casovac sekund sa vypne
nastavenie_casu(); //Proces nastavovania casomiery zacina odznova
+
nastavenie_casu(); //Proces nastavovania casomiery zacina odznova
 
}
 
}
else if (sec_jed < 0) //Ak je jednotiek sekund menej ako nula
+
else if (sec_jed < 0) //Ak je jednotiek sekund menej ako nula
 
{
 
{
sec_des--; //Tak sa desiatky sekund dekrementuju
+
sec_des--; //Tak sa desiatky sekund dekrementuju
sec_jed = 9; //Pricom sa jednotky nastavia na 9
+
sec_jed = 9; //Pricom sa jednotky nastavia na 9
if (sec_des < 0) //Ak je desiatok sekund menej ako nula nastavia sa na hodnotu 5
+
if (sec_des < 0)         //Ak je desiatok sekund menej ako nula nastavia sa na hodnotu 5
 
{
 
{
 
sec_des = 5;
 
sec_des = 5;
min_jed--; //Pricom sa jednotky minut dekrementuju o jedno
+
min_jed--; //Pricom sa jednotky minut dekrementuju o jedno
if (min_jed<0) //V pripade ze su jednotky minut mensie ako nula,
+
if (min_jed<0) //V pripade ze su jednotky minut mensie ako nula,
 
{
 
{
min_jed=9; //nastavia sa jednotky minut na hodnotu 9 a desiatky sa dekrementuju o jedno
+
min_jed=9; //nastavia sa jednotky minut na hodnotu 9 a desiatky sa dekrementuju o jedno
 
min_des--;
 
min_des--;
if(min_des<0) min_des=0; //Ak su desiatky minut mensie ako je zostavaju na nule
+
if(min_des<0) min_des=0; //Ak su desiatky minut mensie ako je zostavaju na nule
 
}
 
}
 
}
 
}
Riadok 392: Riadok 393:
 
ISR(TIMER0_OVF_vect)
 
ISR(TIMER0_OVF_vect)
 
{
 
{
TCNT0+=55; //perioda 100us
+
TCNT0+=55; //perioda 100us
 
cas();
 
cas();
 
}
 
}
Riadok 402: Riadok 403:
 
ISR(TIMER2_OVF_vect)
 
ISR(TIMER2_OVF_vect)
 
{
 
{
TCNT2+=5; //perioda 500us  
+
TCNT2+=5; //perioda 500us  
 
delay++;
 
delay++;
 
}
 
}
 
</source>
 
</source>
  
Nezabudnite však nahrať aj kompletné zdrojové kódy vášho programu!
+
=== Overenie ===
 +
 
 +
Po pripojení odpočítavacích hodín k zdroju napájania prostredníctvom USB alebo konektora "JACK" sa na displeji rozsvieti čas 10:00. Tento čas je možné pomocou tlačidla SET pod 7-segmentovým displejom nastaviť na ľubovoľnú hodnotu.
 +
Ak chceme čas na displeji nastaviť na vyššiu hodnotu ako je predvolená je potrebné stláčať tlačidlo ''SET'' v krátkych intervaloch.
  
Zdrojový kód: [[Médiá:Serial.h|serial.h]] a [[Médiá:Pip.c|main.c]]
 
  
[[Médiá:MojProgram.c|program.c]]
+
[[Súbor:SET_button.jpg|400px|thumb|center|Tlačidlo ''SET''.]]
  
=== Overenie ===
 
  
Nezabudnite napísať čosi ako užívateľský návod. Z neho by malo byť jasné čo program robí,
+
V prípade potreby nastavenia nižšej hodnoty je nutné tlačidlo ''SET'' pridržať po dobu asi 2 sekúnd. Po krátkom pípnutí pustite tlačidlo a začnite ho stláčať v krátkych intervaloch - hodnota na displeji sa bude zmenšovať.
ako sa prejavuje a aké má užívateľské rozhranie (čo treba stlačiť, čo sa kde zobrazuje).
+
Po nastavení žiadanej hodnoty pridržte tlačidlo ''SET'' po dobu piatich sekúnd. Po dlhšom pípnutí sa začne odpočítavanie.
Ak ste namerali nejaké signály, sem s nimi. Ak je výsledkom nejaký údaj na displeji,
+
 
odfotografujte ho.  
+
Posledných 5 minút je užívateľovi oznámených krátkym pípnutím. Pred odpočítavaním poslednej minúty je počuť dva-krát krátke bliknutie a displej počas zostávajúceho času bliká. Nakoniec zaznie dlhé pípnutie a displej je znovu nastavený na hodnotu 10:00.
 +
 
 +
V prípade problémov je možné odpočítavacie hodiny resetovať pomocou tlačidla ''RESET''. Hodiny sa znovu nastavia na hodnotu 10:00.
 +
 
  
Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.
+
[[Súbor:RESET_button.jpg|400px|thumb|center|Tlačidlo ''RESET''.]]
  
  
 
[[Category:AVR]] [[Category:DVPS]]
 
[[Category:AVR]] [[Category:DVPS]]

Aktuálna revízia z 19:53, 10. január 2014

Autori: Maros Rybarik, Matus Lukac
Študijný odbor: Aplikovaná mechatronika 2. Ing. (2013)

Zadanie

Na konferencii je často potrebné ustrážiť, aby rečník neprekročil vymedzený časový rozsah. Naprogramujte veľkoplošný 7-segmentový LED displej tak, aby od prednastavenej hodnoty odpočítaval minúty smerom nadol, pričom pri zvyšných 5 minútach nenápadne pípne, pri poslednej minúte pípne 2x výraznejšie a po uplynutí času pípne raz dlho. Posledná minúta odpočítavania by mohla byť sprevádzaná aj blikaním displeja. Ovládanie tlačidlom ŠTART a +/- na zmenu počiatočnej hodnoty.

K zapojeniu treba vypracovať dokumentáciu, popis programu, schému zapojenia displeja a riadiacej jednotky. Ako bonus doplňte riadenie intenzity displeja na základe vonkajšieho osvetlenia.

7-segmentLEDdisplayShield.jpg

Literatúra:

Analýza

7-segmentový displej bude riadený procesorom ATMEL ATMEGA 328P, ktorý je súčasťou vývojovej dosky ARDUINO DUEMILANOVE. Táto doska má 14 digitálnych vstupno/výstupných pinov, z ktorých môžem šesť použiť ako PWM výstupy, šesť analógových vstupov a 16 MHz kryštál. Všetky vstupy/výstupy sú zreteľne označené na doske. Pre pripojenie je možné využiť napájací konektor a USB pripojenie. K tejto doske je pripojená vývojová doska so 7-segmentovým displejom podľa schémy zapojenia uvedenej v Popise riešenia.

Ostatné informácie o vývojovej doske ARDUINO DUEMILANOVE sú podrobne vypísané na nasledujúcej adrese http://arduino.cc/en/Main/arduinoBoardDuemilanove.


POTREBNÉ HARDVÉROVÉ VYBAVENIE:

            Vývojová doska ARDUINO DUEMILANOVE
Vývojová doska ARDUINO DUEMILANOVE.


            Vývojová doska so 7-segmentovým displejom, bzučiakom a tlačidlami
Vývojová doska so 7 segmentovým displejom, bzučiakom a tlačidlami.


KATALÓGOVÉ LISTY POUŽITÝCH KOMPONENTOV:


            7-segmentový displej
            [http://www.alldatasheet.com/datasheet-pdf/pdf/220980/BRIGHT/BQ-M514RD.html?
            Procesor Atmel ATmega 328P - použitý na vývojovej doske ARDUINO DUEMILANOVE
            [http://www.atmel.com/Images/doc8161.pdf

Popis riešenia

Schéma zapojenia 7-segmentovky


Schema zapojenia 7 segmentového displeja.


Algoritmus a program

Riadiaci algoritmus pre procesor ATmega 382P bol vytvorený v programe AVR Studio 6.0. Následne pomocou USB pripojenia vývojovej dosky ARDUINO DUEMILANOVE bol súbor *.hex nahraný rýchlosťou 57 600 baudov prostredníctvom softvéru XLOADER do procesora.


Zdrojový kód pre našu aplikáciu vyzerá nasledovne:

#define F_CPU 16000000UL	//Takt procesora 16MHz
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>

//Makra pre operacie s bitmi
#define bit(m)			((1<<m))
#define bit_get(p,m)	((p) & bit(m))
#define bit_set(p,m)	((p) |= bit(m))
#define bits_set(p,m)	((p) |= (m))
#define bit_clear(p,m)	((p) &= ~bit(m))
#define bits_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m)	((p) ^= bit(m))

//Registre portov
#define DDR(x)			(*(&x - 1))
#define PIN(x)			(*(&x - 2))

//Casovac0 pouzity pre zobrazovanie znakov na multiplexovanej 7 segmentovke
#define ZOBRAZENIE_START()	TCNT0+=55;bit_set(TCCR0B,CS01)		//Delicka=8, perioda prerusenia 100us
#define ZOBRAZENIE_STOP()	bit_clear(TCCR0B,CS01);TCNT0=0		//Zastavenie casovaca

//Casovac1 pouzity pre vypocet sekund
#define CASOVAC_START()		TCNT1+=3035;bit_set(TCCR1B,CS12)	//Delicka=64, perioda prerusenia 1s
#define CASOVAC_STOP()		bit_clear(TCCR1B,CS12);TCNT1=0		//Zastavenie casovaca

//v Bootloaderi je povolenie tychto pinov (RX,TX) pre nas program ich vsak nepotrebujeme
#define UART_DISABLE() bits_clear(UCSR0B,bit(RXEN0)|bit(TXEN0)) 

//7segmentovka pinout
#define SEG_PORT PORTD
#define SEG_a	0
#define SEG_b	1
#define SEG_c	2
#define SEG_d	3
#define SEG_e	4
#define SEG_f	5
#define SEG_g	6
#define SEG_dp	7

#define SEG_DIGIT_PORT	PORTB
#define SEG_DIGIT_A1	3
#define SEG_DIGIT_A2	2
#define SEG_DIGIT_A3	1
#define SEG_DIGIT_A4	0

#define SEG_INIT()	bits_set(DDR(SEG_PORT),(bit(SEG_a)|bit(SEG_b)|bit(SEG_c)|bit(SEG_d)|bit(SEG_e)|bit(SEG_f)|bit(SEG_g)|bit(SEG_dp)));bits_set(DDR(SEG_DIGIT_PORT),
(bit(SEG_DIGIT_A1)|bit(SEG_DIGIT_A2)|bit(SEG_DIGIT_A3)|bit(SEG_DIGIT_A4)))

//Bzuciak
#define BUZ_PORT	PORTB
#define BUZ_PIN		5

#define BUZ_INIT()	bit_clear(BUZ_PORT,BUZ_PIN);bit_set(DDR(BUZ_PORT),BUZ_PIN)

//Tlacidlo
#define PB_PORT		PORTB
#define PB_PIN		4

#define PB_INIT()	bit_set(PB_PORT,PB_PIN);bit_clear(DDR(PB_PORT),PB_PIN)

//Premenne su typu volatile, co znamena ze ich kompilator skompiluje a hodnoty sa v obsluhach preruseni budu spravne spracovavat
volatile int8_t sec_jed,sec_des,min_jed,min_des;		//znamienkove 8 bitove premenne obsahujuce hodnoty casomiery
volatile uint16_t delay,dlho;					//neznamienkove 16 bitove premenne 
volatile uint8_t kratko;					//neznamienkova 8bitova premenna pre funkciu tlacidla

//Fukncia zobrazujuca cisla ja zvolenom mieste(sekundy, minuty..)
void cisla_segment(uint8_t segment,uint8_t cislo)
{
	SEG_DIGIT_PORT |= 0x0F - (1<<segment);  //Vypne segmenty okrem toho, ktory sa prave zobrazuje
	
	switch (cislo)
	{
		case 0: SEG_PORT=0xC0;		//cislo 0
			break;
		case 1:	SEG_PORT=0xF9;		//cislo 1
			break;
		case 2:	SEG_PORT=0xA4;		//cislo 2
			break;
		case 3:	SEG_PORT=0xB0;		//cislo 3
			break;
		case 4:	SEG_PORT=0x99;		//cislo 4
			break;
		case 5: SEG_PORT=0x92;		//cislo 5
			break;
		case 6: SEG_PORT=0x82;		//cislo 6
			break;
		case 7: SEG_PORT=0xF8;		//cislo 7
			break;
		case 8: SEG_PORT=0x80;		//cislo 8
			break;
		case 9:SEG_PORT=0x90;		//cislo 9
			break;
		case 10: SEG_PORT=0x7F;		//bodka
			break;
// 		default: SEG_PORT=0xBF;		//pomlcka
// 			break;
	}
	SEG_DIGIT_PORT &= ~(1<<segment);		//Zapne aktualny segment
	
	//zvysenie svietivosti pomocou predlzenia doby aktivneho segmentu
	for (uint8_t i=0;i<100;i++)
	{
		segment++;				//Pouzitie lokalnej premennej pre vytvorenie pauzy
	}
	
}

//Funkcia ovladajuca dlzku tonu bzuciaka
void bzuciak(uint16_t dlzka)
{
	delay=0;
	
	bit_set(BUZ_PORT,BUZ_PIN);		//Zapnutie bzuciaka
	while(delay<dlzka);		        //Pauza
	bit_clear(BUZ_PORT,BUZ_PIN);	        //Vypnutie bzuciaka		
}

//Funkcia zobrazujuca aktalne nastaveny cas pocitadla
void cas(void)
{
	cisla_segment(SEG_DIGIT_A2,10);		//Zobrazenie bodky medzi minutami a sekundami	
	cisla_segment(SEG_DIGIT_A4,sec_jed);	//Jednotky sekund
	cisla_segment(SEG_DIGIT_A3,sec_des);	//Desiatky sekund
	cisla_segment(SEG_DIGIT_A2,min_jed);	//Jednotky minut
	cisla_segment(SEG_DIGIT_A1,min_des);	//Desiatky minut
				
	if(TCCR1B)						                         //Ak casomiera bezi, testuju sa nasledovne podmienky
	{
		if (min_des == 0 && min_jed == 0 && sec_des > 0 && sec_jed > 0  )	//Ak je aktualny cas mensi ako minuta cislice budu blikat
		{
			if (TCNT1<10000)						//Tato podmienka zaruci aby sa bliknutie vykonalo iba raz za sekundu
			{
				bit_set(SEG_DIGIT_PORT,SEG_DIGIT_A1);			//Vypnutie prveho znaku postacuje kedze je to multiplexovana segmentovka
				_delay_ms(20);
			}
		
		}
		if (min_des == 0 && min_jed == 0 && sec_des == 0 && sec_jed > 0  )	//Pri poslednych 10 sekundach cislice blikaju
		{
			if (TCNT1<5000)							//Rychlejsie prebliknutie pri poslednych 10 sekundach
			{
				bit_set(SEG_DIGIT_PORT,SEG_DIGIT_A1);			//Vypnutie prveho znaku
				_delay_ms(10);
			}
		
		}	
	}	
	
}

//Funkcia na obsluhu tlacidla
uint8_t tlacidlo()
{
	uint8_t akt_stav=0;	
	
	for(uint8_t i=0;i<5;i++)					//Odstranenie zakmitov
	{
		akt_stav = !bit_get(PIN(PB_PORT),PB_PIN);		//Citanie logickeho stavu na pine tlacidla, pricom hodnota sa neguje
	}		
	
	if (akt_stav)							//Ak je tlacidlo stlacene inkrementuju sa premenne pre indikaciu dlheho a kratkeho stlacenia	
	{
		kratko++;						//8bit premenna = hodnoty 0-255
		dlho++;							//16bit premenna = hodnoty 0-65535
	}
	else dlho=0;							//ak sa tlacidlo pustilo premenna indikujuca dlhe stlacenie sa vynuluje
	
	return akt_stav;						//Vratenie vysledneho stavu tlacidla(stlacene/nestlacene)
}

//Nastavovanie casomiery
void nastavenie_casu(void)
{
	sec_jed=0,sec_des=0,min_jed=0,min_des=1;			//Globalne premenne obsahujuce hodnoty prednastavenej casomiery
	ZOBRAZENIE_START();						//Spustenie casovaca pre zobrazenie znakov na segmentovke
	CASOVAC_STOP();							//Pripadne zastavenie pocitadla sekund
	
	//Cyklus na inkrementaciu a dekrementaciu casomiery po sekundach
	do 
	{
		//Cyklus inkrementacie casomiery po sekundach
 		do 
		{
			if (tlacidlo()&& !kratko)                        //V pripade ze je tlacidlo stlacene kratko (je stlacene a hodnota kratko pretecie 
                                                                           raz => 0) casomiera sa inkrementuje o jednu sekundu
			{
				sec_jed++;
			}
		
			if (sec_jed>9)					//Ak je viac ako 9 sekund,
			{
				sec_jed=0;				//Jednotky sekund sa vynuluju a
				sec_des++;				//Desiatky sekund sa inkrementuju o jedno
			}
			if (sec_des>5)					//Ak je viac ako 59 sekund,
			{
				sec_des=0;				//Desiatky sekund sa vynuluju a
				min_jed++;				//Jednotky minut sa inkrementuju o jedno
			}	
			if (min_jed>9)					//Ak je viac ako 9 minut,
			{
				min_jed=0;				//Jednotky minut sa vynuluju a
				if (min_des<6)				//V pripade ze je pocet desiatok minut mensi ako 6,
				{
					min_des++;			//Desiatky minut inkrementuju o jedno
				}
				else min_des=0;				//Inak sa desiatky nuluju
			}
		} while (!(tlacidlo()&& dlho>2000));			//V pripad stlacenia tlacidla dlhsie ako 2s sa ukoncuje cyklus inkrementacie 
		dlho=0;							//hodnota sa nuluje v pripade, ze je tlacidlo stlacene dlhsie ako 2s aby nedoslo 
                                                                        k nechcenemu ukonceniu cyklu 
		bzuciak(100);					        //Pre uzivatela sa vysle kratky signal bzuciakom potvrdenie ukoncenia cyklu
		
		//Cyklus dekrementacie casomiery po sekundach
		do 
		{
			if (tlacidlo()&& !kratko)		        //V pripade ze je tlacidlo stlacene kratko (je stlacene a hodnota kratko pretecie raz => 0)
			{
				sec_jed--;				//casomiera sa dekrementuje o jednu sekundu
			}
		
			if (sec_jed < 0)				//Ak je jednotiek sekund menej ako nula
			{
				sec_des--;				//Tak sa desiatky sekund dekrementuju
				sec_jed = 9;				//Pricom sa jednotky nastavia na 9
				if (sec_des < 0)			//Ak je desiatok sekund menej ako nula nastavia sa na hodnotu 5
				{
					sec_des = 5;						
					min_jed--;			//Pricom sa jednotky minut dekrementuju o jedno
					if (min_jed<0)			//V pripade ze su jednotky minut mensie ako nula,
					{
						min_jed=9;		//nastavia sa jednotky minut na hodnotu 9 a desiatky sa dekrementuju o jedno
						min_des--;
						if(min_des<0)		//Ak su desiatky minut mensie ako je zostavaju na nule
						{
							min_des=0;
						}
					}
				}
			}
		} while (!(tlacidlo()&& dlho>2000));			//Pre ukoncenie cyklu dekrementacie je potrebne tlacidlo drzat dlhsie ako 2s
		bzuciak(100);						//Kratkym tonom je uzivatel oboznameny s ukoncenym cyklu dekrementacie
	} while (!(tlacidlo()&& dlho>2000));				//Neustalym drzanim tlacidla sa dostavame von z cykla inkrementacie a dekrementacie
	
	bzuciak(300);							//Dlhym tonom je oznamene ukoncenie cykla a start casomiery
	CASOVAC_START();						//Start casovaca s periodou 1s
}

int main(void)
{
	//Inicializacne makra
	UART_DISABLE();							//Vypnutie alternativnej funkcie pinov(UARTu=RX,TX) PD0 a PD1
	SEG_INIT();							//Nastavenie vystupov multiplexovanej 7 segmentovky
	BUZ_INIT();							//Nastavenie vystupu bzuciaka
	PB_INIT();							//Nastavenie vstupu tlacidla
	
	//Nastavenie masiek preruseni pre pouzite casovace
	bit_set(TIMSK0,TOIE0);
	bit_set(TIMSK1,TOIE1);
	bit_set(TIMSK2,TOIE2);
	
	//Start casovaca s delickou 32 a periodou prerusenia 100us
	TCNT2 += 5;
	bits_set(TCCR2B,(bit(CS21)|bit(CS20)));
	
	//Globalne povolenie preruseni
	sei();
	
	//Po inicializacii sa spusta proces nastavenia casu casomiery
	nastavenie_casu();
    
	while(1)								        //Nekonecna slucka
    {
		if (sec_des == 0 && sec_jed == 0 && min_des == 0 && min_jed == 5)	//Pri 5. minute sa spusti kratky ton bzuciaka
		{
			if (TCNT1<6000)bzuciak(250);			
		}
		
		if (sec_des == 0 && sec_jed == 0 && min_des == 0 && min_jed == 1)	//Pri 1. minute sa spusti dlhsi ton bzuciaka
		{
			if (TCNT1<10000)bzuciak(500);
		}
		
		if (sec_des == 0 && sec_jed == 0 && min_des == 0 && min_jed == 0)	//Ked sa odpocet skonci,
		{
			bit_set(SEG_DIGIT_PORT,SEG_DIGIT_A1);				//Segmentovka sa vypne
			ZOBRAZENIE_STOP();
			bzuciak(5000);							//Bzuciak vydava dlhy ton
			CASOVAC_STOP();							//Casovac sekund sa vypne
			nastavenie_casu();						//Proces nastavovania casomiery zacina odznova
		}
		else if (sec_jed < 0)							//Ak je jednotiek sekund menej ako nula
		{
			sec_des--;							//Tak sa desiatky sekund dekrementuju
			sec_jed = 9;							//Pricom sa jednotky nastavia na 9
			if (sec_des < 0)					        //Ak je desiatok sekund menej ako nula nastavia sa na hodnotu 5
			{
				sec_des = 5;
				min_jed--;						//Pricom sa jednotky minut dekrementuju o jedno
				if (min_jed<0)						//V pripade ze su jednotky minut mensie ako nula,
				{
					min_jed=9;					//nastavia sa jednotky minut na hodnotu 9 a desiatky sa dekrementuju o jedno
					min_des--;
					if(min_des<0) min_des=0;			//Ak su desiatky minut mensie ako je zostavaju na nule
				}
			}
		}
		
    }
}

//Obsluhy preruseni
ISR(TIMER0_OVF_vect)
{
	TCNT0+=55;		//perioda 100us
	cas();
}
ISR(TIMER1_OVF_vect)
{
	TCNT1+=3035;		//perioda 1s
	sec_jed--;
}
ISR(TIMER2_OVF_vect)
{
	TCNT2+=5;		//perioda 500us 
	delay++;
}

Overenie

Po pripojení odpočítavacích hodín k zdroju napájania prostredníctvom USB alebo konektora "JACK" sa na displeji rozsvieti čas 10:00. Tento čas je možné pomocou tlačidla SET pod 7-segmentovým displejom nastaviť na ľubovoľnú hodnotu. Ak chceme čas na displeji nastaviť na vyššiu hodnotu ako je predvolená je potrebné stláčať tlačidlo SET v krátkych intervaloch.


Tlačidlo SET.


V prípade potreby nastavenia nižšej hodnoty je nutné tlačidlo SET pridržať po dobu asi 2 sekúnd. Po krátkom pípnutí pustite tlačidlo a začnite ho stláčať v krátkych intervaloch - hodnota na displeji sa bude zmenšovať. Po nastavení žiadanej hodnoty pridržte tlačidlo SET po dobu piatich sekúnd. Po dlhšom pípnutí sa začne odpočítavanie.

Posledných 5 minút je užívateľovi oznámených krátkym pípnutím. Pred odpočítavaním poslednej minúty je počuť dva-krát krátke bliknutie a displej počas zostávajúceho času bliká. Nakoniec zaznie dlhé pípnutie a displej je znovu nastavený na hodnotu 10:00.

V prípade problémov je možné odpočítavacie hodiny resetovať pomocou tlačidla RESET. Hodiny sa znovu nastavia na hodnotu 10:00.


Tlačidlo RESET.