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:

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 KBPlik nagłówkowy:
Pobierz “pcf8563p.h”
pcf8563p.h – Pobrano 434 razy – 2,77 KBStare wersje:
Pobierz “pcf8563p.c”
pcf8563p.c – Pobrano 328 razy – 6,82 KBPobierz “pcf8563p.h”
pcf8563p.h – Pobrano 327 razy – 2,85 KB
Tego szukałem. Bardzo fajnie napisana biblioteka.
Gratuluję!!
Dzięki. Mam nadzieję, że będziesz z niej zadowolony.
Świetna biblioteka. Tylko szkoda, że nie ma obsługi alarmów.
Może pojawi się w przyszłości.
Ewentualnie, jak opracujesz obsługę alarmów to podziel się nią;)
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.
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!