ATNEL tech-forum
https://forum.atnel.pl/

Problem z timerem programowym
https://forum.atnel.pl/topic21404.html
Strona 1 z 1

Autor:  sildurian [ 10 paź 2018, o 15:28 ]
Tytuł:  Problem z timerem programowym

Cześć,
Robiłem projekt i musiałem wykorzystać timer programowy, niestety występowało nieregularne miganie diody, która powinna migać ze stały okresem. Chcąc sprawdzić o co chodzi napisałem uproszczony program do migania diodą i sprawdzić czy licznik sprzętowy działa poprawnie zmieniając stan wyjścia OC2. Timer sprzętowy okazuje się być ok. Problem jest wydaje mi się ze zmienną uint16_t. Atmega32 to 8 bitowy procesor i pewnie używa flagę przeniesienia. ustawiając wartość timera programowego na więcej niż 255 czyli tyle ile mieści jeden bajt zauważyłem, że wejście w warunek if występuje co 300 plus jeszcze 300-255. Co widać na zdjęciach z oscyloskopu.
Poniżej kod
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

testowane na zestawie atb 1.04b
Obrazek
zdjęcie 1. przerwanie co 100kHz, wartość Timer1 = 300, czyli co 3ms zmiana stanu pinu.
Obrazek
zdjęcie 2. przerwanie co 100kHz, wartość Timer1 = 300, czyli co 3ms zmiana stanu pinu, dodatkowo mamy zmianę stanu co około 46us
Obrazek
zdjęcie 3. przerwanie co 100Hz, wartość Timer1 = 300, czyli co 3s zmiana stanu pinu.
Obrazek
zdjęcie 4. przerwanie co 100Hz, wartość Timer1 = 300, czyli co 3s zmiana stanu pinu, dodatkowo mamy zmianę stanu co około 460ms, jednak nie zawsze, "czasem" działa, widać to po 3 prawidłowych zmianach stanu pinu.

Dla wartości Timer1 < 256 działa poprawnie, tak jak pisałem jest pewnie problem z caryflag. Dzieliłem już zmienną 16bit na dwie ale to nie pomogło.
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Dostałem coś takiego:
Obrazek
Jak sobie z tym radzić, co robię źle?

Autor:  mirekk36 [ 10 paź 2018, o 16:19 ]
Tytuł:  Re: Problem z timerem programowym

Jeśli to jest aż tak istotne to trzeba wprowadzić atomowość po prostu, czyli zamień linię:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


na taką postać:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Autor:  andrews [ 10 paź 2018, o 16:20 ]
Tytuł:  Re: Problem z timerem programowym

Nie zapewniasz atomowego dostępu atomowego dostępu do zmiennej wielobajtowej, używanej zarówno w przerwaniu, jak i w głównej pętli programu. Operacje na takiej zmiennej w mikrokontrolerach 8-bitowych, jak słusznie już sam zauważyłeś, potrzebują co najmniej dwóch taktów zegara. Jeśli pomiędzy tymi taktami wystąpi przerwanie, operacja na takiej zmiennej będzie niepoprawna. U Ciebie taka sytuacja jest to wysoce prawdopodobna, bo operacje na zmiennej Timer1 to większość kodu w pętli głównej.

Aby temu zapobiec, w programie głównym w momencie dostępu do takiej zmiennej należy wyłączać przerwania. Spróbuj zrobić na przykład coś w tym stylu:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


EDIT:
Widzę, że kolega Mirek mnie uprzedził, ale post może zostawię, bo chyba zapomniał o operacji porównania zmiennej Timer w warunku if.

Autor:  mirekk36 [ 10 paź 2018, o 16:22 ]
Tytuł:  Re: Problem z timerem programowym

sorki - jeszcze sprawdzanie wartości timera trzeba atomowo - ale to już andrews mnie ubiegł ;)

Autor:  sildurian [ 10 paź 2018, o 16:58 ]
Tytuł:  Re: Problem z timerem programowym

Dziękuję,
W międzyczasie doszedłem do czegoś takiego i efekt jest taki jak miałem wcześniej
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

teraz w warunku if operuję na zmiennych 8bitowych, a i tak problem jest taki sam, czyli rozumiem, że operacja zajmuje więcej taktów zegara i w momencie jak jest wykonywana operacja if może dojść do przerwania?

Autor:  mirekk36 [ 10 paź 2018, o 17:14 ]
Tytuł:  Re: Problem z timerem programowym

sildurian napisał(a):
i w momencie jak jest wykonywana operacja if może dojść do przerwania?

No toż przecież po to mówimy ci o atomowym podejściu ... tak oczywiście że chodzi o przerwania - a o cóż innego miałoby chodzić. Zarówno sprawdzanie jak i zapis trzeba robić atomowo i masz przykłady wyżej na to

Autor:  sildurian [ 10 paź 2018, o 17:45 ]
Tytuł:  Re: Problem z timerem programowym

dobra, doszedłem do właściwego dla mojego przypadku rozwiązania
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

inaczej zazwyczaj podczas sprawdzania warunku if wchodził w przerwanie,
Dziękuję za pomoc i pozdrawiam :)

Autor:  andrews [ 10 paź 2018, o 17:53 ]
Tytuł:  Re: Problem z timerem programowym

To nie ma znaczenia, czy użyjesz jednej zmiennej 16-bitowej, czy dwóch zmiennych 8-bitowych. Kiedy użyjesz zmiennej 16-bitowej, kompilator i tak musi rozbić to na dwie operacje 8-bitowe, bo to mikrokontroler 8-bitowy. I pomiędzy tymi operacjami nie może wystąpić przerwanie, które zmodyfikuje tę zmienną.

Podam Ci taki przykład:
  • wartość zmiennej Timer1 wynosi 255, czyli 0x00FF,
  • program dochodzi do momentu, kiedy wartość zmiennej Timer1 trzeba porównać z wartością 0 (mówię tu o instrukcji warunkowej if( !(Timer1) ),
  • nie można porównać dwóch bajtów jednocześnie, bo mikrkontroler ma rejestry 8-bitowe, więc najpierw porównywany jest starszy bajt, który wynosi 0x00, czyli warunek jest spełniony,
  • teraz występuje przerwanie od timera, i zmienna zostaje powiększona o 1, czyli przyjmuje wartość 0x0100,
  • mikrokontroler wraca do wykonywania programu głównego, i porównuje teraz młodszy bajt (bo starszy przecież już porównał); teraz młodszy bajt (z liczby 0x0100) wynosi również 0x00, więc warunek znowu jest spełniony,
  • w związku z tym, że wynikiem porównaniu starszego bajtu z zerem była prawda i wynikeim porównania młodszego bajtu z zerem była prawda, mikrokontroler uznaje, że cała liczba jest równa zero, a przecież nie jest, bo wynosi 0x0100.

Wszystko byłoby dobrze, gdyby pomiędzy dwoma operacjami porównania nie wystąpiło przerwanie i nie zmodyfikowało zmiennej, bo wtedy drugie porównanie zwróciłoby fałsz i wszystko byłoby OK. Dlatego w momencie modyfikowania, czy też porównywania zmiennej wielobajtowej należy przerwania wyłączyć. Przykłady masz podane powyżej.

Można też zrobić tak, jak zrobiłeś, pod warunkiem, że wykonanie bloku instrukcji pomiędzy cli() a sei() nie będzie trwało zbyt długo. Należy zadbać o to, żeby wyłączenie przerwań trwało jak najkrócej. Dlatego podałem przykład z tworzeniem kopii zmiennej, bo to wyłącza przerwania tylko na kilka taktów. Twój sposób wyłączy zapewne na dłużej, choć w tym przypadku jeszcze nie będzie tragedii. Piszę o tym raczej, żebyś zapamiętał na przyszłość, bo gdyby w bloku instrukcji było jakieś wyświetlenie na LCD lub transmisja UART, wtedy Twój sposób nie jest dobry.

Autor:  SylwekK [ 10 paź 2018, o 19:11 ]
Tytuł:  Re: Problem z timerem programowym

Jeśli to stały czas i nie ma możliwości zmienić taktowania przerwań to ja w takich przypadkach wykorzystuje dodatkową flagę, która daje sygnał dla warunku w przerwaniach i to tam jest odświeżana wartość dla timera. Działa zawsze prawidłowo :) Natomiast w sytuacji gdy odliczany czas jest modyfikowany stosuje inna zmienną w przerwaniach, która np. wstępnie podzieli mi przez dwa i zamiast 300 wpisuje wtedy 150. Jest 8bit? No jeeest ;-)

Strona 1 z 1 Strefa czasowa: UTC + 1
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/