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

[avr-gcc] Błąd kompilacji: brak definicji funkcji `sbi` w kodzie AVR

yorek 29 Kwi 2005 16:14 35747 42
Najlepsze odpowiedzi LABEL_AI_GENERATED

Dlaczego avr-gcc zgłasza brak definicji `sbi` przy kompilacji prostego programu AVR i jak zastąpić `sbi(DDRB,PB1); sbi(PORTB,PB1);`?

W nowszym avr-gcc nie używaj `sbi/cbi`, tylko operacje na bitach, np. `DDRB |= _BV(PB1); PORTB |= _BV(PB1);` [#1448211][#1777654] `|=` ustawia wskazany bit w rejestrze, a `_BV(bit)` daje maskę bitową (`1 << bit`) [#1448273] Jeśli robisz z tego makro, pamiętaj też o poprawnym użyciu średników i nawiasów, bo makra są tylko podstawianiem tekstu, a nie „funkcją” sprawdzaną przez kompilator [#3452361]
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
  • #1 1448176
    yorek
    Poziom 12  
    Posty: 37
    Pomógł: 1
    Ocena: 1
    witam
    zainstalowałem winavr, przepisałem przykład:

    #include <avr/io.h>
    
    #define LED_ON sbi(DDRB,PB1);sbi(PORTB,PB1)
    
     
    
    int main (void) 
    
    {
    
    	LED_ON;
    	
    
        for (;;) 
    
       {
    
       
    
       }
    
     
    
        return (0);     
    
    }
    
     


    i dostaje:
    > "make.exe" all
    avr-gcc -g -Wall -O2 -mmcu=atmega8    -c -o 1.o 1.c
    1.c: In function `main':
    1.c:11: warning: implicit declaration of function `sbi'
    avr-gcc -g -Wall -O2 -mmcu=atmega8  -Wl,-Map,1.map -o 1.elf 1.o 
    1.o(.text+0x10): In function `main':
    C:\avr_c/1.c:11: undefined reference to `sbi'
    1.o(.text+0x1a):C:\avr_c/1.c:11: undefined reference to `sbi'
    make.exe: *** [1.elf] Error 1
    
    > Process Exit Code: 2

    o co chodzi??
  • #2 1448199
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    https://www.elektroda.pl/rtvforum/topic274287.html#1379189
    - i nie ma więcej pytań... Jak to znalazłem ?
    Wpisałem "implicit declaration of function" (łącznie z cudzysłowami) w "szukaj", znajdującym się u góry każdej strony na elektrodzie, wybierając jeszcze forum "mikrokontrolery", aby wyników nie było w innej tematyce.
    Pozdrawiam, Light'I
  • #4 1448246
    yorek
    Poziom 12  
    Posty: 37
    Pomógł: 1
    Ocena: 1
    Light'­­­­I napisał:
    Jak to znalazłem ?

    no tak, nie popisałem się, przepraszam

    Cytat:
    #define LED_ON DDRB |= _BV(PB1); PORTB |= _BV(PB1)

    a jak to rozszyfrować? jakie działanie oznacza |= i co to jest _BV ?
  • #5 1448273
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    yorek napisał:
    jakie działanie oznacza |= i co to jest _BV ?

    |= to OR z jakąś stałą/zmienną, wynik i operator to ta sama zmienna.
    PORTB|=_BV(PB1) to to samo co PORTB=PORTB|_BV(PB1)
    _BV to makro wyłuszczające bit do jego wartości liczbowej. PB1 to inaczej 1, więc _BV(1) = $$2^1$$ = 2
    Sporo informacji jest też w dokumentacji avrgcc...
    Pozdrawiam, Light'I
  • #6 1777466
    valarian
    Poziom 22  
    Posty: 647
    Pomógł: 33
    Ocena: 112
    Czy ponizsze instrukcje odpowiadaja tym po lewej stronie?
    PORTC |= _BV(0); sbi(PORTC, PC0);
    PORTC &= _BV(0); cbi(PORTC, PC0);
    DDRC |= _BV(0); sbi(DDRC, PC0);
    DDRC &= _BV0(0); cbi(DDRC, PC0);
    PORTC & _BV(0); bit_is_set(PORTC, PC0)
    !(PORTC & _BV(0)); bit_is_clear(PORTC, PC0)

    Nie wiem tylko, co robi ta instrukcja i jaki ma odpowiednik w takich "standardowych" funkcjach jak cbi() itp.
    PORTC ^= _BV(0);
    Moderowany przez Light-I:

    Nie zakładaj nowego tematu, gdy był już omawiany !!! Następnym razem żółta kartka...

  • #7 1777540
    Jacu$
    Poziom 27  
    Posty: 730
    Pomógł: 119
    Ocena: 26
    Przeczytaj to a wszystko stanie się jasne.

    Moderowany przez Light-I:

    Wstawiono dodatkowe podkreślenie w linku dla poprawy czytelności.

  • #8 1777574
    valarian
    Poziom 22  
    Posty: 647
    Pomógł: 33
    Ocena: 112
    Spoko, tylko jeszcze nie wiem, do czego jest zmienna ^= _BV(numer_bitu);

    I czy sbi(PORTC, 3) ustawi mi 3 bit, czy musze uzyc sbi(PORTC, _BV(3))?
  • #9 1777620
    Jacu$
    Poziom 27  
    Posty: 730
    Pomógł: 119
    Ocena: 26
    Nie wiesz, bo nie przeczytałeś:
    Cytat:
    zmienna ^= _BV(numer_bitu); // przełączenie bitu


    Jak chcesz ustawić bit 3 w porcie C to musisz napisać:
    PORTC |= _BV(3);
  • #10 1777625
    valarian
    Poziom 22  
    Posty: 647
    Pomógł: 33
    Ocena: 112
    Przeczytalem... Tylko nie wiem, co to jest przelaczenie bitu...?
    A sbi(PORTC, _BV(3)) nie ustawi bitu?
  • #11 1777654
    Jacu$
    Poziom 27  
    Posty: 730
    Pomógł: 119
    Ocena: 26
    Przełączenie to zmiana na przeciwną wartość (jeśli było zero to zrobi się jeden i na odwrót).

    Cytat:
    A sbi(PORTC, _BV(3)) nie ustawi bitu?

    Nie, to nie ma sensu. Jeśli już się upierasz przy sbi to:
    sbi(PORTC,PC3);

    Ale ostrzegam: sbi / cbi już nie będzie w nowych wersjach kompilatora więc po co się tego uczyć?
  • #12 3296458
    Kuniarz
    Moderator Projektowanie
    Posty: 4520
    Pomógł: 371
    Ocena: 826
    Sorry za odgrzanie tematu, to moje pierwsze w życiu zapalanie diodki przez uC ;-)

    Kod:

    
    #include <avr/io.h>
    #define LED_ON DDRB |= _BV(PB1); PORTB |= _BV(PB1)
    
    int main (void)
    {
    	LED_ON
    	
    	for (;;)
    	{
    	
    	}
    	
    return (0)
    }
    


    kompoilacja wywala error : led.c:8: error: syntax error before "for"

    szukałem, niewiele znalazłem... co jest nie teges ?
    Pomogłem? Kup mi kawę.
  • #13 3296467
    wojtkow
    Poziom 14  
    Posty: 80
    Pomógł: 9
    Dodaj średnik po LED_ON w funkcji main

    
    #include <avr/io.h>
    #define LED_ON DDRB |= _BV(PB1); PORTB |= _BV(PB1)
    
    int main (void)
    {
       LED_ON;
       
       for (;;)
       {
       
       }
       
    return (0)
    }
    
  • #14 3296481
    Kuniarz
    Moderator Projektowanie
    Posty: 4520
    Pomógł: 371
    Ocena: 826
    o ja ślepa kura, morał z tego taki że nie można grać w Warcrafta do 12 w nocy bo na drugi dzień rano nie widzi się wszystkiego :D

    DZIEKI

    Dodano po 4 [godziny] 59 [minuty]:

    Przepraszam że znów zawracam gitare, ale znalazłem w necie kurs dla zielonych pod adresem www.patron.net.pl - jest tam łopatologicznie wszystko opisane, co dla mnie jest istotne póki co.
    Znów utknęłem na programiku do migającej diody (poprzedni zadziałał...):

    
    #include <avr/io.h>
    /*
    ************* definicje stalych ***********
    */
    #define F_CPU 1000000    /* 1MHz zegar procesora */
    #define CYCLES_PER_US ((F_CPU+500000/1000000  /* cykle cpu na milisekunde */
    #define LED_ON DDRB |= _BV(PB1); PORTB |= _BV(PB1)
    #define LED_OFF DDRB |= _BV(PB1); PORTB &= _BV(PB1)
    
    void delay(unsigned int us)
    {
    	unsigned int delay_loops;
    	register unsigned int i;
    	delay_loops = (us+3)/5*CYCLES_PER_US;
    	for (i=0; i<delay_loops; i++) {};
    }
    void delayms(unsigned int ms)
    {
    	unsigned int i;
    	for (i=0;i<ms;i++)
    		{
    			delay(999);
    			asm volatile (
    			"WDR"::);
    			}
    		}
    		
    	
    int main (void)
    {
    	LED_ON;
    	
    	for (;;)
    	{
    	LED_ON;
    	delayms(1000);
    	LED_OFF;
    	delayms(1000);
    	}
    	
    return (0);
    }
    


    Czy ja znów czegoś nie widzę czy to jest poprostu do bani ?
    Pomogłem? Kup mi kawę.
  • #15 3299825
    VIRUS
    Poziom 15  
    Posty: 77
    Pomógł: 10
    Ocena: 3
    #define CYCLES_PER_US ((F_CPU+500000/1000000  /* cykle cpu na milisekunde */ 


    1. Licz nawiasy... (Każdy otwarty nawias musisz w końcu zamknąć)
    2. Kopiuj - Wklej zamiast przepisywać - będzie mniej takich pomyłek
    3. Czytaj komunikaty kompilatora (Po piątym przeczytaniu zrozumiesz o co mu chodzi, co może być źle)
  • #16 3303457
    Sind
    Poziom 16  
    Posty: 182
    Pomógł: 9
    Ocena: 3
    Witam czytających

    Jezeli chodzi o wl/wyl diody to mozesz to zrobic tak Kuniarz:

    #include <avr/io.h>

    #define LED_ON DDRB=_BV(PB4)
    #define LED_OFF DDRB=!DDRB

    int main(void) {

    unsigned int i;

    while(1){
    LED_ON;

    for(i=0;i<0xFF;i++){};

    LED_OFF;

    for(i=0;i<0xFF;i++){};


    }
    }

    Oczywiscie opoznienia mozesz sobie wstawiac po swojemu, ja pisalem na szyko :) milego eksperymentowania

    Pozdrawiam

    --------------------------------------------------------------------
    AVR Studio 4.12
  • #17 3304137
    wojtkow
    Poziom 14  
    Posty: 80
    Pomógł: 9
    @Sind - a dlaczego ustawiasz tylko rejestr DDRB (czyli kierunek działania portu) a nie ustawiasz stanów pinów w PORTB ??
    Wg mnie kod powinien wyglądać tak: (pominąłem definicję funkcji opóźniającej waitms)

    
    #include <avr/io.h>			// AVR device-specific IO definitions
    
    #define bit_set(v,m) ((v) |= (m))
    #define bit_clear(v,m) ((v) &= ~(m))
    
    int main(void){
       PORTB = 0x00;
       DDRB  = 0x01;
    
       bit_clear(PORTB,_BV(0));
       while(1){
    
    		bit_set(PORTB,_BV(0));
    		waitms(250);
    		waitms(250);
    		bit_clear(PORTB,_BV(0));
    		waitms(250);
    		waitms(250);
    	}
       return 0;
    }
    
  • #18 3304527
    Sind
    Poziom 16  
    Posty: 182
    Pomógł: 9
    Ocena: 3
    Widzisz.... ja to robilem na szydko :) ustaiwenie bitu w porcie moze byc zrobione w ten sam sposob, np:

    #define LED_ON PORTB=_BV(PB5);DDRB=_BV(PB5)
    #define LED_OFF PORTB=!_BV(PB5);DDRB=!_BV(PB5)

    albo nie uzywajac DDRB


    #define LED_ON PORTB=_BV(PB4)
    #define LED_OFF PORTB=!_BV(PB4)

    i to tez dziala :)

    POZDRAWIAM :):)

    Dodano po 3 [minuty]:

    ...Zapomnialem dodac ze Twoj program jest uniwersalny i zapis jest bardzo ogolny i uniwersalny w zastosowaniu :) .... sam bede z niego korzystal - dzieki :)
  • #19 3304632
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1464
    Ludzie !!!
    Nie uczcie innych ludzi takich #define

    Przecież to horror, jak to użyć w nieco innym konteksie.

    a) podstawienie w #define !!!
    b) sklejane instrukcje ; nie zamkniete nawiasami
    c) nawiasy nie do pary
    z takimi nawykami potem ktoś ciężko szuka błedu w 'bezbłednym' kodzie.

    Błedy w makrach NIE SĄ diagnozowane przez kompilator, to czyste wstawienie tekstu.
    Te problemy które ma kolega, to zaledwie przedsmaktego co może być.

    A na zapis podobny do funkcji jest śliczna funkcja 'inline', w pełni sprawdzana przez kompilator, będąca jakąś tam sensowną całością.

    zamiast
    #define LED_OFF PORTB=!_BV(PB4)
    inline void LED_OFF(void)
    {
    PORTB=!_BV(PB4) ;
    }

    wydajnośc ta sama, formalnie poprawne itd.

    Jak już ktoś MUSI, naprawdę MUSI (kompilatory w starym standardzie), względnie najmniej złe będzie:

    #define LED_ON() {sbi(DDRB,PB1);sbi(PORTB,PB1) ;}
  • #20 3315345
    Sind
    Poziom 16  
    Posty: 182
    Pomógł: 9
    Ocena: 3
    Kolego JackuCz to jaki ktos kod uzywa to jest jego indywidualna sprawa :) to po pierwsze, a po drugie najnowszy AVRStudio 4.12 nie obslugyje ani sbi, ani cbi wiec napisanie tej samej linijki jak u pana:

    #define LED_ON() {sbi(DDRB,PB1);sbi(PORTB,PB1) ;}

    rownowazy sie z tym co bylo podane wczesniej:

    #define LED_ON PORTB=_BV(PB4)

    wiec nie ma co podnosic glosu :) a jezeli chodzi koledze o nawiasy to prosze spojrzec ile jest w instrukcji wyzej a ile w tej nizej..... :)

    Pozdrawiam
  • #21 3315511
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Sind napisał:
    Kolego JackuCz to jaki ktos kod uzywa to jest jego indywidualna sprawa :) to po pierwsze...

    Owszem , dopuki ten KTOŚ , nie "upublicznia" tego kodu.
    Sind napisał:
    ... , a po drugie najnowszy AVRStudio 4.12 nie obslugyje ani sbi, ani cbi wiec napisanie tej samej linijki jak u pana:

    A kto Panu powiedział , że nie obsługuje :?:
    Poza tym , pomylił Pan AVRStudio z AVR-GCC .
    Jedźmy dalej:
    Sind napisał:

    
    #define LED_ON() {sbi(DDRB,PB1);sbi(PORTB,PB1) ;}
    

    rownowazy sie z tym co bylo podane wczesniej:
    
    #define LED_ON PORTB=_BV(PB4) 
    

    Dlaczego Pan operuje na całym porcie , a nie na pojedynczym bicie :?:
    A co z kierunkiem(DDRB) :?:
    Sind napisał:

    wiec nie ma co podnosic glosu :) a jezeli chodzi koledze o nawiasy to prosze spojrzec ile jest w instrukcji wyzej a ile w tej nizej..... :)
    Pozdrawiam

    Dokładnie , tylko trzeba wiedzieć CO się pisze :(

    Pozdrawiam
    Piotrek
  • #22 3319542
    Sind
    Poziom 16  
    Posty: 182
    Pomógł: 9
    Ocena: 3
    No ja widze ze kolega robi problem z czegos czego nie ma :)

    Napisalem wczesniej ze mozna skonfigurowac tak:


    #define LED_ON PORTB=_BV(PB5);DDRB=_BV(PB5)
    #define LED_OFF PORTB=!_BV(PB5);DDRB=!_BV(PB5)


    i bardzo prosze i DDRB tez jest uzyty :)

    A jezeli kolega nie wie ze najnowszy AVRStudio korzysta wlasnie z kompilatora avr-gcc .... pozostawiam bez komentarza

    i dlatego uzywa sie skryptu _BV() :)

    Pozdrawiam
  • #23 3319750
    wojtkow
    Poziom 14  
    Posty: 80
    Pomógł: 9
    @Sind - kiedy Twój przykład jest ewidentnie zły, bo:

    1. operujesz na całym porcie - a chcesz ustawić jeden bit

    #define LED_ON PORTB=_BV(PB5);DDRB=_BV(PB5) 

    da na porcie B po wykonaniu 00100000 nie zależnie od tego co było wcześniej. Powinieneś to zrobić tak
    PORTB |= _BV(5);

    2. ustawiasz kierunek portu (DDRB) dopiero po jego zapisie
    3. Ustawiasz kierunek portu przy każdej operacji - dla mnie jest to zbędne.

    BTW. _BV to nie skrypt a makro o następującej treści
    #define _BV(bit) (1 << (bit))
  • #24 3319876
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Sind napisał:
    No ja widze ze kolega robi problem z czegos czego nie ma :)

    Napisalem wczesniej ze mozna skonfigurowac tak:


    #define LED_ON PORTB=_BV(PB5);DDRB=_BV(PB5)
    #define LED_OFF PORTB=!_BV(PB5);DDRB=!_BV(PB5)


    i bardzo prosze i DDRB tez jest uzyty :)

    Nadal nie wiesz CO piszesz :(

    Sind napisał:

    A jezeli kolega nie wie ze najnowszy AVRStudio korzysta wlasnie z kompilatora avr-gcc .... pozostawiam bez komentarza :)

    Idąc tym tropem można by równie dobrze napisać , że Windows XP+SP2 "nie obsluguje ani sbi, ani cbi" :(
    Piotrek
  • #25 3447810
    smajlas
    Poziom 12  
    Posty: 74
    Pomógł: 1
    Ocena: 2
    Po skompilowaniu pliku abc otrzymalem kilka dodatkowych, kolejne rozszerzenia to: abc.elf, abc.lst, abc.map, abc.o oraz abc.rom Który z nich nadaje się do wgrania do uPC?? (czy nie powinienem też mieć abc.hex ?? a jeśli tak, to gdzie on jest?? )
  • #26 3450546
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1464
    yorek napisał:
    witam
    zainstalowałem winavr, przepisałem przykład:

    #include <avr/io.h>
    
    #define LED_ON sbi(DDRB,PB1);sbi(PORTB,PB1)
    
     
     




    Zawsze sie zastanawialem skąd pokutują wśród uKontrolerowców takie tragiczne wzory użycia C.
    Nie mówcie że takie antyprzykłady to jest oficjalne wydanie ?????? Nie wierzę!!!!


    PS. Propozycje innych makr w tym wątku (pod względem formalnym i jakości kodu, nie sterowania uP, o tym sie nie wypowiadam) TEŻ MI JEŻĄ (ostatnie) WŁOSY.

    Autorzy maja wylot z każdego stanowiska programisty C, jakie by próbowali objąć (a ja bym miał na to wpływ).
  • #27 3451746
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    JacekCz napisał:
    ...Autorzy maja wylot z każdego stanowiska programisty C, jakie by próbowali objąć (a ja bym miał na to wpływ).

    Możesz nas nieco oświecić łaskawco :?:

    Piotrek
  • #28 3452361
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1464
    zumek napisał:
    JacekCz napisał:
    ...Autorzy maja wylot z każdego stanowiska programisty C, jakie by próbowali objąć (a ja bym miał na to wpływ).

    Możesz nas nieco oświecić łaskawco :?:

    1. Od czasu do czasu jestem w jakims projekcie C/C++ (na duże PC) 'seniorem' i próby zatrudnienia programisty pokazują tragiczny średni poziom programistów który podają język C w swoim CV. Nawet nie to, że mało, ale nieprawidłowe nawyki, a tych sie od kogos nauczyli.

    2. O makrach #define (bardziej niebezpiecznych i mniej niebezpiecznych ale ciągle niebezpiecznych) i alternatywnych opcjach pisałem tutaj więc można przeszukać.

    Krótki przykład:

    
    if(i==1)
     LED_ON
    


    Kto ma oczy niechaj patrzy.
    [/code]
  • #29 3454693
    wojtkow
    Poziom 14  
    Posty: 80
    Pomógł: 9
    Faktycznie dobry przykład pokazujący że przede wszystkim trzeba rozumieć co się pisze.

    Co do nadużywania makr, to wina niestety paru kursów umieszczonych w sieci, które uczą właśnie takiego stylu - wspomniane makro LED_ON występuje przynajmniej w dwóch znanych mi.
  • #30 3455058
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1464
    wojtkow napisał:
    Faktycznie dobry przykład pokazujący że przede wszystkim trzeba rozumieć co się pisze.

    Co do nadużywania makr, to wina niestety paru kursów umieszczonych w sieci, które uczą właśnie takiego stylu - wspomniane makro LED_ON występuje przynajmniej w dwóch znanych mi.


    Minister Giertych powinien wprowadzić obcinanie łap autorom takich kursów. Taki powrót do tradycyjnych wartości.
    Chyba że to absolweni giertychowskiej matury z matematyki i logiki.

Podsumowanie tematu

LABEL_AI_GENERATED
Problem dotyczy błędu kompilacji w kodzie AVR, gdzie funkcja `sbi` (set bit in I/O register) jest niezdefiniowana, co powoduje ostrzeżenia i błędy linkera podczas kompilacji przy użyciu avr-gcc i WinAVR. Dyskusja wyjaśnia, że makra `sbi` i `cbi` nie są już wspierane w nowszych wersjach kompilatora avr-gcc i zaleca się zastąpienie ich operacjami bitowymi z użyciem makra `_BV(bit)`, np. `PORTB |= _BV(PB1);`. Operator `|=` oznacza bitowe OR z przypisaniem, a `_BV(bit)` to makro przesuwające bit na odpowiednią pozycję. Wskazano, że makra definiujące wielokrotne instrukcje powinny być poprawnie zamknięte w nawiasy lub lepiej zastąpione funkcjami inline dla czytelności i bezpieczeństwa kodu. Poruszono także kwestie poprawnego ustawiania kierunku portu (DDRx) i stanu portu (PORTx) oraz unikania nadpisywania całych portów zamiast pojedynczych bitów. Wskazano, że `sbi` i `cbi` były wygodnymi, ale przestarzałymi makrami, a nowoczesne podejście to używanie `_BV()` i operatorów bitowych. Dodatkowo omówiono dobre praktyki programistyczne w C dotyczące makr i inline, a także problemy z błędami składniowymi wynikającymi z braku średników lub nawiasów. W dyskusji pojawiły się także przykłady poprawnego kodu do sterowania diodą LED na mikrokontrolerze AVR oraz uwagi dotyczące optymalizacji i debugowania kodu.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA