logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Atmega644pa - Timer1 nie odmierza równo 1 sekundy w trybie CTC

mumin_80 06 Wrz 2013 09:24 2913 15
REKLAMA
  • #1 12706846
    mumin_80
    Poziom 12  
    Witam
    Mam dziwny problem z konfiguracją timer1 w atmedze644pa w trybie CTC.
    Kod jest następujący:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    w main:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Układ jest taktowany kwarcem 11059200.
    Wartości TIMER1_OCR zmieniałem jeszcze doświadczalnie -+1 ale bez skutku.
    Wynik powyższego kodu jest następujący:

    23:16:08.009> X
    23:16:09.007> X
    23:16:10.255> X
    23:16:11.255> X
    23:16:12.440> X
    23:16:13.502> X
    23:16:14.687> X
    23:16:15.686> X
    23:16:16.871> X
    23:16:17.871> X
    23:16:19.118> X
    23:16:20.118> X
    23:16:21.302> X
    23:16:22.301> X

    Układ się zachowuje dzwnie, czasmi odlicza jedną sekundę a czasem wydłuża
    odliczanie o ok 200 ms.

    Może jakieś pomysły ? :)
  • REKLAMA
  • Pomocny post
    #2 12706872
    BlueDraco
    Specjalista - Mikrokontrolery
    Pomysł pierwszy: zapisz poprawny wzór na zawartość rejestru okresu OCR

    #define PERIOD (F_CLK / PRESCALER)

    Pomysł drugi: załaduj poprawną wartość:

    OCR1A = PERIOD - 1;

    Pomysł 3:
    Takie użycie przerwania kompletnie nie ma sensu. Wyłącz przerwanie i testuj znacznik timera z rejestru TIFR w pętli głównej.

    Pomysł 4:
    Zamiast printf użyj czegoś prostszego - np. wysyłania pojedynczego znaku.
  • #3 12706930
    mumin_80
    Poziom 12  
    Dzięki BlueDraco
    Wzór jest poprawany ale sprawdzę punkt 3-ci bo może tu coś wyjdzie.
    Problem też jest tej kwestii że ten mikrokontroler oprócz odlicznia jednej sekundy
    robi mnóstwo inny ważniejszych rzeczy, obsługuje moduł IP po SPI, robi odczyty/zapisy do NVRAM po I2C, wysyłanie informacji na dwa porty RS232.

    Może przyjąć inne podejscie, np timer ustawić na 50ms i zwiekszać licznik o 1, i gdy osiągnie wartość 20 to wywoływać funkcję do sprawdzania crona bo o to tu chodzi.

    Co do punktu 4-ego to co masz na myśli ?

    mumin
  • REKLAMA
  • Pomocny post
    #4 12707036
    BlueDraco
    Specjalista - Mikrokontrolery
    Podejrzewałem, że coś zajmuje czas uC, myślałem, że to może printf, ale skoro ujawniłeś, że uC "robi mnóstwo innych rzeczy", to tam szukaj przyczyny. po prostu coś zajmuje mu te 200 ms.
  • REKLAMA
  • #5 12730646
    mumin_80
    Poziom 12  
    Cześć
    Niestety nadal coś jest nie tak,
    Wgrałem poniższy kod do uC i problem nadal występuje.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Czyli kod ma za zadanie teoretycznie co sekundę wysłać X, niestety w praktyce jest inaczej.
    F_CPU 11059200.

    mumin_80
  • Pomocny post
    #6 12731266
    maly_elektronik
    Poziom 23  
    Pamiętaj że sama transmisja też swoje trwa :) a poza tym nie pokazałeś funkcji printf (może ona bawi się w _delay_ms() ?)

    Zauważ również że przerwanie występuje niezależnie od transmisji, może dochodzić do takiej sytuacji ze raz przerwanie zmienić Ci wartość zmiennej tuż przed transmisją a raz tuż po niej i to spowoduje Twoje opóźnienia. Spróbuj blokować przerwanie przed wysłaniem ciągu znaków i następnie je odblokuj uzyskasz wtedy równe interwały czasowe.

    Pamiętaj że zmienna stosowana poza przerwaniem musi mieć znacznik VOLATILE !
  • Pomocny post
    #7 12733107
    Fredy
    Poziom 27  
    Poza brakiem volatile nie bardzo rozumiem sens kasowania flagi cron_chk poza warunkiem?
    Jeśli cron_chk się ustawi akurat wtedy gdy będzie procesor wykonywał inną funkcję niż ten warunek to skasujesz ją i nie wyśle ci nic na RSa.
    I jeszcze jedno - jaka jest pewność że terminal ci nie wprowadza opóźnień i błędów czasowych ? Zamiast takiego testu co 1 sekundę, zrób sobie licznik np do 100 i wtedy sprawdz czy są błedy.
  • #8 12734829
    mumin_80
    Poziom 12  
    Racja Fredy, poza warunkiem nie powinno być flagi.
    Ustawienie volatile nie pomogło.

    Zamieszczam cały poprawiony kod:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    I wynik jego działania:

    14:20:25.471> X
    14:20:26.405> X
    14:20:27.342> X
    14:20:28.340> X
    14:20:29.276> X
    14:20:30.211> X
    14:20:31.147> X
    14:20:32.084> X
    14:20:33.099> X
    14:20:34.033> X
    14:20:34.969> X
    14:20:35.967> X

    Teraz widać że timer nie dochodzi do 1 sekundy.
    Fuse bity:


    Atmega644pa - Timer1 nie odmierza równo 1 sekundy w trybie CTC

    Brak mi pomysłów.
    Na terminal raczej bym nie stawiał.
    Funkcja printf jest standardowa i nie używa delay_ms.
    Teraz wygląda na to że timer nie dochodzi do 1 sekundy :(

    mumin_80
  • Pomocny post
    #9 12734897
    maly_elektronik
    Poziom 23  
    Możesz jeszcze wewnątrz przerwania spróbować przeładowywać rejestr OCR1A na zadaną wartość, gdzieś kiedyś się z tym spotkałem ale teraz nie mogę odnaleźć artykułu (pochodził chyba z AVRfreaks) :)
  • REKLAMA
  • Pomocny post
    #10 12734974
    tmf
    VIP Zasłużony dla elektroda
    mumin_80 napisał:

    14:20:25.471> X
    14:20:26.405> X
    14:20:27.342> X
    14:20:28.340> X
    14:20:29.276> X
    14:20:30.211> X
    14:20:31.147> X
    14:20:32.084> X
    14:20:33.099> X
    14:20:34.033> X
    14:20:34.969> X
    14:20:35.967> X

    Teraz widać że timer nie dochodzi do 1 sekundy.


    Ale te wartości markera czasowego pochodzą nie z programu lecz z systemu operacyjnego, tak? Więc włóż je sobie... :) OS (np. Windows) robi jednocześnie wiele rzeczy, obsługa USART nie jest akurat priorytetem. Od tego ma bufor, żeby znaków nie zgubić, ale kiedy je odbierze i obsłuży to trudno przewidzieć, bo to zależy od tego co jeszcze wykonuje. Żeby w Windows taki pomiar był wiarygodny, musiałbyś napisać driver systemowy, który doda marker natychmiast po odebraniu znaku, co w praktyce zawieszałoby cały system na czas transmisji. Jak chcesz sprawdzić czy timer zlicza sekundę (bo nie wierzysz nocie katalogowej) to sobie machaj pinem IO i podłącz np. oscyloskop. A jak nie masz to sobie ten kod odpal w symulatorze i sprawdzaj stan rejestrów timera.
  • #11 12748314
    mumin_80
    Poziom 12  
    Być może jest tak jak piszesz TMF ale to nie to.
    Teraz dodałem zmienną timer z wartościa 600 żeby uC wyrzucał po RS dane co 10 minut.
    Niestety nie ma pełnych 10 minut, jest raz mniej, raz więcej.

    Wynik dla TIMER1_OCR 10799
    22:17:55.187> START
    22:27:04.500> ON

    Wynik dla TIMER1_OCR 10801
    22:29:09.860> START
    22:38:19.547> ON
    22:47:29.917> ON
    22:59:33.101> ON

    Kod:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Ręce mi opadają :(
    Zakasałem rękawy i usiadłem do symulatora, nie jestem tu mocny ale zawsze coś, wyszło mi coś takiego:

    Wartość "Cycle Counter" - różnica pomiędzy "cycle counter" kiedy zmienia sie zmienna cron_chk, warunek "if(timer==0) { .... " wykasowany:

    15052 - start po inicjalizacji
    11061592 11061246
    22122838 11061250
    33184088

    Wydaje mi się że tu powinna być wartość F_CPU czyli 11059200.

    Help ... :)

    Print screen z symulatora w załaczniku.



    mumin_80
  • #12 12748766
    _Robak_
    Poziom 33  
    Po pierwsze, nie wysyłaj printf skoro chcesz odmierzać dokładnie. Po drugie, jeśli chcesz sprawdzić co jest nei tak to zapamiętaj w przerwaniu wartość licznika jaka jest w momencie przerwania i ją wyślij uartem. Po trzecie, zeruj licznik w przerwaniu. Po czwarte, musisz mieć dokładny kwarc/generator. Po piąte, używaj typedef i definicji zmiennych uint8_t itp..
  • #13 12749341
    mumin_80
    Poziom 12  
    Jeżeli mam nie korzytać z printf to z czego ?
    Druga sprawa, jeżeli z niego skorzystam raz na 10 minut to chyba nie wprowadzi to opóźnienia/przyspieszenia o aż 50 sekund. Bez przesady.

    Mogę zerować licznik ale w powyższym kodzie while zajmuje bardzo krótki czas więc wartość licznika nie wzrośnie dużo.

    mumin_80
  • #14 12749400
    maly_elektronik
    Poziom 23  
    Nigdzie nie znalazłem informacji na temat samego RS'a. Jest to przejściówka USB<->RS232 czy może sprzętowy RS232 komputera?
    Jeżeli to przejściówka choćby na układzie ft232 (bądź podobnym) czy też jakiegoś rodzaju inna przejściówka nie koniecznie TTL to wina będzie leżeć po stronie sterownika USB, który z pewnością magazynuje dany i w momencie "wolnej" chwili magistrali danych (czy nawet mostu) przesyła dane do obróbki. Możesz tu jedynie pokombinować nad pisaniem własnych wstawek bądź nawet sterowników zwiększających priorytet danych magistrali aczkolwiek w przypadku W7 musiałbyś podszywać się pod układ z dużym priorytetem (np master HDD) ale tu będzie problem z podpisami sprzętowymi...
    W przypadku sprzętowego RS'a czy masz dobrze dobrane kondensatory do MAX'a (bądź czegoś podobnego)?
  • #15 12749962
    mumin_80
    Poziom 12  
    Cachować dane rozumiem ale nie przez 50 sekund, litości....

    Tu jest przejściówka RS232->USB po FT232.

    mumin_80
  • #16 12750195
    BlueDraco
    Specjalista - Mikrokontrolery
    Powtórzę:

    - wyrzuć printf, wysyłaj pojedyncze znaki i sprawdź, co z tego wyjdzie; pomimo wielu sugestii upierasz się na używanie b. ciężkiego printf i strumieni stdin/stdut
    - sprawdź, czy masz dobrze ustawione bity konfiguracji do kwarcu
    - wyrzuć bezsensowne przerwanie timera, a w pętli głównej zamiast zmiennej cron_chk testuj i zeruj bit OCF1A.
REKLAMA