Aktyw Forum

Zarejestruj się na forum.ep.com.pl i zgłoś swój akces do Aktywu Forum. Jeśli jesteś już zarejestrowany wystarczy, że się zalogujesz.

Sprawdź punkty Zarejestruj się

dzielenie liczb w zapisie z uzupełnieniem do dwóch

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:
dzielenie liczb w zapisie z uzupełnieniem do dwóch

Postautor: Sławek5 » 21 lis 2005, o 06:36

Cześć.

Chciałem Was prosić o pomoc w rozwiazaniu takiego problemu.
Otóż mam czujnik temperatury, który podaje wynik z uzupełnieniem do dwóch.
Odczytuje ten wynik i potrzebuję podzielić tą wartość przez dwa.
I tu zaczynają sie kłopoty, bo jeśli mam np dziesiętnie -6 (a hex 0xFA) to po podzieleniu przez 2 wcale nie dostaję -3 (0xFD) tylko zupełnie inną liczbę. Jest tak jakby kompilator miał zamiast -6 liczbę dodatnią 250 i dopiero tą liczbę dzieli przez 2.

Jest to kompilator C dla AVR i zmienna jest deklarowana jaku signed char.

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 21 lis 2005, o 11:08

Moze takie coś na poczekaniu wymyślone:

temp - temperatura

Kod: Zaznacz cały

char div2(char temp) { unsigned char utemp=(unsigned char)temp; if((utemp & 0x80)==0) return temp/2; else { char x=(char)((utemp-0x80)/2); return x-64; } }


ZARAZ, ZARAZ.....
zasugerowałem się i wyprodukowałem powyższe. ale to nie jest konieczne. lczbę -3 (char) uzyskasz automatyczne dieląc -6 (char) przez 2. Musiałeś gdzieś rzutować na unsigned char itp.... Ten kod nie jest potrzebny!!!!
Zamieść swój kod.
Ostatnio zmieniony 21 lis 2005, o 12:35 przez a_antoniak, łącznie zmieniany 1 raz.

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 21 lis 2005, o 11:54

Czesć.
Dzięki za odp. sprawdzę czy dziala po południu.

A tak w ogóle to jak to jest z tym uzupełnieniem do dwóch.
Dlaczego inne sa obliczenia jak sie deklaruje liczbę ze znakiem oraz bez znaku.

Na czym polegaja takie obliczenia i traktownie takiej liczby ze znakiem.

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 21 lis 2005, o 12:32

Sprawdź. Ale myśle ze takie bawienie się jest niekonieczne. Zamieść swój kod - popatrzymy :).

Co tak naprawdę "widzi" komputer? Ano widzi ciągo zer i jedynek. Juz nawet organizacja w bajt i przypisywanie 8 bitom wartości 0...255 jest pewną interpretacją ciągu ośmiu zer/jedynek - po polsku nazywa się to NKB (Naturalny Kod Binarny). Kod U2 jest po prostu inną interpretacją ciągu iluś tam (np. ośmiu) zer/jedynek pozwalającą na zapis liczb całkowitych, także ujemnych. Inna interpretacja (jest ich wiele, najpopularniejsza to bodaj IEEE754) pozwala zapisywać pewne liczby rzeczywiste zmiennoprzecinkowe (floating point numbers) za pomocą takiego samego ciągu zer/jedynek.

Na temat U2 znajdziesz dużo w sieci.

Jak się deklaruje w C?
char - 8-bitowa liczba całkowita ze znakiem (U2, zakres -128...127)
unsigned char - 8-bitowa liczba całkowita bez znaku (NKB, zakres 0...255)

Awatar użytkownika
bis
-
-
Posty:134
Rejestracja:12 maja 2005, o 08:11
Lokalizacja:Warszawa

Postautor: bis » 21 lis 2005, o 13:07

Taka drobna uwaga: W części kompilatorów są globalne ustawienia jak traktować typ "char", i tam może być ustawione aby typ "char" był traktowany jako 8 bitów BEZ ZNAKU czyli z zakresu (0..255) i może z tym się borykasz. Nie podałeś zapisu jaki zastosowałeś, może być że z zapisu kompilator domniemuje że jakaś operacja pośrednia jest unsigned i dlatego wywołuje funkcje dzielenia bez znaku. Typy predefiniowane w C nie gwarantują zawsze określonego rozmiaru bitowego (choć prawie zawsze tak jest dla typu char). Szczególnie gdy ogląda sie programy na mikrokontrolery to rozmiar bitowy typów może być różny szczególna konfuzja może powstać przy przenoszeniu kodu z/do 32-bitowców. Z tego powodu utarło się aby możliwie ograniczać stosowanie typów wbudowanych "C", a w projektach definiować własne typy np s8, s16, s32, u8, u16.. (odpowiednio signed/unsigned i ilość bitów) albo byte, word itd. dokładnie odwzorowujące naturę zmiennych sugerowaną przez programistę. Zapisane w jakimś pliku nagłówkowym, włączanym do każdego pliku żródłowego. Odpowiednie kostrukcje preprocesora (np. z użyciem pseudofunkcji sizeof() mogą automatycznie testować prawidłowość rozmiarów, niestety w niektórych kompilatorach ta funkcja nie działa na etapie preprocesingu i wtedy pozostaje (jednorazowe!) przetestowanie ręczne prawidłowości definicji tych typów). Wydaje się że jest to więcej piasania, ale zwraca sie to z nawiązką bo eleminuje stratę czasu na wyszukiwanie "głupich" błędów w programie. (A który błąd nie jest "głupi" jak się go już znajdzie?)

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 21 lis 2005, o 13:25

Bis ma rację, z tym że (chyba) niezwylke rzadko zdarza się aby domyślne konfiguracje były takie. W każdym razie ja się jeszcze nie spotkałem. Więc jeśli Sławku grzebałeś w ustawieniach kompilatora to bardzo prawdopodobne, że jest tak jak napisał bis.

No i własne typy to b. dobra idea, także dlatego że ona m.in. pozwala łatwo przenieść soft na inny kompilator.

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 22 lis 2005, o 07:08

Czesc. Sorry ze dopiero teraz odpowiedam, ale miałem problem z siecią.

doczytalem się ze moj kompilator nie obsluguje signed char, tylko zaczyna od int (coś jak bascom).

To fragment kodu:
void main(void)
{
signed char Tb;
signed int Tm;
unsigned char Tb01,minus,;
char Str[9];
Tb=(signed char)Str[0]; // w tym rejestrze jest wartiosc tem w kodzie U2
Tb=Tb/2;
Tb01=((Str[7]-Str[6])*10)/Str[7];
Tm=(Tb*100)+(Tb01*10)-25;

if((Tm&0x8000)==0x800)
{ //liczba ujena
minus=1;
Tm=~Tm;
Tm=Tm+1;
}
else minus=0;

Str[0]=0;
while(Tm>99){ Tm=Tm-100; Str[0]++; } //wyliczenie czeci calokwitej
Tb01=(char)Tm; //reszta to cyfra po przecinku
Tb01=Tb01/10; //tylko jedno miejsce po przecinku

}

A może jest lepszy kd do obsługi tego DS1820.

Szukałem trochę po sieci o U2, ale nie znalazlem nic o obliczeniach na U2 jak maacie jakiś link to będę wdzięczny.
P.S. Ten fragment kodu nie jest mój tylko zaczerpnięty z sieci.

Awatar użytkownika
bis
-
-
Posty:134
Rejestracja:12 maja 2005, o 08:11
Lokalizacja:Warszawa

Postautor: bis » 22 lis 2005, o 12:42

Co robi ten kod (i po co) wie wyłacznie ten co to zapisał, a większość informacji pozostała w jego głowie. Można sie w nim doszukiwac różnego sensu, a najbardziej zagorzali znajdą nawet obsługę owego DS1820, ale ja wymiękam( jestem za cienki). Ale jest to przykład na brak umiejętności dzielenia się dorobkiem(pisałem o tym w innych postach)
Natomiast prośba o info o U2 jest ciekawa. Przecież "koń jaki jest każdy widzi" (ale po latach). Spróbowałem sie sobie przypomnieć skąd ja to wiem i...pustka. Nabyłem te wiedzę w czasach gdy źródłem wiedzy podstawowej były książki (takie bloczki kartek, połączonych razem, zabrudzonych masą literek) Nadal mam ich trochę. Przeszukałem i .. nadal nic. Jest ładny rozdział o w "Sztuce programowania" Tom2 "algorytmy seminumeryczne" Donalda Knutha,(gorąco polecam) ale uprzedzam że język jest zdecydowanie akademicki. Sa napomknienia w starych podręcznikach do programowania w assemblerach 8-bitowców. (8080, Z80, 8051) Wtedy obowiązkowe były algorytmy na podstawową arytmetykę na 16 i 32 bitowych liczbach. Myślę że inni forumowicze podrzucą Tobie te linki Internetowe. Wtedy polecam trochę zabawy z kartką i ołówkiem i zrozumienie samo wejdzie, na zawsze.

szymel
-
-
Posty:212
Rejestracja:16 sty 2005, o 16:42
Lokalizacja:Włocławek

Postautor: szymel » 23 lis 2005, o 11:45

Hmmm...
Z powyższego kodu wynika , że ktoś się nieźle nagimnastykował , tylko niepotrzebnie.
Natomiast drugi ktoś , albo nie zauważył podstawowego błędu autora, albo sam popełnił błąd przy przepisywaniu kodu.

Kod: Zaznacz cały

... if((Tm&0x8000)==0x800) // co znaczy ten warunek ??? przecież zawsze zwróci FALSE // kompilator też się nie popisał :( if(((Tm&0x8000)==0x8000) //zapewne tak miało być ;) { //liczba ujena minus=1; Tm=~Tm; Tm=Tm+1; } else minus=0; ...
Nie wnikam , dlaczego autor tak zagmatwał proste wyliczenie temperatury , zwróconej przez DS1820.Można to zrobić prościej(?):

Kod: Zaznacz cały

signed int tt=0; unsigned char str[9]; //tablica zawiera dane odczytane z scratchpad-a DS1820 str[0]&=0xFE; tt=(str[1]<<8 | str[0]); tt*=50; tt-=25; tt+=((str[7]-str[6])*100)/str[7]; tt/=10; // wartość temperatury z rozdzielczością 0.1 C , przedstawioną ... // ... w dziesiętnych częściach stopni C. // np.dla temperatury 13.7 C tt=137, a dla -0.5 tt=-5(0xFFFB) // teraz wystarczy tt zamienić na string , ... // ... ZINTERPRETOWAĆ i wyświetlić sprintf(str,"%d",tt); // strasznie pamięciożerne itoa(str,tt,10); //mniej pamięciożerne ...
Jeśli operujemy na zmiennej tybu signed , to po diabła sprawdzać znak tej liczby:?:
O to niech zadbają funkcje , konwertujące tę liczbę do ... czegośtam :D

Pozdrawiam
Piotrek

Wróć do „Projektowanie PCB, programy EDA, CAD, narzędziowe”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 60 gości