Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATMega8][C] - Korzystanie z własnych flag

lego001 23 Mar 2013 13:32 1683 13
  • #1 23 Mar 2013 13:32
    lego001
    Poziom 9  

    Witam wszystkich!
    Napisałem program w którym wykorzystuje flagi do oznaczania np: obecności czujnika DS18B20, stanu przycisków czy też innych zdarzeń. Aby zaoszczędzić pamięć, zamiast użyć np. 8 zmiennych typu unsigned char (bo tyle potrzebuje flag) chciałem użyć tylko jednej zmiennej unsigned char i wykorzystać wszystkie jej 8 bitów.
    Oto fragment kodu:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Po wciśnięciu odpowiedniego klawisza uruchamia się funkcja void kropka(void) i wewnątrz niej 5 bit zmiennej flags powinien zostać ustawiony, co skutkuje stałym świeceniem się kropki na wyświetlaczu 7 segmentowym. Niestety kropka świeci się do czasu wyjścia z funkcji void kropka (void). Po opuszczeniu funkcji stan flagi jest niejako "gubiony". Sytuacja prezentuje się analogicznie w przypadku innych bitów zmiennej flags. Co ciekawe, gdy zachowam się "nieoszczędne" i zastosuje 8 osobnych zmiennych, program działa. Gdzie popełniłem błąd? Jak być powinno? Z góry dziękuję za odpowiedzi :)

    0 13
  • #2 23 Mar 2013 14:23
    excray
    Poziom 39  

    Czemu bajt flags nie jest volatile?

    0
  • Pomocny post
    #3 23 Mar 2013 14:44
    TQelektronik
    Poziom 10  

    Witam,
    jest

    Kod: c
    Zaloguj się, aby zobaczyć kod
    a powinno być
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #4 23 Mar 2013 15:21
    lego001
    Poziom 9  

    excray napisał:
    Czemu bajt flags nie jest volatile?

    volatile nic nie zmieniało, ale na wszelki wpadek poprawię to, żeby później nie było niespodzianek.

    TQelektronik napisał:
    Witam,
    jest
    Kod: c
    Zaloguj się, aby zobaczyć kod
    a powinno być
    Kod: c
    Zaloguj się, aby zobaczyć kod


    To pomogło :) Dzięki wielkie. Gdzieś u kogoś w programie widziałem właśnie taki zapis i na pierwszy rzut oka wydawało się być ok. Niestety to poskładało moją koncepcje flag :? Dzięki wam za pomoc.

    0
  • #6 23 Mar 2013 15:50
    tmf
    Moderator Mikrokontrolery Projektowanie

    No i jeszcze warto rozważyć użycie pól bitowych w strukturze. Dzięki temu kod będzie bardziej przejrzysty, a wyliczanie masek bitowych przerzucimy na kompilator. Można też taką strukturę umieścić w pamięci dostęnej przez cbi/sbi, dzięki czemu zmiana flagi odbywać się będzie atomowo i uniknie się problemó opisanych przez kolegę BlueDraco.

    0
  • #7 23 Mar 2013 16:27
    BlueDraco
    Specjalista - Mikrokontrolery

    No to jeszcze dodam, że na pamięCi danych w ten sposób oszczędzamy, ale odbywa się to kosztem wydłużenia kodu w porównaniu z sytuacją, gdy każdy znacznik byłby oddzielną zmienną typu _Bool. Przy takim zapisie nie byłoby też potrzebne blokowanie przerwań na czas modyfikacji, bo modyfikacja odbywałaby się przez pojedynczy zapis, a nie przez operacje logiczną, wymagającą dwóch dostępów do pamięci.

    Wybór oczywiście należy do programisty - ja sugerowałbym indywidualne zmienne logiczne, chyba, że pamięci RAM brakuje, a ROM mamy w nadmiarze.

    0
  • #8 23 Mar 2013 17:13
    lego001
    Poziom 9  

    BlueDraco napisał:
    Blokuj przerwania na czas modyfikacji tej zmiennej przez program główny!!!

    Jakie niepożądane skutki może przynieść brak blokady przerwań?

    Jeśli chodzi o pola bitowe, to zastosowanie ich zmniejszy zapotrzebowanie na pamięć, ale spowolni działanie programu z powodu wolniejszego dostępu do danych?

    kolega BlueDraco napisał jeszcze, że:
    BlueDraco napisał:
    w porównaniu z sytuacją, gdy każdy znacznik byłby oddzielną zmienną typu _Bool. Przy takim zapisie nie byłoby też potrzebne blokowanie przerwań na czas modyfikacji, bo modyfikacja odbywałaby się przez pojedynczy zapis, a nie przez operacje logiczną, wymagającą dwóch dostępów do pamięci.

    Może kolega napisać przykład takiego zapisu? Nie bardzo rozumiem "zmienną typu _Bool" W C nie ma jako takich zmiennych typu bool. Są w C++. Trochę się pogubiłem, a jestem wybitnie początkujący.

    0
  • #9 23 Mar 2013 18:10
    tmf
    Moderator Mikrokontrolery Projektowanie

    Jeśli nie zablokujesz przerwań na czas dostępu do flag z poziomu aplikacji, to jeśli ta sama komórka pamięci będzie modyfikowana z poziomu handlera przerwania, to zawartość zmiennej się całkowicie "rozjedzie". Dlatego, że operacje te nie będą atomowe. Problem rozwiąże umieszczenie zmiennej w obszarze dostępnym dla cbi/sbi, bo wtedy zmiana stanu flagi będzie atomowa. Ale już jak pisze kolega BlueDraco operacje logiczne wymagające sekwencji RMW (read-modify-write) atomowe ciągle nie będą. Więc na czas ich wykonania trzeba zablokować przerwania.
    Przy okazji dostęp do takiej zmiennej, która de facto jest polem bitowym będzie wolniejszy, bo kompilator musi ją odczytać, zamaskować odpowiedni bit, zmienić jego stan i zapisać nową wartość. Ale znowu - tylko jeśli zmienna będzie w obszarze SRAM, jeśli będzie w obszarze IO dostęnym dla cbi/sbi to dostęp będzie nawet szybszy.

    0
  • #10 23 Mar 2013 18:17
    BlueDraco
    Specjalista - Mikrokontrolery

    Brak blokady przerwań przynosi takie niepożądane skutki, jakie właśnie obserwujesz - samoczynne przestawianie bitów.

    Użycie pól bitowych spowolni działanie, ale przede wszystkim wydłuży kod.

    W C są zmienne typu _Bool! Używam ich we wszystkich programach. Jeśli masz stary kompilator, który nie ma typu _Bool - użyj uint8_t - dokładnie na to samo wyjdzie. Znacznik zajmie bajt, ale do zapisu znacznika wystarczy instrukcja x = 1 lub x = 0, która jest zwykłym, pojedynczym zapisem do pamięci.

    0
  • #11 24 Mar 2013 01:15
    lego001
    Poziom 9  

    Kompilator mam raczej aktualny, a mianowicie Atmel Studio 6. Po prostu nie wiedziałem o typie _Bool dla C. Jeszcze sporo nauki przede mną :)
    Co do umieszczania danych w obszarze IO i instrukcji cbi/sbi, to nie bardzo wiem jak to wykorzystać. Zastosuje chyba rozwiązanie ze zmiennymi _Bool. Wtedy zamiana wartości odbywał by się w jednej instrukcji, jeśli dobrze rozumiem.
    BlueDraco, tak w ogóle, to czekam na rozwinięcie "smoczych zasad". W punkcie 1.7 mam nadzieję omówisz zagadnienia które poruszałeś wraz z Kolegą tmf. Podejrzewam, że skorzysta z tego wielu początkujących, takich jak ja :)

    0
  • #12 24 Mar 2013 08:57
    tmf
    Moderator Mikrokontrolery Projektowanie

    Typ bool masz też zdefiniowany w stdbool.h. Zdefiniowanie zmiennej jako bool czy _Bool nie spowoduje, że dostęp do niej będzie w jednej instrukcji. AVR nie ma po prostu takich instrukcji. Chyba, że to nowy rdzeń XMEGA, ale nawet wtedy odpowiednie operacje trzeba by zrealizować jako makra/funkcje w asemblerze.

    0
  • #13 24 Mar 2013 09:46
    BlueDraco
    Specjalista - Mikrokontrolery

    tmf: ponieważ typ _Bool jest implementowany jak uint8_t, czyli w postaci bajtu, nie ma żadnego powodu, by nie dało się pojedynczej zmiennej tego typu ustawić pojedynczą instrukcją procesora - i tak się to robi.

    Oczywiście można też zadeklarować spakowaną strukturę, np. { _Bool f1:1, f2:1} - wtedy będziemy mieli znaczniki bitowe, a typowy procesor do modyfikacji pojedynczego znacznika będzie używał operacji logicznej (o ile nie ma on na to lepszego sposobu). Wtedy trzeba blokować przerwania.

    lego001: rozwinięcie p. I.7 jest gotowe i czeka na publikację.

    0
  • #14 24 Mar 2013 10:08
    tmf
    Moderator Mikrokontrolery Projektowanie

    Tak, masz rację, po prostu przyjąłem, że typową operacją będzie if(flaga) flaga=cośtam. Spakowana struktura będzie dawała dokładnie to samo, po warunkiem, że będzie w obszarze dostępnym dla cbi/sbi, część AVR ma wydzielone rejestry GPIOR, w części do tego celu można wykorzystać rejestry układów peryferyjnych, których zmiana nie pociąga żadnych konsekwencji. To drugie jest o tyle lepsze, że cbi/sbi operują na wskazanym rejestrze IO i jest to jedna instrukcja. Dla bool zawsze będzie to załadowanie rejestru + jego zapis, a więc para LDI/STS. Oczywiście jeśli modyfikujemy bez sprawdzenia nie będzie miało znaczenia, że to nie jest operacja atomowa.

    0