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

funkcja itoa() i wiodące 0 przy podstawie 2

janbernat 25 Wrz 2010 14:48 7670 63
  • #1 8548879
    janbernat
    Poziom 38  
    Witam.
    Jak w temacie- czy da się jakoś zmusić te funkcję do wyświetlania zera wiodącego?
    A jeśli nie- bo tak podejrzewam- to czy jest jakiś algorytm do wprowadzenia tego zera na wyświetlacz?
  • Pomocny post
    #3 8548922
    sulfur
    Poziom 24  
    A to wiodące zero ma być jedno czy nawet kilka ? Rozwiązaniem może być obliczenie długości łańcucha (np strlen()) i jeśli wynik jest mniejszy od np ośmiu to wypisujemy osiem minus wynik strlen zer. Mam nadzieję, kolega zrozumiał.
  • #4 8548956
    janbernat
    Poziom 38  
    Za szybko.
    Jaka maska?
    Wyświetlam 0xAA binarnie czyli 10101010.
    Bo to odebrałem.
    Potem np. 0x55 binarnie czyli 01010101.
    I chcę wyświetlać binarnie bo widzę co jest na porcie czujnika.
    itoa() równa do lewej i nie wyświetla wiodącego 0.
    W takim wypadku oba odczyty wyglądają tak samo jeśli przedtem się nie wyczyści wyświetlacza.
    Bo zostaje 0 na końcu z poprzedniego odczytu a nowy wyrównany do lewej.
    P.S.
    Dobrze, zaczynam się uczyć strlen().
    Tylko co nią sprawdzać?
    Dostaję:
    uint8_t stany;
    To jeszcze nie jest string.
    Daję to do:
    itoa(stany,s,2);
    s to już jest string.
    To teraz strlen(s).
    Zaraz zacznę sprawdzać.
  • Pomocny post
    #6 8549031
    sulfur
    Poziom 24  
    strlen(s) zwraca długość łańcucha. Czyli jeśli koledze zwróci 7, znaczy że trzeba dopełnić jedno zero, jeśli 8 nie dopełniamy zerami, jeśli 6 dopełniamy dwa zera itp.

    W tym wypadku rozsądniejsza wydaje się być propozycja kolegi tymon_x. Wiedząc, że dane idą i tak na ekran, można skrócić kod do
    int wynik = 0x55;
    int i = 128;
    for (; i; i>>=1)
    	LCD_Write((wynik&i?'1':'0'));
    Pisane na kolanie oczywiście.
  • #7 8549211
    janbernat
    Poziom 38  
    
    				stany = twiread(NOACK);
    				twistop();
    				int wynik = stany;//0x55;
    //				LCD_Write((wynik&i?'1':'0'));
    //				itoa(stany,s,2);
    				LCD_GoTo(22,1);
    				LCD_WriteText("          ");
    				LCD_GoTo(22,1);
    				int i = 128;
    				for (; i; i>>=1)
    				LCD_WriteText((wynik&i?'1':'0'));
    //				LCD_WriteText(s);
    

    ../ADC_32_for.c:158: warning: passing argument 1 of 'LCD_WriteText' makes pointer from integer without a cast
    Tak to teraz wygląda.
    No i oczywiście źle działa.
    To i>>=1 -tak ma być?
  • Pomocny post
    #9 8549241
    sulfur
    Poziom 24  
    Tak ma być, proszę zamienić LCD_WriteText na coś, co przyjmuje jako argument jeden znak, a nie łańcuch.

                stany = twiread(NOACK); 
                twistop(); 
                LCD_GoTo(22,1); 
                uint8_t i = 128; 
                for (; i; i>>=1) 
                LCD_WriteText((stany&i?'1':'0')); 


    Ewentualnie jeśli kolega się upiera lub nie wie "o co chodzi" zamienić na

    LCD_WriteText((stany&i?"1":"0")); 
  • #10 8549352
    janbernat
    Poziom 38  
    Działa:
    
    				stany = twiread(NOACK);
    				twistop();
    //				int wynik = stany;//0x55;
    //				LCD_Write((wynik&i?'1':'0'));
    //				itoa(stany,s,2);
    //				if(strlen(s)<8)
    //					{
    //					uint8_t ilosc_zer=(8-strlen(s));
    //					}
    				LCD_GoTo(22,1);
    				LCD_WriteText("          ");
    				LCD_GoTo(22,1);
    				int i = 128;
    				for (; i; i>>=1)
    				LCD_WriteText((stany&i?"1":"0"));
    //				LCD_WriteText(s);
    
    

    Bez itoa().
    Nie upieram się && nie wiem o co chodzi.
    Teraz będę miał problem- zrozumieć jak to działa.
    Bo to że dostałem działającego gotowca to sprawę uczenia się C rozwiązuje tylko trochę.
    Dzięki wielkie.
    Ale pomysł Tymona też zacznę sprawdzać.
  • Pomocny post
    #11 8549417
    sulfur
    Poziom 24  
    stany = twiread(NOACK); 
    twistop(); 
    LCD_GoTo(22,1); 
    LCD_WriteText("          "); 
    LCD_GoTo(22,1); 
    int i = 128; 
    for (; i; i>>=1) 
      LCD_WriteText((stany&i?"1":"0")); 
    


    Przeanalizujmy zatem. Linie 1 i 2 pomijam bo to dzieło kolegi. Linie 3 i 4 są zbędne. Linia 5 ustawia pozycję kursora wyświetlacza.

    Linia 6 wystarczy zmienna 8 bitowa bez znaku (char lub uint8_t), oszczędzamy jeden bajt SRAM. Ustawiamy na 128 czyli 10000000 binarnie.

    Operacja i>>=1; przesuwa bit o jeden w prawo z każdym obiegiem pętli, czyli po 10000000 mamy 01000000, potem 00100000 i na końcu 00000001. Kolejne przesunięcie o jeden w lewo daje zero, czyli pętla się przerywa.

    LCD_WriteText((stany&i?"1":"0")); 

    To, co mamy w zmiennej stany maskujemy bitowym operatorem and. ?: to jest operator trójargumentowy, w rzeczywistości to jest if else, czyli rozpisując
    if (stany&i)
      LCD_WriteText("1");
    else
      LCD_WriteText("0");


    Teraz dlaczego kolega powinien sprawdzić sobie i używać funkcji pojedyńczego znaku zamiast łańcucha ? Ponieważ funkcja LCD_WriteText i tak wywołuje tą funkcję, tylko trzeba wykonać jeden call więcej, jeden powrót i dwa sprawdzania warunków, które są bez sensu. Nie liczę tutaj push/pop. Dodatkowo, "1" zajmuje dwa bajty w pamięci i "0" zajmuje dwa bajty w pamięci. Łącznie o dwa za dużo.

    Gdyby było coś niezrozumiałe, proszę o dodatkowe pytanie.
  • #12 8549502
    janbernat
    Poziom 38  
    Teraz jest tak:
    
        stany = twiread(NOACK);
        twistop();
        LCD_GoTo(22,1);
        int i = 128;
        for (; i; i>>=1)
        LCD_WriteData((stany&i?'1':'0'));
    

    Zmieniłem w programie radzia LCD_WriteText() na LCD_WriteData().
    I o to chodziło.
    Trudno mi zrozumieć to:
    
        for (; i; i>>=1)
    

    Czy to znaczy- przesuwaj w prawo aż będzie 1?
  • Pomocny post
    #13 8549524
    tymon_x
    Poziom 30  
    janbernat napisał:
    Czy to znaczy- przesuwaj w prawo aż będzie 1?

    Przesuwaj o jeden bit w prawo, do momentu kiedy i będzie wartością różną od zera. Wartość 0100 czy 0010 to prawda logiczna (czyli for wykonuje się dalej), jak będzie 0000, to koniec pętli for( ; warunek; ), bo to jest fałsz. A warunek w środku sprawdza czy jest prawda (dalej) czy fałsz (koniec).

    Tutaj kolega sulfur zawarł idee:
    Operacja i>>=1; przesuwa bit o jeden w prawo z każdym obiegiem pętli, czyli po 10000000 mamy 01000000, potem 00100000 i na końcu 00000001. Kolejne przesunięcie o jeden w lewo daje zero, czyli pętla się przerywa.


    Zapis i>>=1; to jest to samo co i = i >> 1;
  • Pomocny post
    #14 8549550
    michalko12
    Specjalista - Mikrokontrolery
    janbernat napisał:
    Działa:


    Ciekawe jest te rozwiązanie sulfura,
    ale jak to C rozwiązań może być kilka

    poniżej inne rozwiązanie ;)

    char *itob(char *tab, unsigned int val, unsigned int size)
    {
        int i;
          val <<= (sizeof(val)*8) - size;
          
          for(i=0; i<size; i++)
          {          
              *tab++ = (val & (1<<(sizeof(val)*8)-1)) ? '1' : '0';
              val <<=1;        
          }                       
          *tab++ = '\0';        
         return tab;          
    }


    i trochę bezpieczniejsza wersja

    char *itob(char *tab, unsigned int val, unsigned int size)
    {
        int i;
        
        if(size && size <=(sizeof(val)*8))
        { 
          val <<= (sizeof(val)*8) - size;
          
          for(i=0; i<size; i++)
          {          
              *tab++ = (val & (1<<(sizeof(val)*8)-1)) ? '1' : '0';
              val <<=1;        
          }
        }                       
          *tab++ = '\0';        
          return tab;          
    }
    

    wystarczy tylko zmieniać typ argumentu val dopasowując go do procesora i/lub potrzeb.
  • #15 8549791
    janbernat
    Poziom 38  
    Wziąłem piwo, wyszedłem na balkon i przeczytałem o pętli for().
    Czy dobrze rozumiem:
    for(A;B;C)
    A- zrób coś raz na początku- ale równie dobrze możesz nic nie robić.
    Wtedy jest tak:
    for( ;B;C)
    Dopóki B prawdziwe- to rób dalej.
    Ale nie mam pewności czy jak B nie ma to jest prawdziwe.
    Wtedy- o ile dobrze mi się wydaje- może być tak:
    for( ; ;C)
    C- zrób coś jeszcze- albo nic nie rób.
    Zmień- ale niekoniecznie musisz.
    Wtedy tak:
    for( ; ; )
    Pętla nieskończona.
    No i wszystkie inne kombinacje.
    Elastyczność C powoduje że siwieję jeszcze szybciej niż dotychczas.
    tymon i michałko- pozwolicie że wasze rozwiązania sprawdzę stopniowo.
    Może jutro.
    Bo C uczę się od prawie dwóch miesięcy i jest to coraz bardziej skomplikowane.
    Dzięki Wszystkim.
    Jak tylko cos sprawdzę- to się odezwę.
    P.S.0
    To jest straszne:
    "Przesuwaj o jeden bit w prawo, do momentu kiedy i będzie wartością różną od zera. Wartość 0100 czy 0010 to prawda logiczna (czyli for wykonuje się dalej), jak będzie 0000, to koniec pętli for( ; warunek; ), bo to jest fałsz. A warunek w środku sprawdza czy jest prawda (dalej) czy fałsz (koniec)."
    Czytałem że w C umieszcza się dużo warunków w pętli.
    Ale że aż tak?
    W dodatku tu nie ma dużo warunków- tylko łamigłowka.
    Trzeba chyba kilka podręczników przeczytać wielokrotnie żeby wogóle coś zacząć pisać.
    P.S.1
    W zasadzie można by mnie przykleić to tego tematu "Kurs C dla AVR" jako przykład treningu na żywym organizmie.
    P.S.2
    I to że działa nie zwalnia od obowiązku zrozumienia jak działa.
  • #16 8550046
    sulfur
    Poziom 24  
    michalko12: a czy koledze nie pomyliły się czasem warunki w tej "bezpieczniejszej" wersji ?
    if(size && size <=(sizeof(val)*8))
    Moim zdaniem
    if(size && size >=(sizeof(val)*8))
    Dodatkowo w mojej ocenie pierwszy warunek jest zbędny. No i wygląda na to, że może zabraknąć miejsca na to null terminator.

    Mam też wątpliwości, czy
    val <<= (sizeof(val)*8) - size;
    jest bezpieczne. W zasadzie, to mam wątpliwość, czy to w ogóle działa.

    janbernat: sęk w tym, że umiejętność programowania bardzo istotnie zmienia tok myślenia oraz rozumowania. W niektórych dziedzinach tworzy to niestety pewne bariery, które ciężko jest przełamać. Osobiście uważam umiejętność programowania za pewne zboczenie. Wracając do tematu, od kiedy na balkonie kolegi znajduje się opis pętli for ? Warunek w tym wypadku jest jeden, i to najprostszy z możliwych. Ma kolega niewątpliwie jedną z tych cech, które lubię najbardziej.

    tymon_x: liczyłem na pomoc kolegi w wyjaśnieniu zagadnienia, ponieważ nie bardzo wiedziałem jak to inaczej opisać. Zadziałało.
  • #17 8550184
    michalko12
    Specjalista - Mikrokontrolery
    sulfur napisał:
    michalko12: a czy koledze nie pomyliły się czasem warunki w tej "bezpieczniejszej" wersji ?
    if(size && size <=(sizeof(val)*8))
    Moim zdaniem
    if(size && size >=(sizeof(val)*8))


    Nie, pomyliły się!


    sulfur napisał:
    Dodatkowo w mojej ocenie pierwszy warunek jest zbędny.

    Pierwszy warunek nie jest potrzebny, ale też nie szkodzi.

    sulfur napisał:
    No i wygląda na to, że może zabraknąć miejsca na to null terminator.

    To zależy od tego jak kto zinterpretuje argument size;

    sulfur napisał:

    Mam też wątpliwości, czy
    val <<= (sizeof(val)*8) - size;
    jest bezpieczne. W zasadzie, to mam wątpliwość, czy to w ogóle działa.

    To sprawdź!!!
  • #18 8550220
    janbernat
    Poziom 38  
    Już więcej pomógł dać nie mogę.
    Limit elektrody.
    Na balkonie jest fotel.
    Domyślnie.
    Po drodze są książki które można wziąć ze sobą.
    Też domyślnie.
    I poczytać.
    Jak to zapisać w C?
    Od paru lat uczę czasami nowych pracowników programować w NC-kodach.
    To takie do maszyn.
    I strasznie trudno im to wytłumaczyć.
    I nie rozumiem czego oni nie rozumieja.
    Chyba masz rację- to jest jakieś zboczenie.
    A teraz na stare lata postanowiłem zwiększyć sobie wachlarz zboczeń.
    I nie daruję sobie- albo demencja- albo się nauczę C.
  • #19 8550437
    sulfur
    Poziom 24  
    michalko12 napisał:

    sulfur napisał:

    Mam też wątpliwości, czy
    val <<= (sizeof(val)*8) - size;
    jest bezpieczne. W zasadzie, to mam wątpliwość, czy to w ogóle działa.

    To sprawdź!!!


    W zasadzie, to ma kolega rację. Wszystko zależy od tego, jak zostanie zinterpretowany argument size. Moim zdaniem na takie zastosowanie nazwa argumentu nie jest szczęśliwa. Wiele osób może to potraktować jako wielkość tablicy tab, a wtedy prawdopodobnie poda liczbę, której wynik przytoczonego wyrażenia będzie ujemny (lub przynajmniej równy zero).
  • #20 8550524
    michalko12
    Specjalista - Mikrokontrolery
    W sumie zabrakło opisu funkcji więc bez prześledzenia działania funkcji z kodu błędy i niedopowiedzenia mogłyby się wkraść. Gdyby parametr size był rozmiarem tablicy inaczej musiałby wyglądać warunek sprawdzający poprawność argumentów.
  • #21 8551503
    rpal
    Poziom 27  
    To ma być obrazowanie liczby w postaci binarnej czy dziesiętnej? W jednym i drugim przypadku nie są potrzebne żadne badanie długości łańcucha a algorytm jest bardzo prosty tylko prosze o konret w postaci rodzaju obrazowania.
    Zakładając że chodzi o liczbę binarną to nie ma znaczenia ile ma być zer wiodących bo ta nawet dla 0b00000000 to będzie 8 zer. Zakładasz sobie bufor tekstowy o długości 8 znaków, potem w pętli for od 0 do 7 realizujesz przesunięcie w prawo gdzie badasz stan najmłodzego bitu (moż też być w lewo ale wtedy będzie to najstarszy bit) jednoczesnie po kolei wypełniasz swój bufor od lewej do prawej albo liczbą 0x30 albo 0x31 w zalezności co tam nasz na tym badanym bicie i to wszystko. Metoda badania może być tylko różna albo zwykłe if albo na przykład użyjesz struktury bitowej albo jeszcze czegoś tam innego :)
  • #22 8551529
    sulfur
    Poziom 24  
    Zgodnie z tematem, o podstawie 2 czyli binarnie. Istotne dla autora są zera wiodące.
  • #24 8551609
    rpal
    Poziom 27  
    Z pozoru różnicy nie ma ale jest, kolego. Ty badasz i po kolei wyświetlasz a ja proponuję po kolei zbadac, zapamiętać w buforze i wyświelić. Czas jest dłuższy o każdorazowe przygotowanie LCD dla wyświetlenia znaku a poza tym ta liczba istnieje tylko na ekranie. Może to być zupełnie obojętne ale też może być czemuś potrzebne
  • #25 8551621
    tymon_x
    Poziom 30  
    rpal napisał:
    Z pozoru różnicy nie ma ale jest, kolego. Ty badasz i po kolei wyświetlasz a ja proponuję po kolei zbadac, zapamiętać w buforze i wyświelić. Czas jest dłuższy o każdorazowe przygotowanie LCD dla wyświetlenia znaku a poza tym ta liczba istnieje tylko na ekranie. Może to być zupełnie obojętne ale też może być czemuś potrzebne


    Nie ten post (w sumie o ten co chodzi , to nie mój), ciutkę wyżej, zapisuje do tablicy (;
  • #26 8551630
    rpal
    Poziom 27  
    w sumie temat ciągle aktualny więc może Pan Jan jeszcze "nie załapał" :) Inne przedstawienie rady zamiast ryby wędka :)
  • Pomocny post
    #27 8551778
    michalko12
    Specjalista - Mikrokontrolery
    janbernat napisał:
    Wziąłem piwo, wyszedłem na balkon i przeczytałem o pętli for().
    Czy dobrze rozumiem:
    for(A;B;C)
    A- zrób coś raz na początku- ale równie dobrze możesz nic nie robić.
    Wtedy jest tak:
    for( ;B;C)
    Dopóki B prawdziwe- to rób dalej.
    Ale nie mam pewności czy jak B nie ma to jest prawdziwe.
    Wtedy- o ile dobrze mi się wydaje- może być tak:
    for( ; ;C)
    C- zrób coś jeszcze- albo nic nie rób.
    Zmień- ale niekoniecznie musisz.
    Wtedy tak:
    for( ; ; )
    Pętla nieskończona.
    No i wszystkie inne kombinacje.
    Elastyczność C powoduje że siwieję jeszcze szybciej niż dotychczas.


    Weź jeszcze pod uwagę operator przecinkowy. ;)

    for(A; B; C,D,E,F....)
    {
    
    }
    
    for(A,B,C...; D; E,F,G... )
    {
    
    }
    
  • #28 8551963
    janbernat
    Poziom 38  
    Straszne.
    Teraz sprawdzam sposób tymona.
    
    	LCD_GoTo(22,1);
    	for(j=0; j<8; j++){
    	     acc=7-j;
    	     tab[j] = ((stany >> acc) & maska) + 0x30;
                 LCD_WriteData(*tab);
    	}
    

    Też straszne.
    Pokazuje zame jedynki albo same zera.
    P.S.
    Już poprawiłem:
    
    LCD_WriteData(tab[j]);
    

    Nie wskaźnik na tablicę a element tablicy.
    Teraz działa dobrze.
  • #29 8552015
    tymon_x
    Poziom 30  
    
    	LCD_GoTo(22,1);
    	for(j=0; j<8; j++){
    	     acc=7-j;
    	     tab[j] = ((stany >> acc) & maska) + 0x30;
                 LCD_WriteData(*tab);
    	}
    

    Mogę się domyślać, że LCD_WriteData wyśle jeden bajt?? Spróbuj użyć LCD_WriteText(); (choć strzelam jak on co robi):
    LCD_WriteText((char*)tab);


    PS.
    Może też być:
    LCD_WriteData(*(tab+j));

    ;)
  • #30 8552055
    sulfur
    Poziom 24  
    Ale żeby skorzystać z LCD_WriteText poprawnie, na końcu musiałoby być null terminator. Inaczej kompilator raczy wiedzieć, ile funkcja wyśle znaków do wyświetlacza. Po drugie należałoby to zrobić już za pętlą.
REKLAMA