Kanał - ATNEL tech-forum
Wszystkie działy
Najnowsze wątki



Teraz jest 17 gru 2018, o 15:57


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 9 ] 
Autor Wiadomość
PostNapisane: 10 paź 2018, o 15:28 
Offline
Nowy

Dołączył(a): 20 sty 2016
Posty: 3
Pomógł: 0

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?



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 paź 2018, o 16:19 
Online
Moderator
Avatar użytkownika

Dołączył(a): 03 paź 2011
Posty: 23771
Lokalizacja: Szczecin
Pomógł: 897

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.

_________________
zapraszam na blog: http://www.mirekk36.blogspot.com (mój nick Skype: mirekk36 ) [ obejrzyj Kurs EAGLE ] [ mój kanał YT TV www.youtube.com/mirekk36 ]



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 paź 2018, o 16:20 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 429
Pomógł: 100

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.

_________________
Miksowanie kodu C i ASM przy użyciu GCC



Ostatnio edytowano 10 paź 2018, o 16:23 przez andrews, łącznie edytowano 1 raz

Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 paź 2018, o 16:22 
Online
Moderator
Avatar użytkownika

Dołączył(a): 03 paź 2011
Posty: 23771
Lokalizacja: Szczecin
Pomógł: 897

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

_________________
zapraszam na blog: http://www.mirekk36.blogspot.com (mój nick Skype: mirekk36 ) [ obejrzyj Kurs EAGLE ] [ mój kanał YT TV www.youtube.com/mirekk36 ]



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 paź 2018, o 16:58 
Offline
Nowy

Dołączył(a): 20 sty 2016
Posty: 3
Pomógł: 0

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?



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 paź 2018, o 17:14 
Online
Moderator
Avatar użytkownika

Dołączył(a): 03 paź 2011
Posty: 23771
Lokalizacja: Szczecin
Pomógł: 897

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

_________________
zapraszam na blog: http://www.mirekk36.blogspot.com (mój nick Skype: mirekk36 ) [ obejrzyj Kurs EAGLE ] [ mój kanał YT TV www.youtube.com/mirekk36 ]



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 paź 2018, o 17:45 
Offline
Nowy

Dołączył(a): 20 sty 2016
Posty: 3
Pomógł: 0

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 :)



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 paź 2018, o 17:53 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 429
Pomógł: 100

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.

_________________
Miksowanie kodu C i ASM przy użyciu GCC



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 10 paź 2018, o 19:11 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 22 paź 2013
Posty: 1532
Lokalizacja: Lipsko
Pomógł: 109

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 ;-)

_________________
http://www.sylwekkuna.com



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 9 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zidentyfikowanych użytkowników i 5 gości


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Skocz do:  
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO