Clock

Clock

Zostałem poproszony o zaprojektowanie układu prostego i taniego zegara czasu rzeczywistego o podstawowej funkcjonalności i niewielkich wymiarach zewnętrznych – tak oto powstał projekt Clock.

Podstawowe parametry:
  • napięcie zasilania 3…5 V
  • średni prąd obciążenia 70 mA

Budowa i działanie

Schemat urządzenia pokazano na rysunku 1. Zaprojektowano dość prosty system mikroprocesorowy zbudowany z wykorzystaniem popularnego mikrokontrolera firmy Atmel typu ATmega48 taktowanego wewnętrznym, wysokostabilnym oscylatorem o częstotliwości 1 MHz, którego zadaniem jest realizacja wszystkich założonych funkcjonalności. Mikrokontroler ten realizuje tutaj dwa podstawowe zadania: obsługę programowego zegara czasu rzeczywistego RTC oraz obsługę wyświetlacza LED.

Rysunek 1. Schemat ideowy urządzenia Clock

W celu realizacji zegara czasu rzeczywistego, w jego najprostszej formie, wykorzystano układ czasowo-licznikowy Timer2, wbudowany w mikrokontroler, pracujący w trybie asynchronicznym i taktowany przy udziale zewnętrznego rezonatora kwarcowego o częstotliwości 32768 Hz. Odpowiednio skonfigurowany Timer2 generuje co 1 sekundę przerwanie od przepełnienia licznika, co wykorzystano do programowej realizacji prostego zegara czasu rzeczywistego. Sposób konfiguracji układu czasowo-licznikowego Timer2 w celu realizacji zegara czasu rzeczywistego pokazano na listingu 1.

Listing 1. Konfiguracja układu czasowo-licznikowego Timer2 w celu realizacji zegara czasu
rzeczywistego

void megaRTCinit(void){
//Timer2 taktowany za pomocą kwarcu 32768Hz podłączonego do wypr. TOSC1/TOSC2
ASSR |= (1<<AS2);
//Preskaler = 128, przerwanie przepełnienia co 1s (32768/128/256)
TCCR2B = (1<<CS22)|(1<<CS20);
while(ASSR & ((1<<TCN2UB)|(1<<OCR2AUB)|(1<<OCR2BUB)|(1<<TCR2AUB)| (1<<TCR2BUB))); //Oczekiwanie na aktualizację rejestrów
//Skasowanie ewentualnych flag przerwań (przez wpisanie jedynek do bitów flag)
TIFR2 = ((1<<OCF2B)|(1<<OCF2A)|(1<<TOV2));
//Uruchomienie przerwania od przepełnienia licznika TCNT2
TIMSK2 = (1<<TOIE2);
}

Co ważne, dla przejrzystości realizacji założonej funkcjonalności (zegara czasu rzeczywistego i stopera) wprowadzono 2 zmienne strukturalne, których zastosowanie upraszcza kod wynikowy i jednocześnie czyni go bardziej przejrzystym. Deklaracje wspomnianych zmiennych pokazano na listingu 2.

Listing 2. Deklaracje zmiennych w realizacji zegara czasu rzeczywistego

//Definicja typu odpowiedzialnego za obsługę zegara
typedef struct{
volatile uint8_t Flag, Hour, Minute, Second;
} clockType;

//Definicja typu odpowiedzialnego za obsługę stopera
typedef struct{
volatile uint8_t Activity, Flag, Minute, Second;
} timerType;

//Zmienne globalne modułu
extern clockType Clock; //Struktura przechowująca dane zegara
extern timerType Timer; //Struktura przechowująca dane timera

Dalej, na listingu 3, pokazano ciało funkcji obsługi przerwania od przepełnienia zawartości licznika Timer2 (wywoływane co 1 s), której zadaniem jest realizacja zegara czasu rzeczywistego i prostego stopera.

Listing 3. Ciało funkcji obsługi przerwania realizujące funkcjonalność zegara czasu rzeczywistego

//Przerwanie od przepełnienia licznika Timer2 wywoływane 1 raz na sekundę (Timer2
//taktowany kwarcem zegarkowym 32768Hz)

ISR(TIMER2_OVF_vect){
//Obsługa programowego zegara
Clock.Flag = 1;

if(++Clock.Second == 60){
Clock.Second = 0;

if(++Clock.Minute == 60){
Clock.Minute = 0;
if(++Clock.Hour == 24) Clock.Hour = 0;
}
}

//Obsługa programowego timera
if(Timer.Activity){
Timer.Flag = 1;

if(++Timer.Second == 60){
Timer.Second = 0;
if(++Timer.Minute == 100) Timer.Minute = 0;
}
}
}

Pora na przedstawienie drugiego, kluczowego mechanizmu naszego urządzenia. Mowa o obsłudze 7-segmentowego wyświetlacza LED, która realizowana jest w ramach typowego multipleksowania kolejnych cyfr tegoż wyświetlacza. Jest to zwyczajowe rozwiązanie problemu tego typu pozbawione jakiejkolwiek i niepotrzebnej tutaj finezji. Katody poszczególnych wyświetlaczy LED podłączono bezpośrednio do portu PORTD mikrokontrolera, zaś wspólne anody, poprzez tranzystory sterujące (T1…T4), do portu PORTC tegoż układu. Następnie skonfigurowano układ czasowo-licznikowy Timer0 wbudowany w strukturę mikrokontrolera w taki sposób, by generował stosowne przerwanie 240 razy na sekundę (czyli 60 razy na każdą cyfrę wyświetlacza LED), w ramach którego wyświetlane są kolejne cyfry zegara. Aby uruchomić mechanizm multipleksowania, niezbędne jest odpowiednie skonfigurowanie układu czasowo-licznikowego Timer0, które pokazano na listingu 4.

Listing 4. Konfiguracja układu czasowo-licznikowego Timer0 w celu realizacji multipleksowania

void initMultiplex(void){
//Porty wspólnych anod i katod, jako wyjściowe ze stanami nieaktywnymi
//na wyjściach
SEG_BLANK;
SEG_AS_OUTPUT;
COM_BLANK;
COM_AS_OUTPUT;

//Konfiguracja układu Timer0 w celu generowania przerwania do obsługi
//multipleksowania wyświetlacza LED (240 Hz)
TCCR0A = (1<<WGM01); //Tryb CTC
TCCR0B = (1<<CS01)|(1<<CS00); //Preskaler = 64
OCR0A = 64; //240 Hz (przerwanie co 4.167ms)
//Uruchomienie przerwania Output Compare Match A (od porównania)
TIMSK0 = (1<<OCIE0A);
}

Do kompletu potrzebne są nam jeszcze definicje dwóch tablic upraszczających mechanizm multipleksowania. Pierwsza z nich, DIGITS[], zawiera definicje poszczególnych cyfr wyświetlacza 7-segmentowego (czyli stanów logicznych na porcie katod wyświetlacza), zaś druga, COMS[], zawiera definicje dla portu sterującego wspólnymi anodami wyświetlaczy LED (czyli stanów logicznych na porcie wspólnych anod wyświetlacza). Na koniec, na listingu 5, przedstawię ciało funkcji obsługi przerwania układu czasowo-licznikowego Timer0, realizującą mechanizm multipleksowania wyświetlaczy LED.

Listing 5. Funkcja obsługi przerwania układu czasowo-licznikowego Timer0, realizująca mechanizm multipleksowania wyświetlaczy LED

//Przerwanie obsługi wyświetlacza LED wywoływane co 4,167 ms (60 razy na sekundę dla każdej z cyfr)

ISR(TIMER0_COMPA_vect){
static uint8_t Nr; //Numer kolejnej cyfry przeznaczonej do wyświetlenia
//Timer programowy 4ms służący do obsługi migania cyfr wyświetlacza LED
static uint8_t timer4ms;
uint8_t currentDigit = Digit[Nr]; //Optymalizacja zmiennej volatile

COM_BLANK; //Wyłączenie wspólnych anod wyświetlaczy LED

//Sprawdzamy, czy dla danej cyfry uruchomiono funkcję migania (ustawiony najstarszy bit zmiennej)
if(currentDigit & BLINKING_BIT)
{
if(++timer4ms & 0x40) SEG_PORT = pgm_read_byte(&DIGITS[currentDigit & (~BLINKING_BIT)]); else SEG_BLANK;
//Migamy co 266ms
}
//Pobranie kolejnej cyfry na port katod
else SEG_PORT = pgm_read_byte(&DIGITS[currentDigit & (~BLINKING_BIT)]);

//Obsługa migania dwukropkiem
if((++timer4ms & 0x80)) SEG_PORT &= ~(1<<SEG_CL);

//Włączenie odpowiedniej wspólnej anody (aktywny stan „0”)
COM_PORT &= pgm_read_byte(&COMS[Nr]);

Nr = (Nr+1) & 0x03;
}

Jak widać, zaimplementowano dodatkową funkcjonalność w postaci obsługi migania dowolnej cyfry wyświetlacza LED (gdy ustawiony jest najstarszy bit tejże cyfry), co wykorzystywane jest w trybie edycji nastaw zegara czasu rzeczywistego.

Na koniec, już zupełnie dla porządku, należy dodać, że mikrokontroler sterujący odpowiada również za obsługę prostego interfejsu użytkownika w postaci dwóch przycisków umownie oznaczonych jako OK i SET, przy czym, co istotne, obsługiwane jest zarówno krótkie, jak i długie wciśnięcie każdego z przycisków.

Montaż

Schemat płytki PCB oraz schemat montażowy urządzenia Clock pokazano na rysunkach 2 i 3.

Rysunek 2. Schemat montażowy płytki PCB, strona TOP
Rysunek 3. Schemat montażowy płytki PCB, strona BOTTOM

Zaprojektowano bardzo zwarty obwód drukowany, o wielkości zbliżonej do wielkości zastosowanego wyświetlacza LED, zbudowany ze zdecydowaną przewagą elementów SMD umieszczonych po obu stronach laminatu. Montaż urządzenia rozpoczynamy od warstwy BOTTOM, gdzie w pierwszej kolejności przylutowujemy mikrokontroler sterujący. Następnie lutujemy rezonator kwarcowy SMD, tranzystory sterujące a na koniec elementy bierne. Dalej przechodzimy na warstwę TOP, gdzie montujemy elementy C1, T4 i R13, po czym przylutowujemy wyświetlacz LED.

Ustawienia Fuse-bitów (ważniejszych):
CKSEL3...0: 0010
SUT1...0: 10
CKDIV8: 0
CKOUT: 1
DWEN: 1

Na koniec przylutowujemy mikroprzełączniki OK i SET. Poprawnie zmontowany układ powinien działać tuż po włączeniu zasilania. Zmontowaną płytkę od strony BOTTOM pokazuje fotografia 4.

Fotografia 4. Zmontowana płytka od strony BOTTOM

Obsługa

Zgodnie z tym, co napisano wcześniej, interfejs użytkownika naszego urządzenia składa się z dwóch mikroprzełączników umownie nazwanych OK i SET, przy czym obsługiwane jest zarówno krótkie, jak i długie (powyżej 0,5 s) naciśnięcie każdego z elementów sterujących.

Rysunek 5. Diagram obrazujący sposób obsługi urządzenia Clock

Diagram obrazujący sposób obsługi urządzenia przedstawiono na rysunku 5.

Robert Wołgajew, EP

Wykaz elementów:
Rezystory: (obudowa SMD 0805)
  • R1: 47 kΩ
  • R2…R5, R7…R9: 270 Ω
  • R6: 130 Ω
  • R10…R13: 2,2 kΩ
Kondensatory: (obudowa SMD 0805)
  • C1: 100 nF
Półprzewodniki:
  • U1: ATmega48 (TQFP32)
  • T1…T4: BC807 (SOT23)
  • LED: wyświetlacz typu LED-AF5643FS
Inne:
  • SET, OK: mikroswitch TACT 6 mm
  • Q1: rezonator kwarcowy SMD 32768 Hz
Artykuł ukazał się w
Elektronika Praktyczna
sierpień 2019
KIT do tego projektu
Clock, AVT5699
Clock, AVT5699
Clock to prosty projekt zegara czasu rzeczywistego zbudowany z wykorzystaniem popularnego mikrokontrolera firmy Atmel typu ATmega48. Mikrokontroler...
Zobacz w sklepie

Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik wrzesień 2021

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio wrzesień - październik 2021

Świat Radio

Magazyn krótkofalowców i amatorów CB

Automatyka Podzespoły Aplikacje wrzesień 2021

Automatyka Podzespoły Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna wrzesień 2021

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Elektronika dla Wszystkich wrzesień 2021

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów