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

Dzielenie modulo w SDCC na mikrokontrolerze At89S8252 - jak to zrobić?

Zaquadnik 19 Sie 2006 22:56 1985 16
REKLAMA
  • REKLAMA
  • #2 2932777
    Xitami
    Poziom 29  
    Posty: 1130
    Pomógł: 118
    Ocena: 31
    operator %
  • REKLAMA
  • #3 2933059
    Zaquadnik
    Poziom 27  
    Posty: 998
    Pomógł: 103
    Ocena: 25
    Gdyby on działał jak należy to bym nie pytał ;) Dopóki liczba jest mniejsza od 10 (robię dzielenie mod 10) to zwraca poprawny wynik. Natomiast, jeśli na przykład liczba jest równa 12, to w wyniku otrzymuję 0x0C. Dlaczego ? :> Wkleję kod, w którym to stosuję :
    
    void ultoa(unsigned long liczba,char* lancuch,char dlugosc)
    {
    	unsigned char cyfra;
    	unsigned long bufor;
    	while (dlugosc > 0)
    	{
    		cyfra = 0;
    		cyfra = liczba % 10;
    		cyfra = cyfra | 0x30;
    		lancuch[dlugosc-1] = cyfra;
    		liczba = (float) liczba / 10;
    		dlugosc--;
    	}
    }
    
  • #4 2933123
    Xitami
    Poziom 29  
    Posty: 1130
    Pomógł: 118
    Ocena: 31
    0x0C to właśnie 12 tyle, że szesnastkowo
    a czy zainicjowałeś "lancuch"? spacje i zero na końcu
    (float) niby nic nie zmienia, ale poco?
    void ultoa(unsigned long liczba,char* lancuch,char dlugosc)
    {
       unsigned char cyfra;
       lancuch[dlugosc]=0; // dodalem
       while ((dlugosc > 0) & (liczba!=0)) //zmienilem
       {
          cyfra = 0;
          cyfra = liczba % 10;
          cyfra = cyfra | 0x30;
          dlugosc--;                // zamienilem
          lancuch[dlugosc] = cyfra; //
          liczba = liczba / 10;     // wywalilem (float)
       }
       while (dlugosc--)        //dodalem
           lancuch[dlugosc]=32; // 32==spacja
    }
    
    Troszkę zmieniłem, działa OK w "durzym" C
  • #5 2933386
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Nie rozumiem , czemu komplikujecie proste zadanie :D
    
    #include <at89S8252.h>
    //...
    #define MAXDIGITS 10 //decymalny
    
    char* ul2decstr(unsigned long x,unsigned char* y)
    {
    y+=MAXDIGITS;
    *y=0x00;
    while(x)
    	{
    	y--;
    	*y=(x % 10) | 0x30;
    	x/=10;
    	}
    return y;
    }
    
    void main()
    {
    unsigned long xxx = 0xFFFFFFFF;
    char buf[MAXDIGITS+1], *ptr;
    
    ptr=ul2decstr(xxx, buf);
    //...
    while(1);
    }
    
    


    Piotrek
  • #6 2933592
    Xitami
    Poziom 29  
    Posty: 1130
    Pomógł: 118
    Ocena: 31
    Nie chciałem zmieniać zbyt wiele na raz.
    Był parametr „dlugosc”, no to może oczekiwane było dosunięcie do prawej czy ograniczenie szerokości, a nie tylko pokazanie znaczących cyfr (można to poprawić w np. printf, ale to jest małe C, więc trzeba oszczędzać).
  • #7 2933676
    Zaquadnik
    Poziom 27  
    Posty: 998
    Pomógł: 103
    Ocena: 25
    Zumek, przyznam, że nie bardzo rozumiem Twój kod, możesz go troszkę skomentować ? Będę wdzięczny.

    Xitami, bez rzutowania na float podaje zupełnie bzdurne wyniki. Nie do końca wiem czemu. Może wiąże się to z tym, że liczba całkowita jest zapisywana w kodzie U2 (choć unsigned nie powinna), a do dzielenia wymaga zapisu znak-moduł ?

    Xitami, po sprawdzeniu Twoje rozwiązanie różni się w działaniu od mojego tylko tym, że wstawia spacje przed pierwszą znaczącą cyfrę :] To operator % zwraca coś dziwnego.
  • REKLAMA
  • #8 2934069
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Zaquadnik napisał:
    Zumek, przyznam, że nie bardzo rozumiem Twój kod, możesz go troszkę skomentować ? Będę wdzięczny.

    Na początku muszę przyznać , że ta moja funkcyjka zawiera poważny błąd , ponieważ dla long=0 zwraca pusty ciąg , a powinna "0" :(
    Po poprawce ...
    
    char * ul2decstr(unsigned long x,unsigned char * y)
    {
    y+=MAXDIGITS;//przesunięcie wskaźnika o max możliwych cyfr
    *y=0x00; //znacznik końca stringu - równoważne z y[0]=0x00;
                   //zwane inaczej operatorem wyłuskania 
    do{
       y--;
       *y=(x % 10) | 0x30; //równoważne z y[0]=(x % 10) | 0x30; 
       x/=10;                     //równoważne z  x = x / 10;
       } while(x);
    return y;
    }
    

    Działanie polega na tym , że x jest wskaźnikiem na char i adres na który wskazuje , mogę dowolnie zmieniać . Nie mogę tego zrobić z buf , ponieważ taki wskaźnik(deklarujący tablicę) jest traktowany przez kompilator jako const.Funkcja zwraca adres wskazujący na pierwszą/najstarszą/najbardziej znaczącą/itp. cyfrę w ciągu/tablicy.To chyba tyle :D

    Piotrek
  • #9 2934863
    Xitami
    Poziom 29  
    Posty: 1130
    Pomógł: 118
    Ocena: 31
    Zakładam się o 10 punktów, że problem leży w niezainicjowanej zmiennej „lancuch” co tam masz przed zawołaniem ultoa()?
    Co otrzymujesz wołając funkcję Zumka, a co moją?
  • REKLAMA
  • #11 2935004
    Xitami
    Poziom 29  
    Posty: 1130
    Pomógł: 118
    Ocena: 31
    Napisz krótki program testowy, „%” się nie czepiaj, błąd leży poza tą funkcją.
    Pokaż nam ten program, wtedy na 100% powiemy co jest.
    możesz zaGGadać
  • #13 2940765
    Zaquadnik
    Poziom 27  
    Posty: 998
    Pomógł: 103
    Ocena: 25
    OK, moje rozwiązanie dla zmiennej long równej 11000 daje wynik 00 00 00 00 00 31 3B 7E 7C F8.

    Rozwiązanie Xitami dla tej samej danej daje FF FF FF FF FF FF FF FF FF F8.

    Rozwiązanie Zumka daje (też dla tej samej danej) FF FF FF FF FF FF FF FF FF F8.
  • #14 2940825
    viki
    Poziom 16  
    Posty: 262
    Pomógł: 11
    Ocena: 3
    Zaquadnik a czy twoja zmnienna nie jest czasem równa 0x11000?
  • Pomocny post
    #16 2941833
    vibrasphere
    Poziom 15  
    Posty: 134
    Pomógł: 11
    Ocena: 1
    Moja solucja, ktora dziala na kompie:

    
    void reverse(char *s)
    {
      char c, *p, *q;
        q = s;
        while (*(++q));
        for (p=s; p < --q; p++)  {
            c = *p;
            *p = *q;
            *q = c;
        }
    }
    void ultoa(unsigned long n, char* buf)
    {
        char *modbuf = buf;
        while (n != 0) {
            unsigned char remainder = (unsigned char)(n % 10);
            *modbuf = remainder + '0';
            n /= 10;
            modbuf++;
        }
        *modbuf = '\0';
        reverse(buf);
    }
    
    
    
    int main() {
        unsigned long int a = 132423234UL;
        char buf[30];
        ultoa(a, buf);
        printf("%s\n", buf);
    }
    
    

Podsumowanie tematu

✨ Dyskusja dotyczy problemu implementacji dzielenia modulo (%) w kompilatorze SDCC dla mikrokontrolera At89S8252. Użytkownik zgłaszał nieprawidłowe wyniki operatora %, szczególnie dla wartości większych niż 10, gdzie wynik był interpretowany jako wartość szesnastkowa (np. 0x0C zamiast 12). Wskazywano na potencjalne błędy w inicjalizacji bufora znakowego oraz niepoprawne rzutowanie typu liczby całkowitej na float podczas dzielenia. Zaproponowano różne implementacje funkcji konwertujących liczby całkowite na ciągi znakowe w systemie dziesiętnym, m.in. funkcję ul2decstr, która zwraca wskaźnik do pierwszej znaczącej cyfry, oraz funkcję ultoa z odwracaniem ciągu znaków po konwersji. Podkreślono, że operator % działa poprawnie, a problem leży w obsłudze i wyświetlaniu wyników. Wskazano również na konieczność poprawnej inicjalizacji łańcucha znakowego i unikanie niepotrzebnych rzutowań. Ostatecznie autor potwierdził rozwiązanie i zamknął temat.
Wygenerowane przez model językowy.
REKLAMA