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.

AVR/MSP430 - Mnożenie dziwnie zachowanie.

TMEA 03 Gru 2013 08:39 1290 22
  • #1 03 Gru 2013 08:39
    TMEA
    Poziom 16  

    Witam
    Robię a MSP430 układ do kodów. Funkcję liczącą zrobiłem, wyświetlanie też. Robię tak, że w pamięci wewnętrznej procesora jest 350 liczb char w tablicy:
    Unsigned char bazakodow[350]={1,85,35,186,250,45…} - w tablicy jest 350 liczb losowych 0-255.
    Dodatkowo numer kodu jest od 0-700. Jeśli numer kodu jest powyżej 350 do program odczytuje znów z początku tablicy.
    Wzór kodu jest banalnie prosty(część kodu odpowiadająca za kody od 200-249):
    Nrcode=nrcodes;
    If(nrcodes>=350){nrcodes=0;}
    if(nrcode>=200 && nrcode<=249)
    {
    codecheck=(bazakodow[nrcodes]*nrcodes);
    }
    Codecheck i nrcodes jest typu int. Często to banalne mnożenie działa i kod jest porawny a zdarza się że nie działa. Co może być przyczyną? Zauważyłem kiedyś że taki kod działał:
    Nrcodes*bazakodow[280]
    Czyli
    nrcodu=280
    bazakodów[280]= 86
    280*86=24080 – po wpisaniu tego wyniku na ekranie wszystko się zgadzało i kod był akceptowany ale już: 280*120=33600 dawało błąd. Co może być? Czy typy zmiennych się nie zgadzają że mnoże int x unsigned char ale to czasem było by tylko źle?
    pozdrawiam :)

    0 22
  • #2 03 Gru 2013 09:20
    michcior
    Poziom 30  

    A czy INT na 430 nie jest czasem 16 bitowy? Int to typ który zależy od architektury, więc na 16 bitowym 430 INT-a masz -32768 do 32767.
    "long int" to 32 bity na 100% niezależnie od architektury. Ponadto, kompilator podczas działań sprowadza wszystko do domyślnego typy czyli INT-a, i czasami trzeba jawnie "kastować" na wyższy typ, i deklarować stałe, tak by były traktowane jako konkretne typy, np "12343ul" - ("ul" ->unsigned long) .

    0
  • #3 03 Gru 2013 09:41
    TMEA
    Poziom 16  

    czyli może być tu problem? ale czasem robiłem wzór i wynik był do 999999 więc raczej to nie to bo to już long int jest chyba :)

    0
  • #4 03 Gru 2013 09:49
    michcior
    Poziom 30  

    Wydrukuj sobie "sizeof(int)". Na początek. Poza tym, tak jak napisałem, obliczenia są prowadzone z założeniem domyślnego typu i często wynik zaskakuje. Może prosty test:

    volatile unsigned long a;
    volatile unsigned long b;

    a=40000;
    b=a*10;

    printf("b=%u",b);

    (volatile, żeby nie zoptymalizował)

    0
  • #5 03 Gru 2013 10:52
    TMEA
    Poziom 16  

    niestety volatile nic nie daje. Zmieniłbym w tablicy typ zmiennej na int ale nie mieści mi się to do pamięci procesora

    0
  • #7 03 Gru 2013 11:01
    TMEA
    Poziom 16  

    ogolnie nie mam podglądu jaki wynik daje dany kod więc jest mały problem. A co proponujecie jeszcze sprawdzic?

    0
  • #8 03 Gru 2013 11:10
    michcior
    Poziom 30  

    Coś tak jak w przykładzie.
    1) Jeżeli int jest 16 bitowy, to go unikać a najlepiej zdefiniować sobie typy z jawnym rozmiarem: u8, u16 u32, s8, s16, s32 albo coś takiego (uint16 itp.)
    2) Stałe, są traktowane jako domyślny typ, również obliczenia, więc "mapowania" na typ o rozmiarze takim jak chcemy, wszędzie na gdzie się da. W obliczeniach mapuj na takie typy, czyli (s32)costam*(s32 iles)*656234l; tak by kompilator nie sprowadzał obliczeń do domyślnego typu!

    0
  • #9 03 Gru 2013 11:11
    piotrva
    Moderator Mikrokontrolery

    1. Zrób jawne rzutowanie typów
    2. Sprawdź, czy przypadkiem nie przeładowujesz gdzieś stosu - nie wiem jak to wygląda w MSP430 i ile toto ma ramu i ile jeszcze używasz na inne zmienne, ale w AVR stos jest budowany od dołu ramu, a zmienne od góry. I czasem albo w przypadku za dużej liczby zmiennych globalnych, albo gdy stos się rozrośnie (dużo zagnieżdżonych funkcji, dużo zmiennych lokalnych) to dochodzi do zjawiska takiego, że stos nadpisuje końcówkę ramu lub na odwrót - modyfikacja komórek pamięci ram powoduje modyfikację góry stosu - wtedy właśnie bardzo trudno (szczególnie początkującemu) zidentyfikować problem, bo czasem program zachowuje się w naprawdę dziwny sposób.

    0
  • #10 03 Gru 2013 11:29
    BlueDraco
    Specjalista - Mikrokontrolery

    michcior napisał:
    A czy INT na 430 nie jest czasem 16 bitowy? Int to typ który zależy od architektury, więc na 16 bitowym 430 INT-a masz -32768 do 32767.


    Dokładnie tak.

    michcior napisał:
    "long int" to 32 bity na 100% niezależnie od architektury.


    Bzdura. Wszystkie typy standardowe C są zależne od kompilatora. char też nie musi być 8-bitowy. long jest na ogół 32-bitowy, ale np. w Unixach na x86-64 - 64-bitowy, a w Windows na tym samym procesorze - 32-bitowy.

    0
  • #11 03 Gru 2013 12:03
    TMEA
    Poziom 16  

    zrobiłem mały podgląd obliczeń kodu i rozmija się to to dziadostwo dość dużo. Tak jakby obcinało bity.
    jak byl wzór codecheck=(19203+(bazakodow[nrcodes]*nrcode)+(bazakodow[nrcodes]*7)-(nrcode*3))*6;
    to wynik przy kodzie 312 zamiast 186162 to był 055090 :)

    Dodano po 4 [minuty]:

    czyli przerabiając te liczby na bin wychodzi:
    101101011100110010
    001101011100110010

    111001001110010000
    001001001110010000

    czyli że obcina 2 ostatnie znaki ostatni znak :) co Wy na to?

    0
  • #12 03 Gru 2013 12:09
    BlueDraco
    Specjalista - Mikrokontrolery

    Wszystko działa poprawnie. bazakodow[] jest typu unsigned char, nrcode zapewne unsigned int - kompilator zgodnie ze standardem wykonuje działania na liczbach 16-bitowych. Gdybyś pokazał deklaracje, byłoby lepiej widać, o co chodzi.
    Jeśli potrzebujesz dłuższych danych, używaj nowych typów standardowych C zdefiniowanych w stdint.h - uint8_t, uint16_t, uint32_t, int16_t itd.

    0
  • #13 03 Gru 2013 12:11
    TMEA
    Poziom 16  

    unsigned long int codecheck; // cod wyliczony
    int nrcodes; // numer 0-350 i 0-350, nrcode=0-700, nrcodes=0-350
    unsigned char bazakodow[350]={...}

    nie wiem jak się dodaje w CCS5 zmienne uint bo mi nie chcą działać właśnie

    0
  • #14 03 Gru 2013 12:13
    94075
    Użytkownik usunął konto  
  • #15 03 Gru 2013 12:19
    TMEA
    Poziom 16  

    a unsigned long int nie jest 32 bit? bo na tym nie chodzi

    0
  • #16 03 Gru 2013 12:24
    94075
    Użytkownik usunął konto  
  • #17 03 Gru 2013 12:26
    TMEA
    Poziom 16  

    więc już nie rozumiem jak to poprawić aby mieć wiecej niż 16 bit w wyniku :)

    0
  • #19 03 Gru 2013 12:50
    TMEA
    Poziom 16  

    a nrcodes też ma być long skoro nie jest wyższa niż 700? :)

    0
  • #21 03 Gru 2013 13:11
    TMEA
    Poziom 16  

    no więc bazakodów[x] tez nie musi być tyle bo liczby w tej tablicy są typu char 0-255 i jedynie codecheck musi byc jakoś tak ustawiony

    Dodano po 17 [minuty]:

    michcior - dziękuję :) udało się jak na razie :) zobaczymy jak zrobię dłuższe testy.

    0
  • #22 03 Gru 2013 14:51
    BlueDraco
    Specjalista - Mikrokontrolery

    żeby wynik mnożenia był dłuższy od 16 bitów, przynajmniej jeden z argumentów musi być dłuższy od 16 bitów, musisz więc przy jednym argumencie (obojętne którym) dodać rzutowanie (uint32_t).

    0
  • #23 10 Gru 2013 07:19
    TMEA
    Poziom 16  

    problem rozwiązany przez michcior. Faktycznie (unsigned long)zmienna zadziałało. Dałem do wszystkich zmiennych i wszystko działa poprawnie. Zamykam temat :)

    0