Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[AVR][GCC] wskaźnik w strukturze - przekazanie parametru

mirekk36 13 Apr 2010 01:50 3754 8
  • #1
    mirekk36
    Level 42  
    Witam,

    mam taki problem:

    Code:
    char napis[] PROGMEM = {"test"};  // definiuję napis w pamięci FLASH
    

    typedef struct {
       char * wsk;     // struktura ma zawierać wskaźnik do napis'u
    } t_text;            // definiuję strukturę typu t_text

    t_text text PROGMEM = {napis}; // definiuję zmienną text typu t_text i odrazu ją inicjalizuję nazwą tablicy


    i teraz jakaś tam funkcja:

    Code:
    void fun(char * str)
    
    {
        char c;
        while ( (c = pgm_read_byte(s++)) ) UART_putchar(c);
    }


    więc chcę sobie wywołać tę funkcję:

    Code:
    fun( text.wsk );


    i nijak mi się nie udaje wyświetlić tego tekstu :( a przecież do funkcji powinien być przekazany wskaźnik. Co robię źle ???
  • Helpful post
    #2
    BoskiDialer
    Level 34  
    Code:
    // tablica "napis" znajduje się w PROGMEM - w kodzie jest pgm_read_byte: OK
    
    char napis[] PROGMEM = {"test"};
    // zmienna "text"również jest w PROGMEM: wywołanie fun(text.wsk) odwołuje się do złej pamięci
    t_text text PROGMEM = {napis};


    zamień:
    Code:
    fun( text.wsk );

    na coś pokroju:
    Code:
    fun( pgm_read_word(&text.wsk));

    Ewentualnie trzeba będzie dodać rzutowanie.
  • #3
    mirekk36
    Level 42  
    BoskiDialer --> no właśnie cały czas się zastanawiałem jak wyciągnąć spod tego adresu wskaźnik i rzeczywiście tak jak pisałem to odwoływałem się do struktury jakby w pamięci RAM a nie we FLASH.

    WIELKIE DZIĘKI, jak zwykle zresztą na ciebie można liczyć ;)

    teraz działa tylko, żeby eclipse nie podkreślało wężykiem, czyli żeby nie było warninga z którym i tak działa, muszę jednak dodać jeszcze rzutowanie (char *)

    UART_putstr_P( (char *) pgm_read_word(&pgm_params.ati_str) );

    i wtedy wszyściutko pięknie działa ;)

    Dodano po 23 [minuty]:

    Jeszcze lepiej, okazało się, że dokładnie taka sama struktura potrzebna mi jest także w pamięci EEPROM oraz RAM. Przechowuje ona różne ustawienia systemu itp. Oczywiście przy starcie gdy EEPROM pusty ładowany jest domyślnymi wartościami z FLASH podobnie struktura w RAM.

    Wtedy w tej strukturze w RAM mam także wskaźniki ale do pamięci FLASH do tekstu, zatem wywołanie funkcji może się uprościć już do takiego jak było na początku tyle, że z tym rzutowaniem:

    UART_putstr_P( (char *) ram_params.ati_str );

    ;)
  • Helpful post
    #4
    tmf
    Moderator of Microcontroller designs
    Ja sobie swego czasu poszedłem na skróty i wychodząc z założenia, że dane we FLASH nigdy mi nie przekroczą 32kB wykorzystałem najstarszy bit wskaźnika do określenia czy dana jest we FLASH, czy w SRAM. Do tego pare makr i raz na zawsze mogę zapomnieć co jest gdzie. Elegancko da się to zrobić w C++, gdzie można sobie stworzyć klasę implementującą typ o takiej funkcjonalności (w C jest to niemożliwe do eleganckiego zrobienia z powodu braku przeładowywania operatorów). Ale może w jakiejśtam wersji gcc pojawią się w końcu modele pamięci i będzie to można uzyskać elegancko jak np. w IAR.
  • #5
    mirekk36
    Level 42  
    tmf --> tak zawsze opowiadasz o tym C++ dla AVRków, że chyba się w końcu zabiorę za przetestowanie tego do własnych potrzeb.

    Tylko co? w avr gcc jest słabe wsparcie dla C++ ??? ja korzystam jak na razie tylko z Eclipse+AVR GCC - więc jest sens?
  • Helpful post
    #6
    tmf
    Moderator of Microcontroller designs
    Słabe wsparcie o tyle, że nie ma libstdc++, co nie dziwi, przy objętości tej biblioteki. libstdc działa w C++. Jedyne co musisz zrobić to zdefiniować operatory new i delete. Generalnie polecam ci wątek:
    http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453

    A czy jest sens - to IMHO zależy od tego co robisz. W małych projektach sens jest niewielki, ale w większych czytelność kodu poprawia się dramatycznie. Nie mówiąc już o sytuacjach w których obiektowość jest naturalna - np. GUI. Fajnie też wygląda implementacja obiektowa np. 1-wire, czy innych protokołów. Mogę ci podesłać przykładowe kody dla zorientowania się.
    Żeby od razu uprzedzić standardowy atak sceptyków - objętość generowanego kodu dla C i C++ jest praktycznie identyczna. Przy aplikacjach, które pisze mających 30-100kB nie ma różnic. Formalnie jest jedna - na skutek niedomogi gcc VTABLES są kopiowane niepotrzebnie do SRAM, co jest upierdliwe i powoduje marnowanie dużej ilości pamięci. Ale walczę o to z developerami gcc, sam też coś dłubie i myślę, że uda się to zmienić.
  • #9
    tmf
    Moderator of Microcontroller designs
    W załączeniu jako przykład obiektowa realizacja 1-wire. Kod jest trochę skomentowany więc można się zorientować co i jak.
    Poniżej przykład jak tego użyć:
    Code:

    OWDevID *id=OW->ScanDevices();

    const char *x;
    counter=0;
    if(id)
     do{
          x=id->GetDevID(counter++);
          if(x)
          {
             for(uint8_t a=0;a<8;a++)
              {
                 HextoASCII(x[a],tekst);
                LCD->MoveTo(a*16,counter*14);
                LCD->WriteText(tekst);
              }
             HextoASCII(OneWire::CRC8(x,7),tekst);
             LCD->MoveTo(9*16,counter*14);
             LCD->WriteText(tekst);
          }
       } while(x!=NULL);


    OW_DS1820 *ds=new OW_DS1820(OW,id->GetDevID(0));
    uint16_t temp;

    counter=ds->GetLastError();

    do{
       ds->StartConversion(true);
       if((counter=ds->GetLastError())==OneWire::OW_OK)
                            temp=ds->GetTemperature(true);
       if((counter=ds->GetLastError())>OneWire::OW_OK)
        {
          LCD->MoveTo(0,80);
          LCD->WriteText("Err:");
          LCD->MoveTo(54,80);
          uint16todec(counter,tekst,1);
          LCD->WriteText(tekst);
       } else
        {
          LCD->MoveTo(0,80);
          uint16todec(temp,tekst,1);
          LCD->WriteText(tekst);
        }

    } while(1);



    To fragment żywcem wzięty z jakiegoś testowego programu, który kiedyś robiłem, więc bezpośrednio się tego skompilować nie da. Ale to tylko dla ilustracji, no i akurat wy sobie z tym poradzicie.
    Jak widać dodanie obsługi kolejnych urządzeń to tylko napisanie specyficznej klasy-interfejsu. Wszystko w jednym miejscu, urządzenie jest powiązane z opisującymi go danymi - ID, parametry konfiguracyjne itd.