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

[AVR][C] Struktury w pamięci flash i wskaźniki do funkcji

golas17 14 Paź 2009 10:24 2969 5
  • #1 7126656
    golas17
    Poziom 16  
    Witam,
    Po pierwsze. Chciałbym przenieść całą strukturę do pamięci flash:

    
    typedef struct
    {
        unsigned char state;
        unsigned char input;
        unsigned char nextstate;
    } MENU_NEXTSTATE;
    
    
    typedef struct
    {
        unsigned char state;
        unsigned char *pText;
        unsigned char (*pFunc)(unsigned char input);
    } MENU_STATE;


    Czy możecie mi wyjaśnić gdzie mam dopisać PROGMEM czy coś w tym rodzaju?

    Po drugie. Struktura MENU_STATE zawiera element będący wskaźnikiem do funkcji. Stworzyłem sobie tablicę:

    const MENU_STATE menu_state[] PROGMEM = {
    //  STATE                               STATE TEXT                  STATE_FUNC
        {ST_ROBOT_STOP,                     MT_ROBOT_STOP,              NULL},
        {ST_ROBOT_START,                    MT_ROBOT_START,             NULL},
        {ST_CZY_WYSTARTOWAC,                MT_CZY_WYSTARTOWAC,			RobotStart},
        {ST_USTAW_PROMIEN,                  MT_USTAW_PROMIEN,           NULL},
        {ST_USTAW_DYSTANS,                  MT_USTAW_DYSTANS,           NULL},
        {ST_EDYTUJ_DYSTANS,                 MT_EDYTUJ_DYSTANS,		    NULL},
        {ST_EDYTUJ_PROMIEN,                 MT_EDYTUJ_PROMIEN,          NULL},
    
        {0,                                 NULL,                       NULL},
    };

    Jak widać w tej tablicy znajduje się jakaś tam przykładowa funkcja RobotStart (adres funkcji).
    W programie głównym chciałbym do wskaźnika:
    unsigned char (*pStateFunc)(unsigned char);

    przypisać właśnie tą funkcję. Polecenie:
    pStateFunc = pgm_read_byte(&menu_state[i].pFunc);

    nie działa. Jak to się robi prawidłowo? Poza tym dostaję warningi typu:
    "assignment makes pointer from integer without a cast"
    "cast to pointer from integer of different size"
    Wiem że coś jest nie tak ze wskaźnikami, ale nie wiem co (niewiedza szkodzi...)

    Proszę o pomoc i dziękuję z góry za porady
  • Pomocny post
    #2 7126739
    Freddie Chopin
    Specjalista - Mikrokontrolery
    golas17 napisał:
    Czy możecie mi wyjaśnić gdzie mam dopisać PROGMEM czy coś w tym rodzaju?

    Powinno wystarczyć przy deklaracji konkretnej zmiennej, a jak nie to wszędzie gdzie popadnie [;

    Cytat:
    Polecenie:
    pStateFunc = pgm_read_byte(&menu_state[i].pFunc);

    nie działa. Jak to się robi prawidłowo?

    Wskaźnik do funkcji na pewno jest dłuższy niż 1 bajt, zapewne 2, ale zamiast zgadywać lepiej zastosuj funkcję memcpy_P(&pStateFunc, &menu_state[i].pFunc, sizeof(unsigned char (*)(unsigned char)));

    Cytat:
    Poza tym dostaję warningi typu:
    "assignment makes pointer from integer without a cast"
    "cast to pointer from integer of different size"
    Wiem że coś jest nie tak ze wskaźnikami, ale nie wiem co (niewiedza szkodzi...)

    pgm_read_byte() zwraca pewnie uint8_t, a ty chcesz wskaźnik, stąd warning. Pomijając fakt, że całość nie działa, bo odczytujesz zbyt mało danych, to wystarczy wtedy rzutować

    wskaznik = (unsigned char (*)(unsigned char))pgm_read_byte(...);

    ale pamiętaj o tym, że nie tu tkwi błąd i to nie zadziała i tak!

    4\/3!!
  • #3 7126747
    szelus
    Poziom 34  
    golas17 napisał:
    Polecenie:
    pStateFunc = pgm_read_byte(&menu_state[i].pFunc);

    nie działa. Jak to się robi prawidłowo?


    Prawie dobrze. Powinno być:
    
    pStateFunc = (unsigned char(*)(unsigned char))pgm_read_word(&menu_state[i].pFunc);

    Bo wskaźniki są 16-to bitowe.
    Nalepiej zrób sobie typedef na typ fukcji callback:
    
    typedef unsigned char (*CallbackFunc_t)(unsigned char);
    

    Sugestia - wprawdzie kompilatorowi to obojętne, ale przyjęte jest, że nazwy z samych dyżych liter są zastrzeżone dla makr (#define).
  • #4 7126826
    golas17
    Poziom 16  
    Dziękuję bardzo - już działa wszystko tak jak powinno :D
    Mam jeszcze tylko pytania do tych zapisów - co oznaczają:
    - te rzutowania... po co to...
    pStateFunc = (unsigned char(*)(unsigned char))pgm_read_word(&menu_state[i].pFunc);


    - czy ta instrukcja z typedef spowoduje że w programie będę później wywoływał coś w stylu:
    CallbackFunc_t=pgm_read_word(&menu_state[i].pFunc);

    Czy nie do końca o to chodzi...

    Dodano po 2 [minuty]:

    To rzutowanie to taka informacja, że: "to co odczytałeś spod podanego adresu jest wkaźnikiem do funkcji z takim a takim argumentem i zwracającym to i to"
    Dobrze?
  • Pomocny post
    #5 7127312
    szelus
    Poziom 34  
    golas17 napisał:
    To rzutowanie to taka informacja, że: "to co odczytałeś spod podanego adresu jest wkaźnikiem do funkcji z takim a takim argumentem i zwracającym to i to"
    Dobrze?


    Generalnie tak. Rzutowanie w C to w zasadzie informacja dla kompilatora, że programista wie, co robi. :wink:

    Z tym typedef to tak:
    
    typedef unsigned char (*CallbackFuncPtr_t)(unsigned char); 
    
    typedef struct
    {
        unsigned char state;
        unsigned char *pText;
        CallbackFuncPtr_t pFunc;
    } MenuState_t;
    
    CallbackFuncPtr_t pStateFunc;
    
    pStateFunc = (CallbackFuncPtr_t)pgm_read_word(&menu_state[i].pFunc);
    


    Z tym, że tak jak Freddie zaproponował, użycie memcpy_P byłoby bardziej eleganckie - nie trzeba się przejmować czy pamiętać, ile bajtów zajmuje wskaźnik.
  • #6 7128196
    golas17
    Poziom 16  
    Dziękuję Wam bardzo za pomoc. Problemy zostały rozwiązane a wątpliwości rozwiane. Pozdrawiam
REKLAMA