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



Teraz jest 23 sty 2026, o 04:35


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 9 ] 
Autor Wiadomość
PostNapisane: 11 gru 2016, o 00:14 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 02 kwi 2014
Posty: 150
Pomógł: 1

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


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


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




Powyższe funkcje wykonywane są w programie głównym
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


a ich wywołanie uzależnione jest od przerwania
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.



I teraz clou całej sprawy:
W momencie wywołania powyższych funkcji (zmienna ze struktur LED_timer == 0) dla wszystkich struktur, zmienne tych struktur kopiują się i wszystkie diody zaczynają jednocześnie mrugać. Czym to jest spowodowane?
Czy może to być wina/przyczyna, że np dla struktury chimney wykonujemy pierwszą funkcję (select_set_colors_rgb) - czyli cała struktura oraz funkcja są na stosie - a w trakcie tej operacji zostaje spełniony warunek dla struktury window_left i zostaje wywołana ta sama funkcja, w efekcie zmienne z wywołanych funkcji nakładają się na siebie i zapisują te same wartości do różnych struktur ?



Ostatnio edytowano 11 gru 2016, o 11:01 przez amilo_pa, łącznie edytowano 1 raz

Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 11 gru 2016, o 10:07 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 563
Pomógł: 143

amilo_pa napisał(a):
Powyższe funkcje wykonywane są w programie głównym
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Na podstawie pokazanych fragmentów nie widać dokładnie, jak to masz zrobione, ale zwrócę uwagę, że wszelkiego rodzaju dostęp do zmiennej wielobajtowej, współdzielonej pomiędzy przerwaniami a pętlą główną programu powinien odbywać się atomowo, czyli w pętli głównej na czas operacji porównania lub przypisania należy wyłączyć globalne zezwolenie na przerwania (np. używając makra ATOMIC_BLOCK), czyli przykładowo:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Trudno ocenić na podstawie tych fragmentów, czy nie ma innych błędów, ale od tego bym zaczął, ponieważ jeśli tak nie zrobiłeś, zachowanie programu może być nieprzewidywalne.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 11 gru 2016, o 12:38 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 02 kwi 2014
Posty: 150
Pomógł: 1

@andrews Czyli polega to na tym, że w momencie porównania if(!chimney.LED_timer) nie może wystąpić przerwanie od Timera2, dobrze rozumiem zastosowanie flagi atomowej?

Nie wiem czy dobrze to zrobiłem, mógłbyś rzucić okiem?

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


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


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




Wczoraj pobawiłem się trochę programem i zrobiłem po trzy kopie funkcji select_set_colors_rgb oraz flow_colors_rgb (oczywiście lekko zmodyfikowałem ich nazwy) i każdą z kopi wywołuję w main.c
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Efektem tego jest poprawne działanie programu (tzn. działanie programu wg moich założeń)



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 11 gru 2016, o 16:15 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 563
Pomógł: 143

amilo_pa napisał(a):
Czyli polega to na tym, że w momencie porównania if(!chimney.LED_timer) nie może wystąpić przerwanie od Timera2

Dokładnie o to chodzi, jednak nie tylko w momencie porównania, ale także w trakcie przypisania wartości chimney.LED_timer=chimney.timer_set;.

Oczywiście ta zasada nie dotyczy tylko tego konkretnego przypadku. Zawsze kiedy zmienna składająca się z więcej niż jednego bajtu (w mikrokontrolerach 8-bitowych) jest używana zarówno w przerwaniu, jak i w głównej pętli programu należy zapewnić do niej atomowy dostęp. Nie trzeba tego robić wewnątrz procedury obsługi przerwania, ponieważ wtedy globalna flaga zezwalająca na przerwania jest wyłączona, chyba że programista ją sam świadomie włączy, ale to już inna historia :)

Niestety nie mam czasu na szczegółową analizę całego kodu. Zakładam, że skoro działa poprawnie to znaczy, że jest OK. Wydaje mi się, że czasami może niepotrzebnie komplikujesz pewne sprawy, ale to się na pewno zmieni, jak zdobędziesz praktykę :)

Podam jeden przykład. Nie chodzi o to, że to błąd, chodzi tylko o poprawę czytelności (i być może szybkości wykonania).
Mógłbyś w strukturze TLED_RGB zamiast indeksu funkcji użyć wskaźnika do niej. Wprawdzie spowodowałoby to zwiększenie rozmiaru struktury o 1 bajt (nie masz przecież tych zmiennych dużo), jednak wywołanie odpowiedniej funkcji:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

W tej chwili masz tylko dwie funkcje do wyboru, ale jak wyglądałoby Twoje wywołanie, gdyby ich było np. 10?

No ale tak jak napisałem, z czasem na pewno do tego dojdziesz :)



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 11 gru 2016, o 17:33 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 02 kwi 2014
Posty: 150
Pomógł: 1

ok, teraz rozumiem i dziękuję za informacje:)

Program działa poprawnie, ale ze zdublowanymi funkcjami (do każdej struktury TLED_RGB utworzyłem osobną funkcje która wykonuje to samo więc nie jest to optymalny sposób) :/ a dodanie ATOMIC_BLOCK(ATOMIC_RESTORESTATE) nie przyniosło pożądanego efektu :/

Nie za bardzo rozumiem zapis tego kodu window_left.chosen_function(&window_left); i jak ma to wywoływać odpowiednią funkcję :/ możesz coś rozjaśnić? Z góry dziękuję :)



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 11 gru 2016, o 19:36 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 563
Pomógł: 143

amilo_pa napisał(a):
dodanie ATOMIC_BLOCK(ATOMIC_RESTORESTATE) nie przyniosło pożądanego efektu

Nawet jeśli, to uwierz mi, że to nie jest jakieś moje "widzimisię", tak po prostu musi być, aby program działał prawidłowo.

Rozpatrzmy sobie sytuację:
  • Zmienna chimney.LED_timer jest równa 0x0100.
  • W celu sprawdzenia warunku if(!chimney.LED_timer) zmienna musi zostać załadowana do rejestrów.
  • Zostaje wczytany do rejestru najpierw młodszy bajt zmiennej, czyli 0x00.
  • W tym momencie następuje skok do procedury obsługi przerwania i zmienna jest dekrementowana, osiągając wartość 0x00FF.
  • Teraz program wraca do głównego programu i do następnego rejestru jest ładowany starszy bajt zmiennej, czyli w chwili obecnej 0x00.
W efekcie do kolejnych rejestrów została wpisana dwa razy wartość 0x00, czyli kopia całej zmiennej w rejestrach jest równa 0x0000 (warunek if(!chimney.LED_timer) jest spełniony), pomimo tego że w rzeczywistości wartość zmiennej wynosi 0x00FF, czyli program nie działa zgodnie z założeniem.

Oczywiście takie sytuacje nie muszą się zdarzać często, co powoduje, że błąd nie jest od razu widoczny, ale prędzej czy później takie sytuacje się zdarzą.

amilo_pa napisał(a):
Nie za bardzo rozumiem zapis tego kodu window_left.chosen_function(&window_left); i jak ma to wywoływać odpowiednią funkcję

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



Jeśli w tej chwili masz odrębne funkcje dla poszczególnych struktur, to być może przekazywanie argumentu w postaci wskaźnika do struktury będzie zbędne. Trzeba by było w takim przypadku odpowiednio zmodyfikować mój przykład.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 12 gru 2016, o 21:44 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 02 kwi 2014
Posty: 150
Pomógł: 1

@andrews siedzę już 2 godzinę i próbuje zrozumieć to co napisałeś i normalnie nie ogarniam :D totalny mindfuck :D Masz może jakiś zestaw ćwiczeń, który umożliwi mi zrozumienie tego kodu ? :P



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 13 gru 2016, o 08:38 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 563
Pomógł: 143

Chyba niepotrzebnie Ci namieszałem z tymi wskaźnikami na funkcje :), ale to bardzo typowa sytuacja, gdzie aż się prosi, żeby ich użyć, ponieważ to znacznie upraszcza kod.

Zasadniczo sprawa jest stosunkowo prosta. Zakładam, że ogólnie wiesz co to są wskaźniki. Tak samo, jak zmienną można odczytać (lub zmodyfikować) bezpośrednio za pomocą jej nazwy albo pośrednio, za pomocą wskaźnika (adresu w pamięci), tak samo funkcję można wywołać bezpośrednio, za pomocą jej nazwy albo pośrednio, za pomocą wskaźnika na tę funkcję. Funkcja przecież również znajduje się gdzieś w pamięci i musi posiadać swój adres.

Początkowo deklaracja takiego wskaźnika na funkcję może wydawać się nieco skomplikowana i niezrozumiała, ale jak już się zrozumie o co chodzi, staje się to proste. Zapewne w tym przypadku wygląda to jeszcze bardziej skomplikowanie, dlatego że wskaźnik nie jest osobną zmienną, tylko elementem struktury.

W tej chwili nie mam czasu tego opisywać, a poza tym to trochę za dużo pisania, żeby to szczegółowo wyjaśniać na forum. Jest na pewno sporo materiałów na ten temat w internecie, więc poczytaj i jak czegoś nie zrozumiesz to pytaj.

Słowa kluczowe to coś w stylu:
c wskaźnik na funkcję
lub
c function pointers



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 13 gru 2016, o 10:01 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 02 kwi 2014
Posty: 150
Pomógł: 1

Nie nie nie :) właśnie bardzo dobrze, że pokazałeś mi inny sposób i dałeś mi zagwozdkę :) to jest jedyny sposób żeby nauczyć się dobrze programować :) muszę przed świętami zakończyć ten projekt, ale zaraz po świętach ogarnę podesłany przez Ciebie kod i przerobię swój program na wzór tego kodu :)
Dziękuje za podpowiedzi :)



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 2 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:  
cron
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO