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

zamiana int to string i wyslanie prze DBGU przy pomocy PDC

paw789 18 Kwi 2008 00:15 2704 14
REKLAMA
  • #1 5042817
    paw789
    Poziom 18  
    Posty: 298
    Pomógł: 20
    Ocena: 68
    męczę sięz funkcją zamieniającą int na string, która wysyla znaki prze DBGU przy pomocy Peripherial DMA Controler. Musialem sam napisać funcję podobną do itoa ponieważ nie mam jej w bibliotekach.

    
    void DBGU_ZapisDec(int n)
    {
    	char c;
    	char buffor[10];
    	
    	int i,j, sign,size;	
    	if((sign = n) <0) n = -n; // zapamiętaj znak liczby
    	i = 0;
    	
    	do
    	{
    		buffor[i++] = n % 10 + '0';  // resztę z dzielenia przez 10
    		// + wartość znaku zera zapisuję go buffora
    	} while ((n/=10)>0); // dzielę liczbę przez 10 i sprawdzam czy >0
    	 // end do while
    	
    	if (sign<0) buffor[i++] = '-'; // jeśli byl znak minus to go dodaję
    	
    	buffor[i]= '\0';// znak końca
    	
    	// obwrócenie kolejności znaków
    	size = i;
    	for(i=0,j= size - 1 ; i<j; i++, j--)
    		{
    		c = buffor[i];
    		buffor[i] = buffor[j];
    		buffor[j] = c;
    		}
    	
    	// wyslanie przez DBDU przy pomocy PDC (Peripherial DMA Controler)
    	DBGU_ZapisChar( buffor, size);
    } // end DBGU_ZapisDec
    


    W Hyper terminalu jak i Term Terminalu otrzynuję dziwne znaki, w HyperTerminal: ! Ľ
    w TERM Terminal: ! <00>Ľ

    Nie potrafię odnaleźć blędu, wysylanie tekstu jest bezblędne.
  • REKLAMA
  • #2 5042860
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    masz nie tylko problem z funkcja itoa, ale tez bardzo powazny problem z szukaniem informacji na forum. wpisales itoa w wyszukiwarke dzialu? pewnie ze nie wpisales, bo gdybys tak zrobil, to bys nie pisal tego tematu.

    dodatkowo masz tez problem z formulowaniem pytan... DBGU? PDC? a moze byc powiedzial po ludzku na jaki uC to piszesz...

    0x41 0x56 0x45!!
  • #3 5042911
    paw789
    Poziom 18  
    Posty: 298
    Pomógł: 20
    Ocena: 68
    co za różnica co to za uC ? Jest to AT91SAM7S256, o DBGU i PDC napisalem jako ciekawostkę. Zanim zabralem się za pisanie wlasnej itoa() przejrzalem forum.

    Jak to jest z dodawaniem znaku końca ?
    Przenosilem dodawanie znaku końca do bufora dopiero po odwróceniu kolejności, nie pomoglo. Próbowalem bez odwracania kolejności znaków, nic z tego, ciągle wyświetlają się nieodpowiednie znaki. Funkcję którą napisalem do konwersji int2string z powodzeniem używam przy wyświetlaniu liczb na LCD (HD44780), inaczej wygląda tylko odwracanie znaków.
  • #4 5042922
    przemek20
    Poziom 21  
    Posty: 328
    Pomógł: 41
    Ocena: 25
    Witam.
    Znak ASCII tworzy się z pojedynczej cyfry o wartości 0-9 poprzez dodanie do niej 0x30. Musisz dorzucić taką operację w którejś ze swoich pętli.
    Pozdrawiam.
  • REKLAMA
  • #5 5042927
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    przemek20 napisał:
    Witam.
    Znak ASCII tworzy się z pojedynczej cyfry o wartości 0-9 poprzez dodanie do niej 0x30. Musisz dorzucić taką operację w którejś ze swoich pętli.

    jakbys nie zauwazyl, to tak wlasnie jest to zrobione

    @paw789 - przejrzales forum? zartujesz sobie? chocby tutaj masz gotowy przyklad na odejmowaniu, ktory na ARMie bedzie szybszy, gdyz procki te nie maja dzielenia. dostaw sobie tylko znak konca stringa na dowidzenia i masz.

    0x41 0x56 0x45!!
  • #6 5042930
    przemek20
    Poziom 21  
    Posty: 328
    Pomógł: 41
    Ocena: 25
    Faktycznie. Zmęczenie daje o sobie znać ;)
  • #7 5043143
    Fyszo
    Poziom 37  
    Posty: 3987
    Pomógł: 223
    Ocena: 115
    przemek20 napisał:
    Faktycznie. Zmęczenie daje o sobie znać ;)


    Ale ty masz rację. W kodzie z pierwszego postu wogóle nie ma zamiany na ASCII dlatego hyperterminal pokazywał krzaki (a raczej liczby a nie znaki). Dopiero w linku podanym później w kodzie jest taka zamiana i to działa dobrze.
  • REKLAMA
  • #8 5043327
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    polecam doglebna analize tego fragmentu [;

    
    buffor[i++] = n % 10 + '0';
    


    0x41 0x56 0x45!!
  • #9 5045630
    Fyszo
    Poziom 37  
    Posty: 3987
    Pomógł: 223
    Ocena: 115
    No rozumiem. Ja zawsze dodaje 48 bo nie każdy jezyk/kompilator umożliwia sumę liczby i znaku stąd pobierzne wnioski. Przeraszam za wprowadzenie w błąd.
  • #10 5051152
    paw789
    Poziom 18  
    Posty: 298
    Pomógł: 20
    Ocena: 68
    Zmienilem funkcję na proponowaną przez Frrediego

    
    void DBGU_ZapiszDec(int value)
    {
    	char buffor[7];
    	//---------------------------------------------------------
    	int i; 
        
        for(i=0;i<5;i++)                // do that down to tenths 
        { 
            buffor[i]='0';          // initial value is ASCII '0' 
            while(value>=divisor[i])    // loop while current value >= divisor 
            { 
                value-=divisor[i];      // decrement current value 
                buffor[i]++;        // and increment the char in result table 
            } 
        } 
        buffor[5]=(char)value+'0'; // last char equals the final value + '0'
        //----------------------------------------------------------------
    	buffor[6]= '\0'; // znak końca
    	
    	
    	// wyslanie przez DBDU przy pomocy PDC (Peripherial DMA Controler)
    	DBGU_ZapiszString(buffor);
    } // end DBGU_ZapiszString
    


    Funkcja DBGU_ZapiszString:
    
    void DBGU_ZapiszString( char *p )
    {
    	DBGU_ZapiszChar( p, strlen(p) );
    } // end DBGU_ZapiszString
    


    Przy próbie wyslania zmiennej o wartości 1234 otrzymuję: <00><00><00>t
    Coś na pewno robię blędnie, podkreślam że wysylanie tekstu za pomocą
    DBGU_ZapiszString("\n\r Test DBGU ");
    dziala prawidlowo. Gdzie popelniam bląd ?
  • #11 5051983
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    masz jakis debugger, aby podejrzec dokladne wartosci rejestrow? bo ogolnie algorytm ten dziala u mnie. tak w ogole to jesli w twoim kompilatorze int ma 32bity, to wersja z dzieleniem moze byc lepsza. no chyba ze nie bedziesz mial liczb wiekszych niz 99999, bo to max jaki jest w stanie obsluzyc ten algortym. oczywiscie mozna sobie wstawic kolejne wielokrotnosci, ale wtedy warto byloby sprawdzic tez, czy to ma sens, czy moze jednak dzielenie bedzie juz szybsze.

    anyway - jak nie masz debuggera, to moze masz jakies 8 diodek, albo w ostatecznosci jakis port wyprowadzony, zeby podejrzec, czy algorytm aby na pewno ci to prawidlowo przelicza.

    sprawdz jeszcze, czy jak zrobisz tak:

    char string[]="BLABLABLA";
    DBGU_ZapiszString(string);


    to zadziala jak nalezy.

    tak BTW to ta tablice DIVISOR tez gdzies tam wcisnales? z jakimis atrybutami? sprobuj ja wstawic jako labilce lokalna do funkcji.

    0x41 0x56 0x45!!
  • REKLAMA
  • #12 5052060
    paw789
    Poziom 18  
    Posty: 298
    Pomógł: 20
    Ocena: 68
    Co do algotytmu jestem pewien że dziala, jeśli zrobię tak:
     char string[]="BLABLABLA"; 
    DBGU_ZapiszString(string); 
    dziala, problem jest przy jakimolwiek używaniu mojego buffora, jeśli ręcznie wpiszę wartości do buffora, np:
    
    buffor[0]= '1'; // dodawalem rzutowanie, nie pomaga
    buffor[1] = '2';
    buffor[2] = '3';
    buffor[3] ='\0';
    // i wyświetlę
    DBGU_ZapiszString(buffor);
    

    otrzymuję: <00><00>
    Z tego wynika, że problem jest przy zapisie lub odczycie z buffora. Może zmienne są źle zadeklarowane ?

    Za pomocą Debbugera sprawdzalem dzialanie algorytmu, niestety nie mam możliwości podejrzenia zawartości buffora.
  • #13 5052096
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    hmm... no to bardzo specyficzna sprawa, bo wg mnie dzialac powinno jak najbardziej...

    no to moze wez to:

    char string[]="BLABLABLA"; 
    DBGU_ZapiszString(string);


    i zmien na:

    char string[]="BLABLABLA";
    string[2]='2';
    DBGU_ZapiszString(string);


    i przetestuj co ciekawego sie wtedy dzieje [;

    gdy zadeklarujesz bufor jako zmienna globalna to tez tak sie bedzie dziac? gdy uruchamiasz ten kod, to za kazdym razem otrzymujesz dokladnie ten sam efekt, czy moze ogolnie smietnik, ale za kazdym razem co innego? (szczegolnie po zresetowaniu procka zanikiem zasilania!)

    tak pozatym to czemu nie mozesz podejrzec zawartosci bufora? przeciez powinno sie dac to zrobic jak najbardziej.

    0x41 0x56 0x45!!
  • #14 5052229
    paw789
    Poziom 18  
    Posty: 298
    Pomógł: 20
    Ocena: 68
    otrzymuję BL2BLABL
    Dodam że ciągle jest to samo przy resecie, przy wylączeniu i wlączeniu także.

    (później)
    Gdy zadeklarowalem zmienną buffor jako globalną dziala bez problemu :) Ale dlaczego tak się dzialo ?

    W przypadku użycia funkcji do konwersji zmiennych 32 bitowych który sposób jest szybszy (dzielenie czy odejmowanie) ?

    Mój degugger ( Scarabeus ARM Debugger ) nie umożliwia podglądu tablic, można sobie z tym poradzić przypisujęc kolejne komórki tablicy do innych zmiennych. Jeszcze nie uruchomilem OpenOCD.
  • Pomocny post
    #15 5052263
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    no to problem rozwiazany [; caly czas nie zwracalem uwagi, ze ty dane pchasz przez DMA. no wiec problem polegal na tym, ze UART jest na tyle wolny (albo procek na tyle szybki [; zalezy jak na to patrzec), ze zanim on zaczal te dane tak naprawde odbierac i wysylac spod zadanego adresu, to juz funkcja sie skonczyla. skoro zmienna byla lokalna, to byla ona przechowywana na stosie, ktory po wyjsciu z tej funkcji masakrujesz czyms innym, co sie na nim znajdzie.

    poniewaz zmienne globalne sa brzydkie jak noc, to mozesz rozwiazac problem przez dodanie do deklaracji bufora (lokalnej oczywiscie) slowka 'static' - dzieki temu zmienna bedzie przechowywana caly czas w pamieci pod zafixowanym adresem, choc nie bedzie dostepna (bezposrednio [; ) dla innych funkcji - tym sposobem jest ladniej i w ogole pr0 [;

    ktory sposob jest szybszy... problem jest tej natury, ze ciezko mi to ot tak stwierdzic, poniewaz ARMy dopiero poznaje. niemniej jednak - odejmowanie zajmuje pewna stala ilosc cykli na jedna jednostke. jednostka ta jest wielkosc cyfr. np dla liczby 7643 petla wykona sie 7+6+4 razy, bo 3 jest przepisywana na koncu. ogolnie jest to szybkie [; wersja z dzieleniem na pewno bylaby szybsza dla procka ktory by to dzielenie wspieral sprzetowo, a ARMy tego nie maja niestety. dlatego tez stawiam na to, ze wersja z odejmowaniem bedzie szybsza. mozna to w prosty sposob sprawdzic uzywajac timera [;

    przed uruchomieniem funkcji puszczasz timer i po jej zakonczeniu go zatrzymujesz, a jego wartosc przepisujesz sobie do jakiejs zmiennej. to samo zrob dla drugiego rodzaju funkcji i sie przekonasz. pamietaj tylko, ze czas wykonywania funkcji z odejmowaniem jest zalezny od danych wejsciowych: 11111 zostanie przeliczone 10x szybciej niz 99999.

    ostrzegam tez, ze ten algoytm ktory wziales jest najprostsza implementacja rozwiazania problemu i nie byl on optymalizowany po ARMa. wazna sprawa z tego wynikajaca jest to, ze (zakladajac liczby 5 cyfrowe), przeksztalcenie liczby np 123 da w efekcie stringa '00123'. kwestie zer wiodacych mozna w sumie prosto rozwiazac i mozliwe ze nawet w temacie ktory podawalem ktos to zrobil, nie pamietam [;

    0x41 0x56 0x45!!

Podsumowanie tematu

✨ Dyskusja dotyczy problemu konwersji liczby całkowitej (int) na łańcuch znaków (string) i wysyłania go przez interfejs DBGU z wykorzystaniem Peripherial DMA Controller (PDC) na mikrokontrolerze AT91SAM7S256. Autor napisał własną funkcję podobną do itoa(), ponieważ standardowa funkcja nie była dostępna w bibliotekach. Problemem było prawidłowe zamienianie cyfr na znaki ASCII oraz poprawne umieszczenie znaku końca łańcucha. Wskazano, że dodawanie wartości '0' (0x30) do cyfry jest konieczne do uzyskania znaku ASCII. Dodatkowo ujawniono, że lokalna tablica buforu ulega nadpisaniu po zakończeniu funkcji, gdyż DMA odczytuje dane asynchronicznie, dlatego zmienna powinna być zadeklarowana jako globalna lub statyczna, aby zachować poprawną zawartość podczas transmisji. Omówiono także alternatywne metody konwersji liczby na string, m.in. odejmowanie wielokrotności zamiast dzielenia, z uwzględnieniem ograniczeń i wydajności na procesorach ARM. Debugowanie było utrudnione z powodu braku możliwości podglądu tablic w używanym debuggerze. Ostatecznie problem z transmisją rozwiązano przez zmianę zakresu życia bufora na statyczny/globalny, co zapewniło stabilność danych podczas przesyłu przez DMA.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA