Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Solved] ATmega - obsługa zegara PCF8563p - język C

fifcio13-13 29 Sep 2019 11:06 582 6
  • #1
    fifcio13-13
    Level 30  
    Witam,
    1. Mam nie lada zagwozdkę z obsługą zegara PCF8563p przez Atmege32 + wyświetlacz LCD. Sam zegar działa dobrze. Poprawnie wpisuje datę i godzinę. Problem pojawia się z odczytem. W PCF ustawiam wyjście na 1Hz, które jest połączone z Atmegą jako przerwanie INT0. Co kilka razy, przy resecie uC, gdy program startuje od nowa, to czas zaczyna się niepoprawnie wyświetlać. Tj. najpierw wyświetlana jest wartość 02 sekundy, następnie 00, później 04, 00, 06, 00,...,10, 00, 12, itd. Problem dotyczy również przejścia minut i godzin. Próbowałem opóźnić odczyt po ustawieniu wyjścia PCF, ale to nie rozwiązuje problemu, również prosty odczyt w pętli z opóźnieniem nie pomaga. Właściwie próbowałem już wszędzie opóźniać program, ale chyba nie tędy droga.

    2. Zaczerpnąłem już pomocy w dziale programowanie, trochę pozmieniałem kod - wypisywanie na ekran wrzuciłem do pętli głównej, a nie jak to było wcześniej, w funkcjach. Została dodana flaga do LCD, ale nie działa tak jak powinna. Może ktoś zauważy jakiś błąd...

    3. Obsługa termometrów jest w tej chwili nieistotna - wywołanie funkcji zakomentowane.

    4. Mam jeszcze jeden problem. Obecnie ATmega chodzi na 8Mhz z zegara wewnętrznego. Chciałem ją popędzić, ale z kwarcem zewnętrznym powyżej 10MHz już się zawiesza. Nie wiem co jest przyczyną. Tak ustawiam fusy:
    ATmega - obsługa zegara PCF8563p - język C

    Poniżej zamieszczam kod. Proszę o jakieś sugestie.
    Code: c
    Log in, to see the code
  • #2
    szelus
    Level 34  
    1. Skąd wziąłeś bibliotekę do PCF?
    2. Jak masz podłączony ten kwarc?
  • Helpful post
    #3
    ex-or
    Level 27  
    Na początek kwestia formalna: jest za dużo tabulatorów w kodzie przed komentarzami, przez to prawa strona posta oraz kodu jest ucinana na ekranie (mam mały ekran).
    Co do kodu: czytanie zegarka oraz formatowanie sprintfem w procedurze obsługi przerwania jest mocno słabe. Diabli wiedzą jak jest zrealizowany lib TWI. Jakby był oparty na przerwaniach to by w tej sytuacji w ogóle nie działał. Ale jakoś działa więc pewnie zwykły polling. Jednak potencjał całkowitego zablokowania programu jest wysoki jeśli lib nie ma jakiejś reakcji na błędy (a pewnie nie ma). Sprawa nr dwa to czas jaki te dwie operacje zajmują. Co prawda nie sądzę, żeby nastąpiło gubienie przerwań (1s to jednak bardzo długi okres czasu dla µC) ale widać tam w nagłówkach header watchdoga więc być może dochodzi do watchdog resetu.
    Tak w ogóle nie wiem czy ma sens ciągle czytać czas z PCF. Ja bym raczej zrobił licznik czasu w procku, na starcie zrobił synchronizację z PCF (oraz dla zwiększenia niezawodności co jakiś czas np. co godzinę), a przerwania z PCF wykorzystał do inkrementowania licznika. Ale nie wiem, nie budowałem zegarków, może tak właśnie się robi?
  • #4
    fifcio13-13
    Level 30  
    Dziękuję za odpowiedzi. Co do tematu:
    szelus wrote:
    1. Skąd wziąłeś bibliotekę do PCF?

    Wykorzystałem sprawdzoną bibliotekę od DanieloS ze strony: Link
    szelus wrote:
    2. Jak masz podłączony ten kwarc?

    Pracuję na płycie EvB 4.3, nigdy nie było problemu z kwarcem. Sam kwarc jest podłączony do XTAL1 i XTAL2 blisko uC, a z drugiej strony przez kondensatory 22pF do masy.

    ex-or wrote:
    czytanie zegarka oraz formatowanie sprintfem w procedurze obsługi przerwania jest mocno słabe

    Jak mogę to zastąpić?
    ex-or wrote:
    Diabli wiedzą jak jest zrealizowany lib TWI

    TWI napisałem sam, najprostsze jakie jest. Na końcu zamieszczam cały projekt.
    ex-or wrote:
    widać tam w nagłówkach header watchdoga więc być może dochodzi do watchdog resetu

    Dołączyłem, bo później chcę rozwinąć program i będzie mi potrzebny. Póki co zakomentowałem, ale nie wpływa to na błędy.
    ex-or wrote:
    Ja bym raczej zrobił licznik czasu w procku, na starcie zrobił synchronizację z PCF (oraz dla zwiększenia niezawodności co jakiś czas np. co godzinę), a przerwania z PCF wykorzystał do inkrementowania licznika.

    Jest to jakieś wyjście. Dzięki za fajny pomysł. Chociaż chciałbym jeszcze powalczyć z moim kodem. Gdy nie będzie już wyjścia, to zmienię podejście.

    Dołączam cały projekt:
    PCF DS18..0.rar Download (84.01 kB)
  • Helpful post
    #5
    ex-or
    Level 27  
    Spojrzałem w ten kod i niestety jest tam o wiele więcej problemów. Typowy kod początkującego, ale OK - każdy kiedyś zaczynał i pisał takie potworki ;-)
    Co można naprawić? Już Ci to mówili w innym wątku: przede wszystkim wywalić czasochłonne operacje z przerwania. W ISR ustawiasz tylko flagę, a w pętli głównej sprawdzasz jej stan i, jeśli zachodzi warunek, czytasz zegar i aktualizujesz LCD. A więc funkcja get_time() idzie do warunku if(flaga == true). Nie ma gwarancji że sekundy nie będą "przeskakiwać" ale jeśli nawet to powinny sporadycznie.
    To samo z funkcją get_temp - w tej postaci w żadnym wypadku nie może być w ISR. Poza tym jej odpalanie co sekundę jest bez sensu. Odczyt temperatury można zrobić np. co minutę i też będzie dobrze. A więc w tym przypadku robisz timer programowy (widać że masz książkę Kardsia więc wiesz co to jest ;-)) który z pętli głównej zainicjuje konwersję, odczyta wynik i wyśle na LCD.
    Funkcja get_temp, IMO, nie może pozostać w takiej postaci. Przede wszystkim blokowanie przerwań jest za długie. W protokole one wire krytyczne czasowo są tylko długości bitów (a właściwie początki bitów) a więc blokowanie przerwań trzeba zrobić nie na poziomie funkcji get_temp tylko funkcji czytających i piszących bit. To raz. Dwa, że funkcję trzeba rozbić na dwie - inicjującą konwersję i drugą odczytującą czujnik po uplywie zadanego czasu konwersji. Sprawdzanie statusu kownwersji w pollingu nie ma w tym przypadku sensu bo nic nie daje a tylko niepotrzebnie blokuje program. Najdłuższy czas konwersji to wg dataszitu 750ms, ustawić taki odstęp między startem konwersji i odczytem i będzie OK (ale nie jakimś lewym delayem tylko timerem programowym)
    To tyle jeśli chodzi o najgrubsze kiksy.
  • #6
    fifcio13-13
    Level 30  
    Aaa, już rozumiem. W poprzednim wątku źle zrozumiałem obsługę flag. Myślałem, że w przerwaniu ma być wywołanie funkcji i pod koniec funkcji ustawienie flagi na wyświetlacz. Przez to miałem problem z obsługą tego. Teraz już wiem... Wstawię flagę w przerwanie, tak jak dobrze radzisz.

    Co do funkcji get_temp - oczywiście odczyt temperatury będzie docelowo co 60s z obu czujników, a nie naprzemiennie. Niestety obsługa dwóch naraz opóźniała mi zegar i musiałem jakoś obejść ten problem (int i). Timera nie będę musiał używać, ponieważ co minutę do uC będzie przychodziło przerwanie z USART wraz z innymi informacjami do przetworzenia.

    Książki Kardasia jeszcze nie mam :P ale umiem szukać i wykorzystywać zdobytą wiedzę. Ważne że cokolwiek działa. Jak już mam chwile zwątpienia, to wtedy szukam tutaj pomocy.

    W tym tygodniu spróbuję poprawić kod i dam znać. Jeszcze raz dzięki za pomocne wskazówki.
  • #7
    fifcio13-13
    Level 30  
    Poprawiłem kod uwzględniając wszystkie porady, za które serdecznie dziękuję. Jest minimalnie lepiej, lecz wywnioskowałem, że zegar PCF nie nadaje się do ciągłego odczytywania czasu. Zmieniam sposób podejścia. Docelowo czas będzie odświeżany co 60 sekund. W przyszłości planuję zrobić też normalny zegar, ale wykorzystam do tego wewnętrzne timery i czas będę aktualizował np. co 24 godziny.
    Pozdrawiam