Zmienne bitowe w AVR
- Aro
- Użytkownik
- Posty: 677
- Rejestracja: 30 paź 2006, 18:49
- Lokalizacja: Świerczyniec | Wrocław
- Kontakt:
Zmienne bitowe w AVR
Czy da się zmniejszyc rozmiar instrukcji wpisującej i odczytującej zmienne bitowe w C? Bo instrukcje typu
uint8_t zmienna ;
.........
zmienna |=(1<<2);
......
if(zmienna&(1<<2)).....
zajmują więcej pamięci flash niż ze zmiennymi bajtowymi, a znowu bajtowe więcej RAMu. Jest na to złoty środek?
uint8_t zmienna ;
.........
zmienna |=(1<<2);
......
if(zmienna&(1<<2)).....
zajmują więcej pamięci flash niż ze zmiennymi bajtowymi, a znowu bajtowe więcej RAMu. Jest na to złoty środek?
-
michalko12
- -
- Posty: 2
- Rejestracja: 14 sty 2007, 0:57
Re: Zmienne bitowe w AVR
Wybierając język w którym chce sie pisać program trzeba liczyć się z pewnymi kompromisami, albo łatwość i szybkość pisania programu albo zwiezły, oszczędny i szybki kod wynikowy. Od języka wysokiego poziomu nie mozna wymagac wszystkiego, w tych czasach zasoby w procesorach są tak duże ża na takie kwestie nie zwraca sie uwagi, jesli jest cos krytycznego to trzeba zejść na język niższego poziomu i robić np wstawki asemblerowe.
- Aro
- Użytkownik
- Posty: 677
- Rejestracja: 30 paź 2006, 18:49
- Lokalizacja: Świerczyniec | Wrocław
- Kontakt:
Zawsze myślałem że kompilatory C najlepiej przeprowadzają optymalizacje kodu. Jeśli w asemblerze są jakieś rozkazy porównania zmiennych bitowych to mógłbyś pokazac jak taki kod będzie wyglądac w asemblerze , byłbym wdzięczny. Przypominam jeszcze że nie chodzi o program komputerowy tylko o procesor AVR , bo obniosłem takie wrażenie czytając twój post. Nie zależy mi też na małym pliku źródłowym tylko na jak najmniejszym kodzie wynikowym i jak najmniejszej zajętości RAMu.
Aro - w asemblerze AVRków są polecenia związane z bitem T w rejestrze SREG...
Wykorzystać je można dość łatwo - wpierw ładujesz interesujący Ciebie bit ze zmiennej do T, sprawdzasz jaki ma stan, i wykonujesz skok do odpowiedniego miejsca w programie...
Wykorzystać je można dość łatwo - wpierw ładujesz interesujący Ciebie bit ze zmiennej do T, sprawdzasz jaki ma stan, i wykonujesz skok do odpowiedniego miejsca w programie...
Kod: Zaznacz cały
BST rejestr, numerbitu ;przepisanie bitu "numerbitu" z rejestru przechowującego zmienną
BRBS 6, adresskoku ;jeśli bit ma być ustawiony
BRBC 6, adresskoku2 ;jeśli bit ma być wyzerowany
- Aro
- Użytkownik
- Posty: 677
- Rejestracja: 30 paź 2006, 18:49
- Lokalizacja: Świerczyniec | Wrocław
- Kontakt:
I to mi sie podoba
Musze sie jeszcze upewnic czy w połączeniu z moim programem to będzie wyglądac tak?
Mam jeszcze pytanie czy tylko bit T można wykorzystac czy inne bity tego rejestru też można?
I jeszcze jak zrobic taką instrukcję: if(!((PINx &(1<<x)) || (instrukcja sprawdzająca bit)) ?
Kod: Zaznacz cały
//nie robiłem nigdy wstawek asemblerowych w C
//więc kod... to chyba nie jest poprawnie ale to tak tylko żeby było jakoś napisane
//uint8_t zmienna
LDI R19 , 0x00 //deklaracja zmiennej
OUT R19 , 2 //ustawienie drugiego bitu w zmiennej
BST R19 , 2 //przepisanie bitu do bitu T rejestru SREG
BRBS 6 , gdzieś // ->pod adres
....I jeszcze jak zrobic taką instrukcję: if(!((PINx &(1<<x)) || (instrukcja sprawdzająca bit)) ?
Inne NIE! Ten jeden jest przewidziany dla dowolnego wykorzystania...
Pozostałe odpowiadają za stan uP (bit I za włączenie przerwań).
Korzystając z C pamiętaj o zapamiętaniu rejestru przed obsługą wstawki asemblerowej, i przywróceniu po zakończeniu obsługi...
Co do samego "mieszania" C i asemblera - tu pomoże Tobie ktoś bardziej doświadczony (np: Tasza, Koppel, ZbeeGin)
Pozostałe odpowiadają za stan uP (bit I za włączenie przerwań).
Korzystając z C pamiętaj o zapamiętaniu rejestru przed obsługą wstawki asemblerowej, i przywróceniu po zakończeniu obsługi...
Co do samego "mieszania" C i asemblera - tu pomoże Tobie ktoś bardziej doświadczony (np: Tasza, Koppel, ZbeeGin)
A o jakim kompilatorze mowa? Bo wstawki asemblerowe trochę inaczej wyglądają w GCC, inaczej w Keilu... czy innych kompilatorach.
Czy taka wstawka na pewno będzie bardziej optymalna? Pominąwszy MCS51 bardzo mało współczesnych procesorów ma specjalny obszar obsługiwany bitowo. W asemblerze AVR istnieją operacje ustawiające / zerujące bity w przestrzeni wejścia wyjścia. Na przykład operacja:
PORTB |= 1<<3;
Zostanie zamieniona na jedną instrukcję. Natomiast czy działanie zostanie wykonane tak:
1. Wczytanie zmiennej do rejestru
2. Skopiowanie wybranego bitu do flagi T
3. Skok względem T
czy tak:
1. Wczytanie zmiennej do rejestru
2. Operacja AND ze stałą
3. Skok względem flagi zera
To będzie tyle samo kodu i tyle samo cykli. Ogólnie obsługa zmiennych bitowych w AVR zawsze będzie wolniejsza niż obsługa zmiennych bajtowych. Ale zwykle jest to kwestia jednej instrukcji więcej.

Czy taka wstawka na pewno będzie bardziej optymalna? Pominąwszy MCS51 bardzo mało współczesnych procesorów ma specjalny obszar obsługiwany bitowo. W asemblerze AVR istnieją operacje ustawiające / zerujące bity w przestrzeni wejścia wyjścia. Na przykład operacja:
PORTB |= 1<<3;
Zostanie zamieniona na jedną instrukcję. Natomiast czy działanie zostanie wykonane tak:
1. Wczytanie zmiennej do rejestru
2. Skopiowanie wybranego bitu do flagi T
3. Skok względem T
czy tak:
1. Wczytanie zmiennej do rejestru
2. Operacja AND ze stałą
3. Skok względem flagi zera
To będzie tyle samo kodu i tyle samo cykli. Ogólnie obsługa zmiennych bitowych w AVR zawsze będzie wolniejsza niż obsługa zmiennych bajtowych. Ale zwykle jest to kwestia jednej instrukcji więcej.
Niekoniecznie. W GCC podaje się we wstawce listę rejestrów traconych. Kompilator sam je zapisze i odzyska jeśli uzna, że mogą one zawierać potrzebne dane. Jest to o tyle fajna sprawa, że może się okazać, że reszta programu z naszego rejestru nie korzysta i nie trzeba go odzyskiwaćmarcing pisze:Korzystając z C pamiętaj o zapamiętaniu rejestru przed obsługą wstawki asemblerowej, i przywróceniu po zakończeniu obsługi...
Jak zwykle nie napisałem - jakiego rejestru... chodziło mi o SREG.Koppel pisze:W GCC podaje się we wstawce listę rejestrów traconych. Kompilator sam je zapisze i odzyska jeśli uzna, że mogą one zawierać potrzebne dane.
Chociaż nie wiem jak to w AVR-GCC wygląda...
Ale co do sprawdzania stanu bitu za pomocą AND - jak najbardziej się z tym zgadzam.
Nie wiem czy w jakimkolwiek kompilatorze C trzeba pamiętać jego stan. W obsłudze przerwania jest on zapisywany automatycznie, a w kodzie jego stan nie ma znaczenia pomiędzy poszczególnymi instrukcjami. Wstawki asemblerowej i tak nie umieszczamy przecież między jedną a drugą częścią dodawania dwóch liczb 16 bitowychmarcing pisze:chodziło mi o SREG
Ale piszę to jedynie po swoich doświadczeniach z GCC i niewielkich doświadczeniach z Keil'em.
- Aro
- Użytkownik
- Posty: 677
- Rejestracja: 30 paź 2006, 18:49
- Lokalizacja: Świerczyniec | Wrocław
- Kontakt:
To teraz przynajmniej wiem że prościej się nie da. Wyjde troche poza temat. Czy da się uprościc jednorazowe sprawdzenie naciśnięcia przycisku bez zatrzymywania programu?
Ja to robie w taki sposób: jest to dośc pamięciożerne zarówno FLASH jak i RAM. Jakby "sprawdz" kożystac z bitów to zajętośc RAM sie zmniejszy ale FLASH wzrośnie i to sporo.
Ja to robie w taki sposób:
Kod: Zaznacz cały
uint8_t sprawdz;
if(!((PINx &(1<<x)) || (sprawdz)))
{
sprawdz=1;
instrukcje
.....
}
if(PINx &(1<<x)) sprawdz=0;