logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Xmega16a4u w C - brak obsługi liczb ujemnych w zmiennej long int

mas24 19 Mar 2015 09:46 957 9
  • #1 14542690
    mas24
    Poziom 16  
    Witam.

    Mam taki dziwny problem, bo wygląda na to, że deklarując zmienną:

    long Int OBW1;

    teoretycznie powinna obsługiwać liczby ujemne, ale mój program się zachowuje, jakby tak się nie działo. Wpisując taki program

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    efekt jest taki,że dolne połówki sinusoidy ulegają zniekształceniu, gdyż wstawienie wartości mniejszej od zera powoduje "przebicie" zmiennej i na samym dole sinusoidy pojawiają się szpilki tym grubsze, im więcej odejmę, a przecież zmienna OBW powinna obsługiwać liczby ujemne. To samo się robi, gdy zadeklaruję ją jako "signed long int".

    Czemu tak się dzieje?
  • #2 14542717
    remiorn
    Poziom 18  
    A czy przetwornik c/a obsługuje liczby ujemne?
    Chyba nie za bardzo.
  • #3 14542722
    Konto nie istnieje
    Konto nie istnieje  
  • #4 14542802
    mas24
    Poziom 16  
    pgm_read_word to typ całkowity, i mam tam dane z zakresu 0-65535, ale przepisuję go do zmiennej obsługującej liczby ujemne typu Signed Long Int
    teraz po odjęciu wartości stałej, powinien obsłużyć liczby ujemne. Potem spowrotem dodaję taką sama wartość, dlatego właśnie, że przetwornik DAC nie obsługuje ujemnych.
    Chyba, ze po przepisaniu ze zmiennej Unsigned do zmiennej Signed, ta ostatnia automatycznie staje się Unigned? Trochę to dla mnie nie zrozumiałe.

    A to wszystko po to, by móc łatwo modulować wartości z tablicy i tym samym zmieniać amplitudę sygnału wyjściowego bez składowej stałej.

    EDIT
    Kolega Freddie Chopin napisał:

    "Zastanów się dobrze, czy po wzięciu liczby 16-bitowej i wpisaniu jej do liczby 32-bitowej jak sobie odejmiesz stałą to aby na pewno uzyskasz to co oczekujesz... W ramach treningu policz sobie to dla wartości 65535, która 16-bitowo ze znakiem oznacza -1 oraz wartości 65534 (-2)."

    I ta wiadomość naprowadziła mnie na rozwiązanie. Pytanie tylko, dlaczego jego post znalazłem w koszu? Pozwoliłem je sobie tu zacytować.

    Wracając do tematu: Informacja o znaku ujemnym zapisana jest zawsze na najstarszym bicie. Wrzucając liczbę 16-bitową do 32-bitowej, informacja o znaku już nie jest na ostatnim bicie, tylko na 16-stym, a LongInt ma tą informację na 32 bicie. Mam rację?
    Nawet jeśli mam, to nie wiem za bardzo, jak temu zaradzić. Czy zadeklarować wszystkie liczby jako 32-bitowe kosztem pamięci i szybkości?
  • #5 14543222
    mpier
    Poziom 29  
    Witam,
    może prosta matematyka pomoże? Np. dla 0 z tablicy będzie -10, -2560, -2550. Po przesunięciu w prawo o 16, to będzie bardzo dużo.
  • #6 14543230
    mas24
    Poziom 16  
    A nie jest tak, że przesuwając w prawo dzielimy (zmniejszamy) wartość, a w lewo mnożymy (zwiększamy)?

    Czyli przesuwając bity, przesuwny także tą jedynkę na początku i nie jest ona chroniona? Pozostaje więc tylko zwykłe, czasochłonne dzielenie?
  • #7 14543269
    Freddie Chopin
    Specjalista - Mikrokontrolery
    mas24 napisał:
    Pytanie tylko, dlaczego jego post znalazłem w koszu?

    Wiadomość skasowałem sam.

    mas24 napisał:
    racając do tematu: Informacja o znaku ujemnym zapisana jest zawsze na najstarszym bicie. Wrzucając liczbę 16-bitową do 32-bitowej, informacja o znaku już nie jest na ostatnim bicie, tylko na 16-stym, a LongInt ma tą informację na 32 bicie. Mam rację?
    Nawet jeśli mam, to nie wiem za bardzo, jak temu zaradzić.

    Kompilator robi wiele konwersji samodzielnie. Jeśli przykładowo konwertujesz liczbę "signed char" na "signed short" ("signed mniejsze" na "signed większe"), to kompilator dokona "rozciągnięcia znaku" (z angielskiego - "sign extend"). Operacja ta zachowuje wartość zmiennej. Przykłady:
    - 0x80, czyli -127 8-bitowo, znak zostaje "rozciągnięty" do 0xFF80, czyli wciąż -127, tyle że 16-bitowo.
    - 0x01, czyli 1 8-bitowo, brak znaku czyli po rozciągnięciu będzie 0x0001, czyli wciąż 1.

    Takie rozciągnięcie nie jest wykonywane, gdy bierzesz liczbę bez znaku i wpisujesz ją do liczby ze znakiem. Stąd Twój problem - 16-bitowe -1 staje się nagle 32-bitowym 65535.

    Rozwiązaniem będzie poinformowanie kompilatora, że w pamięci programu są dane ze znakiem:

    OBW1=(signed int)pgm_read_word(&PRZEBIEGI[0][X1>>5]);

    Coś takiego powinno wystarczyć.

    mas24 napisał:
    Czyli przesuwając bity, przesuwny także tą jedynkę na początku i nie jest ona chroniona? Pozostaje więc tylko zwykłe, czasochłonne dzielenie?

    W przypadku liczb ze znakiem przesuwanie w prawo zachowuje znak.

    4\/3!!
  • #8 14543328
    mas24
    Poziom 16  
    Wpisałem na początku tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Co dało ten sam efekt, le przesuwanie jest już tylko jedno.

    po zastosowaniu w 1. linii:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    szpilki na dolnych połówkach pozostały, ale sygnał z sinusoidalnego stawał się prostokątny w miarę zmniejszania wartości OY1 od 65535 do 0. Ciekawy efekt, przyda się gdzieś indziej, ale nieoczekiwany jest tutaj.
  • #9 14543338
    trol.six
    Poziom 31  
    mas24 napisał:
    Wracając do tematu: Informacja o znaku ujemnym zapisana jest zawsze na najstarszym bicie. Wrzucając liczbę 16-bitową do 32-bitowej, informacja o znaku już nie jest na ostatnim bicie, tylko na 16-stym, a LongInt ma tą informację na 32 bicie. Mam rację?

    Nie. Informacja w języku C jest zapisana w typie liczby. To jak ona wygląda binarnie zależy od kodowania tejże liczby na procesorze.
  • #10 14545788
    mas24
    Poziom 16  
    Udało się, z Waszą pomocą. Wszystkie zmienne uczestniczące w modulacji muszą być znakowe. Dodatkowo dane do odczytywania przygotowałem znakowe 12-bitowe (-2047 +2047). Oto uproszczony listing, do nauki dla potomnych.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Kod wymaga jeszcze uzupełnienia o wszelkie konfiguracje, w zależności od użytego procka.

    Dzięki Kolegom za pomoc!
REKLAMA