Cílem projektu bylo navrhnout digitální programovatelný časový spínač pro řízení provozu elektrických zařízení. Časový spínač nachází uplatnění v řadě míst, kde je třeba ohlídat čas. Například při různých výrobních procesech. Maximální časový údaj, který lze nastavit, je 99 hodin, 59 minut a 59 sekund.
Obvodové zapojení časovače je na obr.1. Jeho jádrem je naprogramovaný mikrokontrolér ATmega16 od firmy Atmel, který obsluhuje veškeré periférie. MCU je taktován krystalem o frekvenci 16 MHz a k jeho naprogramování slouží konektor ISP . Spínaný obvod je připojen pomocí svorkovnice K1. Silový výstup je vyřešen pomocí 5 V relé s maximálním proudem až 8 A. Toto relé je spínáno tranzistorem T1, který je připojen na pin PC5 mikrokontroléru. Zda je relé sepnuté je opticky signalizováno LED diodou D6. Při rozepnutí výstupního kontaktu dojde po dobu jedné sekundy k akustické signalizaci piezoměničem s rezonančním kmitočet přibližně 4 kHz, který je připojen na pin PD7. Na portu D jsou dále připojeny tři LED diody D2 - D4 a čtyři tlačítka SW2 - SW5. LEDky nejsou použity, ale připraveny na pozdější využití.
Ovládání časovače je vyřešeno pomocí pěti tlačítek SW1 až SW5. Jejich funkce je následující:
O zobrazení uživatelských informací se stará alfanumerický displej MC1602E-TRV o 16x2 znacích obsahující řadič HD44780 od Hitachi. LCD je připojeno na port C a komunikace probíhá ve 4-bitovém režimu, což umožňuje ušetřit čtyři piny MCU a rovněž jednodušší návrh DPS. Trimr P1 slouží pro nastavení kontrastu zobrazení. Na LCD se při provozu zobrazuje stav výstupního konstaktu (ON nebo OFF), aktuální čas zbývající do vypnutí a také formát zobrazovaných hodin. Na obr.2 je ukázán návrh DPS a rozložení periférií na desce.
Napájecí napětí 12 V je na desku plošného spoje přivedeno ze síťového adaptéru na konektor K2. Toto napětí je dále sníženo na 5 V stabilizátorem 7805. Přítomnost napětí signalizuje LED dioda D5.
// Knihovny-------------------------------------------------------------------------------------------------------------------------------------- #define F_CPU 16000000UL // kmitočet hodin #include <avr/io.h> // hlavičkový soubor mikrokontroléru #include "lcd_h.h" // hlavičkový soubor pro LCD #include <stdio.h> // standartní I/O knihovna #include <avr/interrupt.h> // hlavičkový soubor pro přerušení #include <util/delay.h> // hlavičkový soubor pro zpoždění // Definice řetězců ----------------------------------------------------------------------------------------------------------------------------- unsigned char MSG1[12] = "Device is: "; unsigned char MSG2[4] = "OFF"; unsigned char MSG3[4] = "ON "; unsigned char MSG6[6] = "H:M:S"; unsigned char MSG_pom[4]; // Definice globálních proměnných --------------------------------------------------------------------------------------------------------------- unsigned char sek, sek1 = 0; // sekundy unsigned char min, min1 = 0; // minuty unsigned char hod, hod1 = 0; // hodiny unsigned char pom1, pom2, pom3, pom4, pom5, pom6, pom7 = 0; // pomocné proměnné unsigned char kurzor_x = 0; // horizontální souřadnice kurzoru - použito při nastavování časovače unsigned char inkr = 0; // proměnná pro inkrementaci cifer časovače // Prototypy funkcí ----------------------------------------------------------------------------------------------------------------------------- void piezo(void); // sepnutí piezoměniče na 1s void LCD_show( char kur_x, char kur_y, char cislo1, char cislo2, char str); // zobrazení dvoučíslí na LCD // kur_x - horizontální pozice kurzoru, kur_y - vertikální pozice kurzoru // cislo1 - první z dvoučísel, cislo2 - druhé z dvoučísel // str - pomocná proměnná pro rozlišení formátu zobrazení // Obsluha přerušení při přetečení čítače1 ------------------------------------------------------------------------------------------------------ ISR (TIMER1_OVF_vect){ // obsluha slouží pro dekrementaci stavu digitálního časovače TCNT1 = 0x0BDC; // počáteční hodnota čítače1 (aby přetekl za 1s) if(sek == 0){ if(sek1==0 && sek==0){ if( min1 == 0 && min == 0){ if( hod == 0){ if( hod1==0 && hod==0){ hod1=10; } hod1--; hod=10; } min1=5; min=10; hod--; } if(min1 > 0 && min == 0 ){ min1--; min=10; } if(min1 == 0 && min > 0){ min1=0; min--; } if(min1 > 0 && min > 0){ min--; } sek1=6; } sek1--; sek=10; } sek--; } // Obsluha přerušení při přetečení čítače0 ------------------------------------------------------------------------------------------------------ ISR (TIMER0_OVF_vect){ // blikání vybrané cifry na displeji při nastavování počátečního stavu časovače if (pom7 != 20 )pom7++; // blikání s periodou přibližně 320 ms else{ if (pom6 == 0) pom6 = 1; // střídavé zobrazení požadované cifry a prázdného znaku - blikání cifry else pom6 = 0; // pokud je pom6=0 dojde k zobrazení nastavené hodnoty, jinak prázdný znak pom7 = 0; } } // Obsluha externího přerušení od tlačítka ENTER ----------------------------------------------------------------------------------------------- ISR (INT0_vect){ // inkrementace vybrané cifry - při nastavování časovače _delay_ms(50); // if(bit_is_clear(PIND,2)){ // ošetření zákmitů tlačítka if(kurzor_x == 3){ // kurzor na čtvrté pozici - desítky minut if(inkr == 5) inkr=0; // desítky minut max do hodnoty 5, pak nulovat else inkr++; // jinak inkrementuj } else if(kurzor_x == 6){ // kurzor na šesté pozici - desítky sekund if(inkr == 5) inkr=0; // desítky sekund max do hodnoty 5, pak nulovat else inkr++; // jinak inkrementuj } else{ if(inkr == 9) inkr=0; // na jiných pozicích kurzoru je max hodnota 9, pak nulování else inkr++; // jinak inkrementuj } } } // Obsluha externího přerušení od tlačítka START/STOP ------------------------------------------------------------------------------------------ ISR (INT1_vect) { // spouštění a zastavování digitálního časovače _delay_ms(50); // if(bit_is_clear(PIND,3)){ // ošetření zákmitů tlačítka if (pom5 == 0){ TCCR1B |= (1 << CS12); // zapnutí čítače1 - předělička 256 pom5 = 1; } else { TCCR1B = 0x00; // vypnutí čítače1 pom5 = 0; } } } // Hlavní funkce main -------------------------------------------------------------------------------------------------------------------------- int main(void){ // hlavní funkce main DDRD = 0x80; // port D vstupní, pouze PD7 výstupní DDRC |= (1 << PINC5); // relé na portu C pin 5 PORTC = 0x00; // na výstupní piny portu C -> 0 (relé vyplé) MCUCR |= (1 << ISC11)|(1 << ISC01); // externí přerušení INT1, INT0 od tlačítka při sestupné hraně GICR |= (1 << INT1)|(1 << INT0); // povolení externího přerušení INT1 a INT0 TCCR2 |= (1 << WGM21)|(1 << CS22)|(1 << CS21); // CTC režim čítače 2 (toggle), předdělička 256 TCCR1A = 0x00; // normální režim čítače1 TCCR1B = 0x00; // vypnutý čítač1 TCCR0 |= (1 << CS02)|(1 << CS00); // zapnutý čítač0 - normální režim, předdělička 1024, přetečení - asi 16ms TIMSK |= (1 << TOIE1)|(1 << TOIE0); // povolení přerušení při přetečení 16bit čítače1 a 8bit čítače0 TCNT1 = 0x0BDC; // počáteční hodnota čítače1 - přetečení za 1s OCR2 = 0x07; // konstanta pro CTC režim čítače2 - obdélník 4 kHz(pro piezoměnič) lcd_init ( ); // inicializace displeje lcd_clrscr ( ); // smazání obsahu displeje lcd_gotoxy(0,0); // kurzor na pozici 0,0 - 1. řádek, 1. sloupec lcd_puts(MSG1); // zobrazení řetězce MSG1 lcd_gotoxy(11,0); // kurzor na pozici 0,0 - 1. řádek, 12. sloupec lcd_puts(MSG2); // zobrazení řetězce MSG2 lcd_gotoxy(9,1); // kurzor na pozici 0,0 - 2. řádek, 10. sloupec lcd_puts(MSG6); // zobrazení řetězce MSG6 LCD_show( 0, 1, hod1, hod, 1); // zobrazení hodin na pozici 0,1 LCD_show( 3, 1, min1, min, 1); // zobrazení minut na pozici 3,1 LCD_show( 6, 1, sek1, sek, 0); // zobrazení sekund na pozici 7,1 sei (); // povolení globálního přerušení // Nastavování počátečeního stavu digitálního časovače ----------------------------------------------------------------------------------------- while(kurzor_x != 8){ // smyčka se provádí dokud není kurzor na pozici 8 - až se nastaví všechny // cifry časovače if(bit_is_clear(PIND,0) || pom3 == 1 ){ // testování zda je stiknuto tlačítko ON/OFF _delay_ms(100); // pom3 = 1; // if(bit_is_set(PIND,0)){ // _delay_ms(20); // ošetření zákmitů při stisku tlačítka ON/OFF PORTC ^= 0b00100000; // při každém stisku tlačítka je relé bud vypnuto nebo sepnuto pom3 = 0; } } if (PORTC == 0b00100000){ // pokud je relé sepnuté, na displeji se zobrazí ON lcd_gotoxy(11,0); lcd_puts(MSG3); } else if (PORTC == 0b00000000){ // pokud je relé vypnuté, na displeji se zobrazí OFF lcd_gotoxy(11,0); lcd_puts(MSG2); } if(bit_is_clear(PIND,1) || pom4 == 1 ){ // testování zda je stiknuto tlačítko SELECT _delay_ms(100); // pom4 = 1; // if(bit_is_set(PIND,1)){ // _delay_ms(20); // ošetření zákmitů při stisku tlačítka SELECT LCD_show( kurzor_x, 1, inkr, 5, 2); // zajistí zobrazení poslední nastavené hodnoty - sekundy (sek) kurzor_x++; // přesunutí kurzoru o jednu pozici doprava - další cifra inkr=0; // počáteční hodnota cifry při nastavování pom4 = 0; } } if(kurzor_x == 2) kurzor_x = 3; // pokud je pozice kurzoru 2, přesun na pozici 3 - vynechání dvojtečky if(kurzor_x == 5) kurzor_x = 6; // pokud je pozice kurzoru 5, přesun na pozici 6 - vynechání dvojtečky switch (kurzor_x){ // podle pozice kurzoru se do proměnných, které budou následně // dekrementovány, uloží nastavené hodnoty case (0): hod1 = inkr; break; case (1): hod = inkr; break; case (3): min1 = inkr; break; case (4): min = inkr; break; case (6): sek1 = inkr; break; case (7): sek = inkr; break; } if(kurzor_x != 8){ // provádí se dokud se nenastaví všechny cifry if(pom6 == 0){ // k zobrazení nastavené hodnoty dojde jen když pom6=0 LCD_show( kurzor_x, 1, inkr, 5, 2); // zobrazení nastavené hodnoty (inkr) na pozici kurzor_x,1 } else{ lcd_gotoxy(kurzor_x,1); // pokud pom6=1 zobrazí se prázdný znak sprintf(MSG_pom, " "); lcd_puts(MSG_pom); } } } // Dekrementace časovače ----------------------------------------------------------------------------------------------------------------------- TCCR0 = 0x00; // vypnutí čítače0 while (1) // nekonečná smyčka, kde dochází k dekrementaci časovače a aktualizaci jeho { // stavu na LCD if(bit_is_clear(PIND,0) || pom2 == 1 ){ // testování zda je stisknuto tlačítko ON/OFF _delay_ms(100); // pom2 = 1; // if(bit_is_set(PIND,0)){ // _delay_ms(20); // ošetření zákmitů při stisku tlačítka ON/OFF PORTC ^= 0b00100000; // při každém stisku tlačítka je relé bud vypnuto nebo sepnuto pom2 = 0; } } if (PORTC == 0b00100000){ // pokud je relé sepnuté, na displeji se zobrazí ON lcd_gotoxy(11,0); lcd_puts(MSG3); } else if (PORTC == 0b00000000){ // pokud je relé vypnuté, na displeji se zobrazí OFF lcd_gotoxy(11,0); lcd_puts(MSG2); } LCD_show( 0, 1, hod1, hod, 1); // zobrazení hodin na pozici 0,1 LCD_show( 3, 1, min1, min, 1); // zobrazení minut na pozici 3,1 LCD_show( 6, 1, sek1, sek, 0); // zobrazení sekund na pozici 6,1 if(sek1 == 0 && sek == 0 && min1 == 0 && min == 0 && hod1 == 0 && hod == 0) // pokud je časovač ve stavu 00:00:00, tak se provede jeho zastavení { TCCR1B = 0x00; // vypnutí čítače1 - zastaví dekrementaci časovače if (pom1 == 0){ // vypnutí relé a pípnutí piezoměniče se provede pouze jednou LCD_show( 0, 1, hod1, hod, 1); // zobrazení hodin na pozici 0,1 LCD_show( 3, 1, min1, min, 1); // zobrazení minut na pozici 3,1 LCD_show( 6, 1, sek1, sek, 0); // zobrazení sekund na pozici 6,1 PORTC = 0x00; // vypnutí relé lcd_gotoxy(11,0); // kurzor na pozici 11,0 - 1. řádek, 12. sloupec lcd_puts(MSG2); // zobrazení řetězce MSG2 na displeji piezo(); // volání funkce pro piezoměnič - akustická indikace vypnutí časovače pom1 = 1; } } } } // Konec funkce main //Definice funkcí ------------------------------------------------------------------------------------------------------------------------------ void piezo(void){ // funkce piezoměniče TCCR2 |= 0b00010000; // zapnutí piezoměniče char m = 4; while (m>0){ // sepnutí piezoměniče na 250ms x 4 = 1s _delay_ms(250); // zpoždění 250 ms m--; } TCCR2 &= 0b11101111; // vypnutí piezoměniče } void LCD_show( char kur_x, char kur_y, char cislo1, char cislo2, char str){ // funkce pro zobrazení doučíslí na displeji // proměnná str pro rozlišení požadovaného formátu zobrazení - 3 možnosti char cifra [4]; // lokální proměnná if (str == 0){ // zobrazení doučíslí bez dvojtečky lcd_gotoxy(kur_x,kur_y); // kurzor na pozici kur_x a kur_y sprintf(cifra, "%d%d",cislo1, cislo2); // do proměnné cifra uloží řetězec znaků lcd_puts(cifra); // zobraz na displeji řetězec cifra } if (str == 1){ // zobrazení doučíslí s dvojtečkou lcd_gotoxy(kur_x,kur_y); // kurzor na pozici kur_x a kur_y sprintf(cifra, "%d%d:",cislo1, cislo2); // do proměnné cifra uloží řetězec znaků lcd_puts(cifra); // zobraz na displeji řetězec cifra } if (str == 2){ // možnost zobrazení pouze jedné cifry lcd_gotoxy(kur_x,kur_y); // kurzor na pozici kur_x a kur_y sprintf(cifra, "%d",cislo1); // do proměnné cifra uloží řetězec znaků lcd_puts(cifra); // zobraz na displeji řetězec cifra } }
Digitální časový spínač se podařilo realizovat dle předem zadaných požadavků. Jeho přesnost závisí zejména na stabilitě taktovacího kmitočtu MCU. Pro jednoduché aplikace však plně dostačuje. Časovač by bylo možné rozšířit například o obvod RTC, který by dovoloval naprogramovat spínač tak, aby se výstupní konstakt sepl a rozepl v určitou hodinu, den, měsíc nebo rok.