Elektroda.pl
Elektroda.pl
X
Szkolenia elektronika Udemy
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[WinAVR] dostęp do struktury w pamięci programu.

gwozdex 17 Paź 2011 22:03 2394 15
  • #1 17 Paź 2011 22:03
    gwozdex
    Poziom 13  

    Witam!
    Mam pewien problem. Mianowicie, zadeklarowałem sobie strukturę w pamięci programu oraz zainicjowałem ją:

    Code:
    typedef struct stringg
    
    {
       uint8_t screen_cnt;      // ilość ekranów
       char napis[];         // tekst do wyświetlania
    }string_struct PROGMEM;

    string_struct strr = {1, "avc"};


    oraz procedurę piszącą na moim wyświetlaczu:
    Code:
    void print_str(prog_char* str)
    
    {
       int n=0;
       char znak;
       while (0 != (znak= pgm_read_byte(str++)) )
       {
          chose_disp(n/4);
          chose_digit(n%4);
          send_data(znak);
          n++;
       }
    }


    Problem w tym że nie potrafię się dostać do tej struktury... próbowałem na różne sposoby, korzystając z operatora "&" oraz makra pgm_read_byte i nic.

    Odwołanie się w sposób jak poniżej:

    Code:
    print_str(strr.napis);

    skutkuje błędem: "main.c:42: error: request for member `napis' in something not a structure or union", natomiast odwołanie takie:
    Code:
    print_str(strr[0].napis);
    przynosi pożądany efekt tylko nie wiem dlaczego.
    Problem w tym ze docelowo chcę zadeklarować takie coś:
    Code:
    string_struct strr[5] = 
    

    {
       {1,"gitara1"},
       {1,"gitara2"},
       {1,"gitara3"},
       {1,"gitara4"},
       {1,"gitara5"},
    };
    i jak do tego się odwołać to już nie mam pojęcia...
    Za okazaną- dla początkującego w GCC- pomoc serdeczne dzięki...
    gwozdex.
    PS. używam WinAVR 20060125

    0 15
  • Szkolenia elektronika Udemy
  • #2 18 Paź 2011 00:06
    tmf
    Moderator Mikrokontrolery Projektowanie

    Po pierwsze:
    http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_rom_array
    Po drugie - nie używaj typów prog_xxx - one są błędnie zdefiniowane w AVR-libc i w nowych wersjach kompilatora nie będą działać tak jak się spodziewasz.
    Po trzecie, żle określasz atrybut progmem, u mnie powyższy kod daje takie ostrzeżenie:
    ../test.c:8: warning: ignoring attributes applied to 'struct stringg' after definition
    Ale poza tym kompiluje się ok, chociaż dane zgodnie z tym co napisałem wcześniej nie trafiają do FLASH.
    A swoją drogą co skłania cię do korzystania z wersji kompilatora sprzed 5 lat?

    0
  • #3 18 Paź 2011 07:26
    gwozdex
    Poziom 13  

    skłania mnie właśnie to ostrzeżenie o którym wspomniałeś...
    W nowszej wersji WinAVR dane nie trafiają do flasha co sygnalizowane jest właśnie tym komunikatem.

    a jeśli chodzi o typ prog_xxx to tez nie mam z nim problemu.
    Niestety pomimo (mocno) nadszarpniętej nocy nie rozwiązałem swojego problemu...

    Dziękuję za pomoc.

    0
  • Pomocny post
    #4 18 Paź 2011 08:21
    Andrzej__S
    Poziom 28  

    Chyba nie przeczytałeś informacji z linku podanego przez kolegę tmf, bo dowiedziałbyś się, że dla nowego kompilatora należy zamiast:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    użyć składni:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    i wtedy odczyt:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    będzie działał prawidłowo.

    0
  • #5 18 Paź 2011 09:30
    tmf
    Moderator Mikrokontrolery Projektowanie

    Dodatkowo wyjaśnię o co chodzi z tymi typami prog_xxx - żeby inni się nie nacięli.
    Otóż typy te używają słowa kluczowego typedef do przypisania atrybutu progmem do typów podstawowych, np. char. Problem w tym, że w gcc tylko przypadkiem to działa, gdyż zgodnie ze standardem nie można w ten sposób definiować typów i przypisywać im atrybutów. Wiem, że developerzy avr-gcc tej przypadkowej funkcjonalności nie będą rozwijać, ani testować w nowych wersjach avr-gcc, w efekcie już w 4.6.x to może nie działać. Rozwiązaniem jest zastosowanie zamiast typedef #define, ale póki co tego nie wspiera AVR-libc.

    0
  • Szkolenia elektronika Udemy
  • #6 18 Paź 2011 16:29
    gwozdex
    Poziom 13  

    Witam!
    Na początku dziękuję za odpowiedzi...
    Zrobiłem jak poradziliście... zainstalowałem najnowszą wersję WinAVR i zadeklarowałem tablicę wg. waszych wytycznych i do tego momentu wszystko jest ok. Niestety próba odwołania się do tej struktury nadal kończy się niepowodzeniem:
    1. jeśli wywołam funkcję w ten sposób:

    Code:
    print_str(pgm_read_byte(strr[1].napis));

    otrzymuję poniższe ostrzezenie:
    "main.c:42: warning: passing argument 1 of 'print_str' makes pointer from integer without a cast"

    2. dodanie operatora adresu "&" niewiele zmienia oprócz warninga:
    "main.c:42: warning: passing argument 1 of 'print_str' makes pointer from integer without a cast"

    3. Wywołanie takie:
    Code:
    print_str(strr[1].napis);

    kompiluje program bez ostrzeżeń ale nie działa tak jak się spodziewam- wyświetlanie napisu odbywa się od litery która jest w nawiasie kwadratowym, a wyświetlany jest zawsze pierwszy napis...

    Podpowiedzcie co jest nie tak...

    PS. zwracam tylko uwagę, że funkcja print_str potrzebuje wskaźnika- może tutaj mam problem(tzn. zależy mi na tym, żeby tam był wskaźnik, ale z tego wynika ze w wywołując tą funkcje nie przekazuje jej wskaźnika do zmiennej a samą zmienną...).

    0
  • #7 18 Paź 2011 18:55
    tmf
    Moderator Mikrokontrolery Projektowanie

    Zobacz na typy argumentów swojej funkcji print_str - skoro jest char* to jak się spodziewasz, że wynik pgm_read_byte przypasuje? Istotnie w takiej sytuacji pobranie adresu nic nie zmienia.
    Proponowałbym zacząć od książki opisującej C, np. K&R, lub przynajmniej poczytać jakiś porządny tutorial internetowy na temat C.

    0
  • #8 18 Paź 2011 19:20
    gwozdex
    Poziom 13  

    ...temu zaprzeczał nie będę- jestem początkującym w C. De facto to mój pierwszy program, który piszę w tym języku.
    Jeśli chodzi o zgłębianie swojej wiedzy w zakresie C to ostatnio nic innego nie robię, ale jak widać utknąłem...
    A za okazaną pomoc dziękuję i przydzielam punkty.
    Pozdrawiam.
    gwozdex

    0
  • #9 18 Paź 2011 19:33
    Andrzej__S
    Poziom 28  

    @tmf:
    ...ale autor tematu napisał, że print_str(strr[1].napis); też mu nie działa prawidłowo.

    Myślę, że prawdopodobnie kompilator ma problem z określeniem rozmiaru struktury i - co za tym idzie - obliczeniem wskaźnika do następnego elementu tablicy struktur.
    Proponuję dodać w strukturze rozmiar ciągu znaków:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Takie rozwiązanie może nieco zwiększyć przestrzeń danych we flash'u potrzebną do zapisania tablicy struktur (jeśli ciągi znaków będą różniły się długością), ale powinno działać prawidłowo.

    Jeśli musisz oszczędzać flash (masz dużo tych ciągów i/lub znacznie różnią się one długością) to znowu odsyłam do linku wspominanego wcześniej. Tam masz praktycznie gotowe rozwiązanie:
    AVR-libc FAQ napisał:

    Kod: c
    Zaloguj się, aby zobaczyć kod



    Musisz to tylko przerobić na swoje potrzeby, czyli umieścić wskaźniki zamiast ciągów wewnątrz swoich struktur.

    0
  • #10 18 Paź 2011 19:54
    tmf
    Moderator Mikrokontrolery Projektowanie

    Oczywistym jest, że nie można indeksować wielowymiarowej tablicy, w której jeden z wymiarów jest typem niekompletnym, bo jak niby obliczyć w takiej sytuacji adres? W FAQ do AVR-libc jest dokładny przykład jak to rozwiązać, czyli tak jak to elegancko pokazałeś - jeśli jeden z typów ma nieokreślony rozmiar to albo zrobić typ nadmiarowy, który będzie marnotrawił pamięć, albo zamienić taką pozycję na wskaźnik - co też marnuje pamięć. Tak więc w zależności od reprezentowanych danych jedno z tych rozwiązań jest lepsze.
    Niemniej zamiast drążyć różne sztuczki, myślę, że dla autora lepiej by było, aby zanim zacznie dalej pisać program poczytać o typach danych i strukturach w C, bo zrobi kolejny krok i już tak się zaplącze, że tylko się zniechęci.

    0
  • #11 18 Paź 2011 20:27
    Andrzej__S
    Poziom 28  

    Przepraszam. Nie chciałem nikogo zniechęcać ;)
    Miałem tylko nadzieję, że mój post może nieco wyjaśni, a jeśli nie, to przynajmniej zmusi do poczytania.

    0
  • #12 18 Paź 2011 22:12
    gwozdex
    Poziom 13  

    Panowie, Panowie... za głupi jestem, żeby się zniechęcić :D.

    Jeśli mam być szczery to właśnie takich odpowiedzi oczekiwałem.
    :arrow: Andrzej__S

    Miałeś rację! problem tkwił w w rozmiarze struktury. zmiana deklaracji z:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    na:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    pozwoliła wywołać polecenie print_str z pozytywnym efektem.

    Pozwolę sobie jednak tutaj na przedstawienie moich wniosków.
    Poczytałem trochę manuala do avr-libc dołączonego do najświeższego WinAVR i jak byk pisze tam, że aby zadeklarować i zainicjować tablicę łańcuchów w pamięci programu trzeba osobno zadeklarować samą tablicę jak i stringi:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Natomiast jeśli chodzi o struktury to powyższa reguła nie znajduje zastosowania!
    W mini programie który napisałem wszystkie dane trafiają do sekcji .text i na tej podstawie twierdzę ze moja deklaracja struktury w 1. poście zawierała tylko jeden błąd- nie posiadała rozmiaru pola napis.

    0
  • #13 19 Paź 2011 11:19
    Andrzej__S
    Poziom 28  

    gwozdex napisał:

    Poczytałem trochę manuala do avr-libc dołączonego do najświeższego WinAVR i jak byk pisze tam, że aby zadeklarować i zainicjować tablicę łańcuchów w pamięci programu trzeba osobno zadeklarować samą tablicę jak i stringi

    ...

    Natomiast jeśli chodzi o struktury to powyższa reguła nie znajduje zastosowania!


    Ależ znajduje:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Twoje rozwiązanie (z podaniem rozmiaru stringa), jak już wcześniej pisał kolega tmf polega na stworzeniu typu nadmiarowego. Oznacza to, że jeśli będziesz miał przykładowo 50 ciągów znaków, z których 49 ma długość np. 5 znaków, a tylko jeden ma 20 znaków, to i tak musisz wpisać do rozmiaru tablicy 21, co powoduje, że 49 razy tracisz po (20-5) znaków, bo niezależnie od długości ciągu i tak każda struktura musi mieć określony rozmiar.

    Rozwiązanie, które przedstawiłem jest w tym przypadku lepsze, bo każdy ciąg jest zapisany we flash jeden po drugim (bez niepotrzebnych odstępów), a tablica struktur zawiera tylko wskaźniki do tych ciągów. Nie zawsze jednak takie rozwiązanie jest lepsze. Gdy większość ciągów znaków będzie miała zbliżoną długość, strata związana z zapisaniem ich bezpośrednio w strukturze może być mniejsza, niż strata związana z osobnym zapisywaniem ciągów i dodatkowym zapisywaniem wskaźników do nich w strukturze.

    Wybór rozwiązania zależy więc od tego, na jakich danych operujesz, a nie od tego, że nie da się tego inaczej zrobić (jak zasugerowałeś).

    Tyle już chyba wystarczy, bo niedługo napiszę ten program za Ciebie. :)
    Musisz jeszcze sporo poczytać o wskaźnikach, strukturach i tablicach, żeby to dobrze opanować, zanim przystąpisz do trudniejszych rzeczy.
    Kolega tmf ma absolutną rację, że taką podstawową wiedzę należy zdobywać samodzielnie z książek lub kursów internetowych. Forum do tego nie służy.

    I nie bierz tego "do siebie". Nikt tu nie sugeruje, że jesteś głupi. Nawet Einstein nie urodził się z wiedzą, którą posiadał na koniec życia. Sugerujemy tylko, żebyś uczył się "po kolei" (nie mylić z PKP :)), bo programowanie to wiedza raczej dosyć ścisła i nie da się pewnych rzeczy pominąć.

    0
  • #14 19 Paź 2011 15:34
    gwozdex
    Poziom 13  

    Witam!
    Nie ma co... zmiażdżyliście mnie wiedzą Panowie :).
    :arrow: Andrzej__S Oczywiście nie biorę tego do siebie, ale posłuchać konstruktywnej krytyki jest zawsze dobrze.
    podany kod działa wyśmienicie.

    Cytat:
    Kolega tmf ma absolutną rację, że taką podstawową wiedzę należy zdobywać samodzielnie z książek lub kursów internetowych. Forum do tego nie służy.


    Może macie jakieś godne polecenia kursy (przeglądałem kilka ale jakoś mi nie spasowały...)

    Jeszcze raz wielkie dziękuję za pomoc.
    Pozdrawiam.
    gwozdex

    0
  • #16 15 Paź 2012 16:57
    gwozdex
    Poziom 13  

    Witam!
    Tytułem zamknięcia tematu zamieszczam listing gotowego programu. Jest on w zasadzie zebraniem w całość Waszych podpowiedzi z postów powyżej. Jeszcze raz wielkie dzięki za pomoc.

    Pozdrawiam.
    gwozdex

    0