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

Scalenie dwóch bajtów, AVRStudio, gdzie robię błąd?

www 23 Sie 2007 21:03 1533 7
REKLAMA
  • #1 4208840
    www
    Poziom 14  
    Posty: 219
    Pomógł: 7
    Ocena: 13
    Witam.

    Mam dwie zmienne u08, jest to wynik pewnej operacji, potrzebuje wsadzić je do jednej zmiennej u16.

    Robię to tak:
    u16 rxData=0;
    u08 data1=0, data2=0;

    data1=0x69; //MSB
    data2=0x8C; //LSB
    rxData=rxData+data1;
    rxData=rxData<<8;
    rxData=rxData|data2;

    Policzyłem to kalkulatorem i powinno być dobrze ale niestety w AVRStudio zmienna rxData przyjmuje jakieś dziwne ujemne wartości.
    Nie mogę uruchomić symulatora bo mi się wywala więc pytam bo nie rozumiem o co tu chodzi.

    Pozdrawiam.
  • REKLAMA
  • #2 4209019
    markosik20
    Poziom 33  
    Posty: 2261
    Pomógł: 208
    Ocena: 147
    Proponuje tak :wink:
    
    u16 rxData=0; 
    u08 data1=0, data2=0; 
    
    data1=0x69; //MSB 
    data2=0x8C; //LSB 
    rxData=data1;
    rxData<<=8; 
    rxData|=data2;
    

    albo wykorzytać unię
    
    union {
             u16 MSB_LSB;
             struct {
                       u08 MSB;
                       u08 LSB;
                       }bajt; 
             }rxData;
    

    i odwołujesz się do 16bitów jako
    
    rxData.MSB_LSB=.......;

    i do pojedynczych bajtów jako
    
    rxData.bajt.MSB=....;
    
  • REKLAMA
  • #3 4209164
    2P
    Poziom 20  
    Posty: 345
    Pomógł: 22
    Ocena: 205
    u16 rxData=0;
    u08 data1=0, data2=0;
    
    data1=0x69; //MSB
    data2=0x8C; //LSB
    rxData=rxData+data1; // <- Po co ta kombinacja z dodawaniem??
    rxData=rxData<<8 ; // <- Tu jest podstawowy błąd - przesuwasz liczbę 8 bit o 8 bit.... w wyniku zawsze 0.
    rxData=rxData|data2; 


    Pamiętając, ze C umożliwia wykonywanie kilku działań w jednej linii (więcej... nawet się zaleca tak pisać, ponieważ ułatwia to optymalizację kodu):
    u16 rxData=0;
    u08 data1=0, data2=0;
    
    data1=0x69; //MSB
    data2=0x8C; //LSB
    
    rxData = (u16)data1<<8 | data2; // <- Rzutujemy, przesuwamy i dodajemy logicznie. Przy włączonej optymalizacji to powinno się zmienić na dwa przesłania. 
  • REKLAMA
  • #4 4209363
    aster11
    Poziom 19  
    Posty: 211
    Pomógł: 36
    Ocena: 1
    Twoje przeliczenie wygląda na poprawne. Modyfikacja jaką zaproponował markosik20 eliminuje tylko jedno zbędne (ale nie błędne:) ) dodawanie, a propozycja 2P to dalej to samo, tylko jeszcze bardziej skompresowane. Wszystkie kody powinny jednak w efekcie działać jednakowo.
    Skoro piszesz, że wyświetlają Ci się wartości ujemne, chociaż wartość jest unsigned, to prawdopodobnie stosujesz złe formatowanie przy wyświetlaniu. Napisz w jaki sposób wyświetlasz wartość zmiennej rxData.
  • REKLAMA
  • #5 4209456
    www
    Poziom 14  
    Posty: 219
    Pomógł: 7
    Ocena: 13
    aster11: w zupełności się z Tobą zgadzam dlatego pęka mi już głowa.
    Do wyświetlania wyniku używam funkcji:
    usart_putf (rxData);
    z biblioteki AVRLIB.
    Oto kod tej procedury:
    
    void usart_putc(char data) {
        while (!(UCSRA & 0x20)); // Wait untill USART data register is empty
        // Transmit data
        UDR = data;
    }
    
    void usart_puts(char *data) {
      int len=0, count=0;
      
      len = strlen(data);
      for (count = 0; count < len; count++) 
        usart_putc(*(data+count));
    }
    
    void usart_putf (int usart_num)				/* Writes integer to the USART		*/
    {
     char usart_ascii_string[6]="      ";		/* Reservation to the max absvalue (2^16)/2		*/
     
     itoa(usart_num, usart_ascii_string, 10);	/* Convert integer to ascii [not ansi c]		*/
     usart_puts(usart_ascii_string);		/* Sens ascii pointer to the lcd_printf()		*/
    }
    


    Pozdrawiam.
  • #6 4209587
    aster11
    Poziom 19  
    Posty: 211
    Pomógł: 36
    Ocena: 1
    Wygląda na to, że funkcja usart_putf() rzeczywiście wypisuje liczbę, biorąc ją jako wartość ze znakiem. Jednak dla Twoich próbnych wartości:
    data1=0x69; //MSB 
    data2=0x8C; //LSB 

    powinna wyjść wartość dodatnia (16bit, U2). Sam nie rozumiem, co jest grane. Może inni coś jeszcze zauważą lub zaproponują.
    Ja sugeruję skoncentrować się na sposobie wypisania wartości, możesz spróbować np. coś w stylu:
    char text[10];
    
    sprintf(text, "%x", rxData);
    usart_puts(text);
  • #7 4213733
    2P
    Poziom 20  
    Posty: 345
    Pomógł: 22
    Ocena: 205
    www napisał:

    Policzyłem to kalkulatorem i powinno być dobrze ale niestety w AVRStudio zmienna rxData przyjmuje jakieś dziwne ujemne wartości.
    Nie mogę uruchomić symulatora bo mi się wywala więc pytam bo nie rozumiem o co tu chodzi.
    Rzeczywiście kod powinien działać prawidłowo. Nie przyjrzałem się.

    Zauważyłem natomiast, że w plikach wynikowych z nowszych wersji AVR-GCC jest problem z wyświetlaniem zawartości zmiennych lokalnych pod AVRStudio. Spróbuj (tylko testowo) zdefiniować rdData jako zmienną globalną typu volatile. Jeśli to będzie pokazywane prawidłowo oznaczać to będzie, że błąd następuje przy określaniu położenia zmiennej w pamięci przez sam symulator a nie w działającym kodzie programu.
  • #8 4213981
    shg
    Poziom 35  
    Posty: 2289
    Pomógł: 339
    Ocena: 135
    Funkcja itoa() operuje tylko na liczbach ze znakiem, więc użycie jej do liczb bez znaku jest błędem.
    Nowa biblioteka avr-libc ma funkcję utoa(), która operuje na liczbach bez znaku i to jej należało by użyć.
    Mimo wszystko i tak dziwnie, bo podane przez Ciebie wartości mieszczą się i tak w typie ze znakiem więc teoretycznie powinny być wyświetlone normalnie.

    Spróbuj kompilacji z wyłączoną optymalizacją. Może być tak, że kompilator generuje kod pomijając pewne operacje, których wynik nie jest nigdzie używany. Chociaż z drugiej strony dane te zapisywane są (pośrednio) do rejestru UDR, a ten zadeklarowany jest jako volatile, więc "po nitce do kłębka" kompilator powinien dojść i nie usuwać tych operacji.

    Pozostaje jeszcze wina debugera. AVR Studio ma pewne niedostatki i nie wszystko jest emulowane do końca tak jak powinno być.

Podsumowanie tematu

✨ Problem dotyczy łączenia dwóch zmiennych 8-bitowych (u08) w jedną 16-bitową (u16) w środowisku AVRStudio. Kod użytkownika przesuwał wartość po dodaniu, co mogło prowadzić do błędów, jednak poprawne łączenie powinno wyglądać jak: rzutowanie MSB na u16, przesunięcie o 8 bitów w lewo i połączenie z LSB operatorem OR. Wskazano, że problem z ujemnymi wartościami wynika prawdopodobnie z błędnego formatowania podczas wyświetlania, gdyż funkcja usart_putf() używa itoa(), która działa na liczbach ze znakiem, co może powodować nieprawidłową interpretację wartości unsigned. Zalecane jest użycie funkcji utoa() dla liczb bez znaku lub formatowanie przez sprintf() z odpowiednim specyfikatorem. Dodatkowo zauważono, że AVRStudio może mieć problemy z poprawnym wyświetlaniem zmiennych lokalnych w symulatorze, co sugeruje testowanie zmiennych globalnych volatile. Kompilacja bez optymalizacji może pomóc w diagnozie. Proponowano także alternatywne metody łączenia bajtów, np. użycie unii z polami MSB i LSB.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA