Biblioteka dla zegara RTC PCF8563p

Przyszła kolej na prezentację biblioteki zegara RTC PCF8563p własnego autorstwa.

Układ PCF8563p jest zegarem czasu rzeczywistego (Real-Time Clock). Jest bratem dobrze znanego układu tej samej marki PCF8583p. Największa różnica występuje w podłączeniu tych układów.

PCF8563 nie posiada nóżki adresowej – adres układu jest stały – natomiast posiada zamiast niej wyjście CLKOUT, oraz pin 7 został zamieniony z pinem 3. Poniżej przedstawiam schemat podłączenia układu:

pcf8563p
Podłączenie układu RTC – PCF8563p

Kolejna różnica występuje w formacie zapisu roku. Opisywany układ posiada zapis roku jako dwie ostatnie cyfry, np 15 – rok 2015 (zakres 00 do 99). Natomiast w układzie PCF8583p występowało określenie roku parzystości (rejestr przechowujący rok w formacie 0 do 3).

W moich bibliotekach nie zaimplementowałem obsługi funkcji alarmu oraz timera.

Poniżej przedstawiam zawartość odpowiednich plików mojej biblioteki (na końcu artykułu można pobrać komplet plików):

Plik główny *.c:

    /*
     * pcf8563p.h
     *
     *  Created on: 08-05-2014
     *   Edited on: 11-05-2014
     *      Author: Daniel
     *
     *       *      UWAGA!!
     *              Koniecznie na początku programu nalezy zarejestrowac funkcji do startu, stopu odbierania i wysylania
     *              danych po i2c (TWI). Dokonuje się to przy uzyciu funkcji:
     *                      register_twi_start_pcf( );                      //rejestracja funkcji start z i2c
     *                      register_twi_stop_pcf( );                               //rejestracja funkcji stop z i2c
     *                      register_twi_write_pcf( );      //rejestracja funkcji zapisującej do i2c
     *                      register_twi_read_pcf( );       //rejestracja funkcji odczytującej z i2c
     *
     *              Odczyt danych z rtc dokonuje się z callendar_rtc po wczesniejszym wywolaniu funkcji rtc_refresh_data()
     *              Zapis danych do rtc dokonuje się poprzez wywolanie funkcji rtc_write_data(), powczesniejszym wpisaniu
     *              zadanych danych do callendar_rtc
     *
     */
     
    #ifndef PCF8563P_H_
    #define PCF8563P_H_
     
    #define ADR_PCF8563P_R  0xA3
    #define ADR_PCF8563P_W  0xA2
     
    //adresy odpowiednich rejestrów
     
    #define RG_SECONDS              0x02
    #define RG_MINUTES              0x03
    #define RG_HOURS                0x04
    #define RG_DAYS                 0x05
    #define RG_WEEKDAYS             0x06
    #define RG_MONTHS               0x07
    #define RG_YEARS                0x08
     
    typedef struct{
            uint8_t seconds;        //sekundy
            uint8_t minutes;        //minuty
            uint8_t hours;          //godziny
            uint8_t days;           //dzien
            uint8_t weekdays;       //dzien tygodnia
            uint8_t months;         //miesiac
            uint8_t years;          //rok
    }DS_PCF8563;
     
    extern volatile DS_PCF8563 callendar_rtc;               //zawiera kalendarz - odczytane dane z rtc
     
    void register_twi_start_pcf(void (*twi_callback)(void));                        //rejestracja funkcji start z i2c
    void register_twi_stop_pcf(void (*twi_callback)(void));                         //rejestracja funkcji stop z i2c
    void register_twi_write_pcf(void (*twi_callback)(uint8_t bajt));        //rejestracja funkcji zapisującej do i2c
    void register_twi_read_pcf(uint8_t (*twi_callback)(uint8_t ack));       //rejestracja funkcji odczytującej z i2c
     
     
    uint8_t rtc_write_date(void);                                   //zapisuje dane do rtc, które znajduja sie w callendar_rtc. Zwraca 1 gdy wszystko OK
    uint8_t rtc_refresh_date(void);                                 //odswieza date i godziny w callendar_rtc. Zwraca 1 gdy wszystko OK
     
     
    #endif /* PCF8563P_H_ */

Plik nagłówkowy *.h

    /*
     * pcf8563p.c
     *
     *  Created on: 08-05-2014
     *       Edited on: 11-05-2014
     *      Author: Daniel
     *
     *
     *      Przy pomocy książki:
     *                                                      Mikrokontrolery AVR
     *                                                      Język C - podstawy programowania
     *
     *                                                                                                                      Autor:
     *                                                                                                                              Mirosław Kardaś
     *
     *      UWAGA!!
     *              Koniecznie na początku programu nalezy zarejestrowac funkcji do startu, stopu odbierania i wysylania
     *              danych po i2c (TWI). Dokonuje się to przy uzyciu funkcji:
     *                      register_twi_start_pcf( );                      //rejestracja funkcji start z i2c
     *                      register_twi_stop_pcf( );                               //rejestracja funkcji stop z i2c
     *                      register_twi_write_pcf( );      //rejestracja funkcji zapisującej do i2c
     *                      register_twi_read_pcf( );       //rejestracja funkcji odczytującej z i2c
     *
     *              Odczyt danych z rtc dokonuje się z callendar_rtc po wczesniejszym wywolaniu funkcji rtc_refresh_data()
     *              Zapis danych do rtc dokonuje się poprzez wywolanie funkcji rtc_write_data(), powczesniejszym wpisaniu
     *              zadanych danych do callendar_rtc
     *
     */
     
     
    #include <avr/io.h>
    #include <avr/pgmspace.h>
     
    #include "pcf8563p.h"
     
    volatile DS_PCF8563 callendar_rtc;              //zawiera kalendarz
     
    //-----*****+++++       funkcje widoczne tylko wewnątrz biblioteki
     
    // konwersja liczby dziesiętnej na BCD
    uint8_t dec2bcd(uint8_t dec) {
    return ((dec / 10)<<4) | (dec % 10);
    }
     
    // konwersja liczby BCD na dziesiętną
    uint8_t bcd2dec(uint8_t bcd) {
        return ((((bcd) >> 4) & 0x0F) * 10) + ((bcd) & 0x0F);
    }
     
    //rejestracje funkcji z i2c
     
    static void (*pcf_twi_start)(void);
    static void (*pcf_twi_stop)(void);
    static void (*pcf_twi_write)(uint8_t bajt);
    static uint8_t (*pcf_twi_read)(uint8_t bajt);
     
    void register_twi_start_pcf(void (*twi_callback)(void)){
            //rejestracja funkcji start z i2c
            pcf_twi_start = twi_callback;
    }
     
    void register_twi_stop_pcf(void (*twi_callback)(void)){
            //rejestracja funkcji stop z i2c
            pcf_twi_stop = twi_callback;
    }
     
    void register_twi_write_pcf(void (*twi_callback)(uint8_t bajt)){
            //rejestracja funkcji zapisującej do i2c
            pcf_twi_write = twi_callback;
    }
     
    void register_twi_read_pcf(uint8_t (*twi_callback)(uint8_t ack)){
            //rejestracja funkcji odczytującej z i2c
            pcf_twi_read = twi_callback;
    }
     
     
    //-----*****+++++       funkcje widoczne na zewnatrz
     
    //--**zapis do rtc
    uint8_t rtc_write_date(void){
            //zapisuje dane do rtc, które znajduja sie w callendar_rtc. Zwraca 1 gdy wszystko OK, 0 gdy nie
     
            if(!pcf_twi_read || !pcf_twi_write || !pcf_twi_start || !pcf_twi_stop) return 0;        //jezeli nie zostaly zarejestrowane odpowiednie funkcje
     
            uint8_t temp = dec2bcd(callendar_rtc.seconds);  //odczyt z struktury sekund i konwersja na bcd
     
            pcf_twi_start();
            pcf_twi_write(ADR_PCF8563P_W);                  //wyslanie adresu na i2c
            pcf_twi_write(RG_SECONDS);                              //zapis rozpoczynamy od sekund
            pcf_twi_write(temp);                                    //wyslanie wartoscie sekund po pcf w formacie bcd
            temp = dec2bcd(callendar_rtc.minutes);
            pcf_twi_write(temp);
            temp = dec2bcd(callendar_rtc.hours);
            pcf_twi_write(temp);
            temp = dec2bcd(callendar_rtc.days);
            pcf_twi_write(temp);
            temp = dec2bcd(callendar_rtc.weekdays);
            pcf_twi_write(temp);
            temp = dec2bcd(callendar_rtc.months);
            pcf_twi_write(temp);
            temp = dec2bcd(callendar_rtc.years);
            pcf_twi_write(temp);
            pcf_twi_stop();                                                 //procedura stop
     
            return 1;
    }
     
    //--**odswiezenie danych z rtc (odczyt z rtc)
    uint8_t rtc_refresh_date(void){
            //odswieza date i godziny w callendar_rtc. Zwraca 1 gdy wszystko OK
     
            if(!pcf_twi_read || !pcf_twi_write || !pcf_twi_start || !pcf_twi_stop) return 0;        //jezeli nie zostaly zarejestrowane odpowiednie funkcje
     
            uint8_t temp=0;
     
            pcf_twi_start();                                                //procedura start
            pcf_twi_write(ADR_PCF8563P_W);                  //adres pcf
            pcf_twi_write(RG_SECONDS);                              //odczyt zaczynamy od sekund
            pcf_twi_start();                                                //wyslanie ponownie startu
            pcf_twi_write(ADR_PCF8563P_R);                  //adres pcf ale tym razem jako odczyt
     
            //odczyt sekund i zamaskowanie najstarszego bitu
            temp = pcf_twi_read(1) & 0x7f;
            //konwersja z bcd i zapis do callendar rtc
            callendar_rtc.seconds = bcd2dec(temp);
     
            //odczyt minut i zamaskowanie najstarszego bitu
            temp = pcf_twi_read(1) &; 0x7f;
            //konwersja z bcd i zapis do callendar rtc
            callendar_rtc.minutes = bcd2dec(temp);
     
            //odczyt godzin i zamaskowanie
            temp = pcf_twi_read(1) & 0x3f;
            //konwersja z bcd i zapis do callendar rtc
            callendar_rtc.hours = bcd2dec(temp);
     
            //odczyt dnia i zamaskowanie
            temp = pcf_twi_read(1) & 0x3f;
            //konwersja z bcd i zapis do callendar rtc
            callendar_rtc.days = bcd2dec(temp);
     
            //odczyt dnia tygodnia i zamaskowanie
            temp = pcf_twi_read(1) & 0x07;
            //konwersja z bcd i zapis do callendar rtc
            callendar_rtc.weekdays = temp;
     
            //odczyt miesiaca i zamaskowanie najstarszego bitu
            temp = pcf_twi_read(1) & 0x1f;
            //konwersja z bcd i zapis do callendar rtc
            callendar_rtc.months = bcd2dec(temp);
     
            //odczyt roku
            temp = pcf_twi_read(0);
            //konwersja z bcd i zapis do callendar rtc
            callendar_rtc.years = bcd2dec(temp);
     
            pcf_twi_stop();
     
            return 1;
    }

Obsługa biblioteki sprowadza się do:

1) Rejestracji podstawowych funkcji magistrali TWI (I2C):

register_twi_start_pcf(twi_start);
register_twi_stop_pcf(twi_stop);
register_twi_read_pcf(twi_read);
register_twi_write_pcf(twi_send);

Dzięki temu program działa z każdą poprawnie napisaną biblioteką do obsługi I2C (TWI).
Argumenty które są przekazywane do tych funkcji są również funkcjami, które odpowiadają za start, stop, odczyt i zapis danych po magistrali TWI.

2) Aktualizacji odczytanych danych poprzez wywołanie funkcji:

rtc_refresh_date();

Funkcja ta odczytuje z naszego RTC czas oraz datę i zapisuje ją do odpowiednich rejestrów.

3) Odczytu danych poprzez użycie zmiennej callendar_rt, np.;

uint8_t godzina, minuta;
godzina = callendar_rtc.hours;
minuta = callendar_rtc.minutes;

Dla „wyciągnięcia:” reszty danych dotyczących czasu i/lub daty postępujemy podobnie jak zostało przedstawione w przykładzie

4) Zapisania/zaktualizowania danych w RTC, poprzez wpisanie nowych danych do zmiennej callendar_rtc, np.:

callendar_rtc.hours = 11;
callendar_rtc.minutes = 30;

Następnie należy wysłać danej do układu RTC poprzez wywołanie funkcji:

rtc_write_date();

W razie jakichkolwiek pytań, wątpliwości piszcie używając formularzu kontaktowego.


Dodano 2 listopada 2016r.

Pliki biblioteki zostały uzupełnione o możliwość konfiguracji przebiegu prostokątnego na wyjściu CLKOUT. Aby uaktywnić przebieg prostokątny należy wywołać funkcję:

pcf8563p_set_clkout(freq);

gdzie jako parametr należy podać wartość żądanej częstotliwości. W celu ułatwienia konfiguracji zostały stworzone odpowiednie makra, których nazwa wskazuje na odpowiednio wybraną częstotliwość:

CLKOUT_32768HZ	//częstotliwość 32.768kHz
CLKOUT_1024HZ	//częstotliwość 1.024kHz
CLKOUT_32HZ	//częstotliwość 32Hz
CLKOUT_1HZ	//częstotliwość 1Hz

wybrane makro, należy przekazać do wcześniejszej funkcji. Przykładowo, gdy chcemy uzyskać przebieg o częstotliwość 32Hz należy wywołać funkcję z parametrami:

pcf8563p_set_clkout(CLKOUT_32HZ);

Należy pamiętać o wcześniejszym zarejestrowaniu funkcji star,stop, write i read. W przypadku błędów, powyższa funkcja zwróci 0.

Zapraszam również do pobierania plików:

Plik główny:

Pobierz “pcf8563p.c”

pcf8563p.c – Pobrano 433 razy – 6,75 KB

Plik nagłówkowy:

Pobierz “pcf8563p.h”

pcf8563p.h – Pobrano 434 razy – 2,77 KB

Stare wersje:

Pobierz “pcf8563p.c”

pcf8563p.c – Pobrano 328 razy – 6,82 KB

Pobierz “pcf8563p.h”

pcf8563p.h – Pobrano 327 razy – 2,85 KB

6 Komentarzy

  1. Staszek

    Tego szukałem. Bardzo fajnie napisana biblioteka.
    Gratuluję!!

    1. danielos (Post autora)

      Dzięki. Mam nadzieję, że będziesz z niej zadowolony.

  2. komax

    Świetna biblioteka. Tylko szkoda, że nie ma obsługi alarmów.

  3. danielos (Post autora)

    Może pojawi się w przyszłości.
    Ewentualnie, jak opracujesz obsługę alarmów to podziel się nią;)

  4. MAREKHAB

    Biblioteka po prostu świetna, jednak moja wiedza jest zbyt znikoma i nie wiem jak dokładnie zarejestrować
    te funkcję. Próbowałem wkleić to z komentarza na samym początku pliku pcf8563p.c

    register_twi_start_pcf( ); //rejestracja funkcji start z i2c
    register_twi_stop_pcf( ); //rejestracja funkcji stop z i2c
    register_twi_write_pcf( ); //rejestracja funkcji zapisującej do i2c
    register_twi_read_pcf( ); //rejestracja funkcji odczytującej z i2c
    Nie mogę skompilować programu

    próbowałem jeszcze wkleić to
    register_twi_start_pcf( ); //rejestracja funkcji start z i2
    register_twi_stop_pcf( ); //rejestracja funkcji stop z i2c
    register_twi_write_pcf( ); //rejestracja funkcji zapisującej do i2c
    register_twi_read_pcf( ); //rejestracja funkcji odczytującej z i2c

    Albo w złym miejscu wklejam.
    Proszę o wytłumaczenie co i gdzie wpisać abym mógł zarejestrować te funkcję, jestem całkowitym nowicjuszem dlatego zwracam się o pomoc.

    1. danielos (Post autora)

      Po pierwsze musisz posiadać jeszcze bibliotekę do obsługi magistrali I2C (TWI), ponieważ ta biblioteka sama w sobie nie zawiera obsługi tej magistrali – a do niej jest podłączony PCF8563.

      Do tych funkcji musisz przekazać funkcje ze swojej biblioteki I2C (TWI), a dokładnie funkcje start, stop, read oraz write. Przykładowo jeżeli w swojej bibliotece masz funkcję void start_twi(void) musisz ją zarejestrować w ten sposób register_twi_start_pcf(start_twi);. Tak samo z stop, read oraz write. Przy czym biblioteka z której korzystasz powinna mieć napisaną funkcję odczytującą z magistrali dane w ten sposób aby przekazywana do niej była zmienna typu uint8_t (przy czym ta funkcji nic nie ma zwracać), a funkcja wysyłająca dane powinna zwracać typu uint8_t, oraz mieć możliwość przekazania do niej zmiennej typu uint8_t (możliwość przekazania do tej funkcji potwierdzenia – ack).

      Powodzenia!

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *