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

Linker error przy kompilacji programu AVR w AVRside - co poprawić?

dzik84 25 Mar 2006 18:41 2164 29
REKLAMA
  • #1 2456466
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    Co jest nie tak?

    oto program:
    #include <interrupt.h>
      #include <delay.h>
      
      #define tau0 250;
      
      unsigned char liczt0;
      
      SIGNAL (SIG_OVERFLOW0)
      
      {
       TCNT0=tau0;
       ircr liczt0;
       
       if(liczt0==5)
    	{
    	  liczt0=0;
          PORTB.0=1;
          _delay_us(1500);
          PORTB.0=0;
         }
       }
       
       
     int main(void)
      {
       DDRB=0xFF;
       TIMSK=1<<TOIE0
       TCNT0=tau0
       TCCR0=4
       
       sei();
       }
  • REKLAMA
  • #2 2456653
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    A wskazales w opcjach AVRSIDE plik wykonawczy avr-gcc.exe ?? Znajduje sie on w katalogu WINAVR/BIN .
  • #3 2456846
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    Nie, ale już to zrobiłem.
    teraz wyskoczyły mi jeszcze inne błędy, część poprawiłęm ale zostały jeszcze dwa odnośnie sterowania portem b.0
    pisze:
    error: syntax error before numeric constant

    to kod:
      #include <avr/interrupt.h>
      #include <util/delay.h>
    
      #define tau0 250;
    
      unsigned char liczt0;
    
      SIGNAL (SIG_OVERFLOW0)
    
      {
       TCNT0=tau0;
       liczt0=liczt0+1;
    
       if(liczt0==5)
    	{
    	  liczt0=0;
          PORTB.0=1;
          _delay_us(1500);
          PORTB.0=0;
         }
       }
    
    
     int main(void)
      {
       DDRB=0xFF;
       TIMSK=1<<TOIE0;
       TCNT0=tau0;
       TCCR0=4;
       sei();
       }


    i co jeszcze trzeba ustawić w avrside?
    bo jak dałem prosto z książki sbi(PORTB,0) to pisał
    implicit declaration of function 'sbi'
  • REKLAMA
  • #4 2456932
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    Sbi i Cbi zostaly "wycofane" z nowszych wersji WINAVR , wiec one juz nie dzialaja. Natomiast :




    .. Przyzwyczajenia z Bascoma??
    Taki numer w GCC niestety nie przejdzie :)

    Zeby ustawic jakis bit portu trzeba napisac :

    PORTB|=(1<<PB0) - ustawiamy bit 0 portu B. PB0 jest zdefiniowane w standardowych bibliotekach WINAVR po prostu jako 0 , PB1 jako 1 itp. wiec mozna zapisac też PORTB|=(1<<0).

    Poza tym
    
      liczt0=liczt0+1;
    
    


    mozesz zapisać jako
    liczt0++;
  • #5 2457891
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    Poprawiłem to, program kompiluje sie ale z ostrzeżeniami i nie działa
    wywala:
    #warning "F_CPU not definied for <util/delay.h>"
    control reaches end of non-void function

    jak wgrałem ten program pomimo tych ostrzeżeń to na wyjściu procka było coś o częstotliwości zbliżonej do 40Hz ale zmieniającej się, na oscyloskopie widziałem skracający się impuls sterujący servem które w tym czasie warjowało a po chwili nie było już nieczego na wyjściu
  • REKLAMA
  • #6 2458162
    Ireq
    Poziom 13  
    Posty: 56
    Pomógł: 1
    Ocena: 1
    Nie wiem czy to pomoze ale Linker error to zazwyczaj blad w pliku .h dolaczonym do projektu, napewno odwolujesz sie w projekcie do funkcji ktora nie istnieje w pliku .h albo cos w tym stylu. Ja tak czasami mam.
  • #7 2458271
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    dzik84 napisał:
    Poprawiłem to, program kompiluje sie ale z ostrzeżeniami i nie działa
    wywala:
    #warning "F_CPU not definied for <util/delay.h>"




    Dzieje sie tak dlatego, że kożystasz z biblioteki delay.h Biblioteka ta wymaga podania czestotliwosci kwarcu, jesli jej nie podasz zaostaje przyjeta czestotliwosc domyslna ,ktore moze sie nie zgadzac z faktyczna predkoscia twojego kwarcu. Jak chcesz zobaczy jak ta funkcja delay.h wyglada , wejdz do katalogu WINAVR/util tam znajdziesz funkcje delay.h

    Zeby to bylo zrobione poprawinie najlepiej zawsze na poczatku programu definiuj sobie czestotliwosc kwarcu :

    #define F_CPU 8000000 // zdefiniowana czesto kwarcu 8MHz

    Po tym nie powinno byc juz problemow.

    Aha i jeszcze jedna sprawa .
    dzik84 napisał:

    control reaches end of non-void function

    Funkcja main nie moze sie konczyc!!


    
    
    int main(void)
      {
       DDRB=0xFF;
       TIMSK=1<<TOIE0
       TCNT0=tau0
       TCCR0=4
       
       sei();
       }
    


    Program rozpoczyna sie od funkcji main. Najpierw ustawiasz porty, potem rejestry timera ok, potem globalne zezwolanie na przerwania , a potem co sie dzieje??? Teoretycznie funkcja main sie konczy i stad to ostzrezenie, praktycznie WINAVR jest zabezpieczone przed takim czyms i chyba automatycznie powraca do poczatku funkcji main ale nie jestem pewien.
    Wiec zeby miec pewnosc ze nie bedzie jakis niespodzienak trzeba napisac tak:


    
    
    int main(void)
      {
       DDRB=0xFF;
       TIMSK=1<<TOIE0
       TCNT0=tau0
       TCCR0=4
       
       sei();
    
     while(1)        // dodajemy petle nieskonczona. 
    {}
    
    
       }
    
  • #8 2459995
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    Program sie teraz pięknie kompiluje ale sterowanie portem kompletnie nie działa - nic się nie dzieje

    Napisałęm też taki prosty programik:
      #define F_CPU 16000000
      #include <avr/io.h>
      #include <util/delay.h>
    
    
    int main(void)
      {
       DDRB=0xFF;
       PORTB|=(1<<PB0);
       _delay_ms(1000);
       PORTB|=(0<<PB0);
       PORTB|=(1<<PB1);
       while(1)
    {}
       }
       


    I też zero reakcji od strony procka
    :|
  • #9 2460467
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    No teraz to musi dzialac , a ustawiles odpowiednia czestotliwosc kwarcu za pomoca fusebitow ?

    Co do programu:
    
    int main(void)
      {
       DDRB=0xFF;                             
       PORTB|=(1<<PB0);           
       _delay_ms(1000);            
       PORTB|=(0<<PB0);       
       PORTB|=(1<<PB1);
       while(1)
    {}
       }
       


    Wszystko dziala tylko ze ty nie zauwazysz ze to dziala :>
    Funkcja _delay_ms(1000); jest ok tylko ze maks opoznienie dla tej funkcji oblicza sie :(dla kwarcu 16Mhz) (1/16000000)*65536*4 = 0,016509 s = 16 ms
    Wejdz do katalogu WinAvr/avr/include/util i tam jest f. delay.h Otworz ja i zobaczysz jak wyglada i dlaczego maks opoznienie to w tym przyoadku 16ms.
    Jest tam napisane :
    " The maximal possible delay is 262.14 ms " dla kwarcu 1Mhz , jak masz kwarc 16 Mhz to wszystko chodzi 16 razy szyvciej czyli 262/16 = 16 ms czyli tak jak Ci odliczylem wczesniej.

    Co do programu napisz tak :

    
    int main(void)
      {
     int i;
       DDRB=0xFF;                             
     
       PORTB|=(1<<PB1);
       while(1)
      {
       PORTB|=(1<<PB0);  
         for(i=0;i<30;i++)
         {         
          _delay_ms(1000);   
         }         
         PORTB|=(0<<PB0);       
    
     }
       }
    
    
       
  • #10 2460759
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    No dobra, zaraz sobie spr. ten programik.

    Ale czemu nie działa ten o który naprawde chodzi, fusy napewno dobrze ustawione bo analogiczny program w bascomie działa

    Wklejam kod jeszcze raz żeby nie było wątpliwości jak wygląda
      #define F_CPU 16000000
      #include <avr/interrupt.h>
      #include <util/delay.h>
      #define tau0 250;
    
      unsigned char liczt0;
    
      SIGNAL (SIG_OVERFLOW0)
    
      {
       TCNT0=tau0;
       liczt0++;
    
       if(liczt0==5)
    	{
    	  liczt0=0;
          PORTB|=(1<<PB0);
          _delay_us(1500);
          PORTB|=(0<<PB0);
         }
       }
    
    
     int main(void)
      {
       DDRB=0xFF;
       TIMSK=1<<TOIE0;
       TCNT0=tau0;
       TCCR0=4;
       sei();
       while(1)
    {}
       }
  • #11 2460869
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    Trochę zmieniłem Twój program (mam diody na Porcie C i nie używam biblitoek delay.h) i załączam mój program który napewno działa (mam ATmega16 z zewnętrznym kwarcem 16MHz).

    Na 99% u Ciebie brak dołączenia biblioteki signal.h

     #define F_CPU 16000000
      #include <avr/interrupt.h>
      #include <avr/signal.h>
    
      #define tau0 250;
    
      unsigned char liczt0;
    
      SIGNAL (SIG_OVERFLOW0)
    
      {
       TCNT0=tau0;
       liczt0++;
    
       if(liczt0==5)
       {
         liczt0=0;
          PORTC|=(1<<PC0);
     
         }
       }
    
    
     int main(void)
      {
       DDRC=0xFF;
       TIMSK=1<<TOIE0;
       TCNT0=tau0;
       TCCR0=4;
       sei();
       while(1)
    {}
       }
  • #12 2461553
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    W nowych wersjach WInAvr nie trzeba dolaczac biblioteki signal.h , wystarczy tylko interrupt.h , ale być moze masz werjse ktora wymaga jeszcze podania signal.h
  • #13 2461736
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    Ja mam wersję WinAVR 20040720 i rzeczywiście najnowsza to ona zdaje się nie jest. Wiem że u mnie jak załączyłem tą bibliotekę to programik zadziałał:)
  • #14 2468501
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    Nie wiem czemu ale jak teraz usuadłem znowu do tego, klikam make, to daje mi error
    undefinied reference to 'main'

    a jak dodam tą biblioteke signal.h to dostaje dodatkowo ostrzeżenie żebym użył biblioteki interrupt a ta jest zbędna
  • #15 2468886
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    No interrupt zbędna nie jest bo przecież wykorzystujesz przerwanie.

    A wkleiłeś ten program co ci podesłałem? Działał, czy to w nim te błędy wyrzuca?
  • #16 2469442
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    źle napisałęm tego posta, pisze że signal jest zbędna i żeby użyć interrupt, pozatym co mi po twoim programie jak musze zmieniać to wypełnienie i od tego ma byc funkcja delay
  • #17 2473426
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    Ja juz nie wiem co robić :cry::cry:

    Obojętnie jakiego kodu nie wkleje (przykłady z książki) to zawsze wyskakuje mi ten błąd:
    undefinied reference to 'main'

    ktoś wie co z tym zrobić?
  • #18 2475697
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    Dziwna sprawa. Cos musiales namieszac. Jak nie mzoesz sobie z tym poradzic to usun WINAVRa i AVRSIDE, wyczysc wszystko z katalogow po instalacji i zainstaluj jeszcze raz. Musi dzialac :)
  • Pomocny post
    #20 2480649
    Piroman1024
    Poziom 17  
    Posty: 171
    Pomógł: 18
    Ocena: 17
    dzik84 napisał:
    ...(undefinied reference to 'main')...
    [/url]


    A czy w AvrSide wybrałeś Nowy Projekt,potem procesor,kwarc,itd?
    Należy potem zapisać projekt i dopiero działać - przynajmniej u mnie ten błąd wyskakiwał jak próbowałem na 'sucho' pisać jakiś program ,mógł być najprostszy - tylko main.
  • #21 2480715
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    WIELKIE DZIĘKI DOBRY CZŁOWIEKU :)
  • #22 2484617
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    Hmm, no i dalej nie tak
    1.Te sterowanie portami PORTB|=(0<<PB0) nie działa, jedynie udało mi sie nimi sterować przez przypisanie np. PORTB=0xFF (sprawdzałęm to na prostym programiku "węża" na ledach)

    2.To co powstaje na wyjściu uC nie jest tym czym miało być, nazwałbym to sinusoidą w której linia ma kształt przebiegu prostokątnego :|
    Jest tak przez kilkanaście sekund po czym port jest ustawiany w stanie 1

         #define F_CPU 16000000
      #include <avr/interrupt.h>
      #include <util/delay.h>
      #define tau0 250;
    
      unsigned char liczt0;
    
      SIGNAL (SIG_OVERFLOW0)
    
      {
       TCNT0=tau0;
       liczt0++;
    
       if(liczt0==5)
       {
         liczt0=0;
          PORTB=0xFF;
          _delay_us(1500);
          PORTB=0x0;
         }
       }
    
    
     int main(void)
      {
       DDRB=0xFF;
       TIMSK=1<<TOIE0;
       TCNT0=tau0;
       TCCR0=4;
       sei();
       while(1)
    {}
       }
  • #23 2485256
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    Witam.

    Problem jest znowu z petla opozniajaca ,jak pisalem juz wczesniej.
    Przy kwarcu 16Mhz zapis _delay_us(1500); nie da opoznienia 1500us, poniewaz wartosc 1500 przekracza maksymalne opoznienie dla kwarcu 16Mhz!
    W bibliotece delay.h jest wyraznie napisane :

    
    /**
       \ingroup util_delay
    
       Perform a delay of \c __us microseconds, using _delay_loop_1().
    
       The macro F_CPU is supposed to be defined to a
       constant defining the CPU clock frequency (in Hertz).
    
       The maximal possible delay is 768 us / F_CPU in MHz.
     */
    


    Dla 16Mhz maks opoznienie wynosi 768/16= 48us
    Mozna wykorystac funkcje _delay_ms() , ale nie uzyskamy w niej opoznienia 1,5 ms bo nie mozna podawac wartosci ulamkowych.

    Proponuje przerobic nieco te funkcje opozniajace z biblioteki delay.h:

    
    void delays(uint16_t __count)
    {
    	__asm__ volatile (
    		"1: sbiw %0,1" "\n\t"
    		"brne 1b"
    		: "=w" (__count)
    		: "0" (__count)
    	);
    }
    
    
    static __inline__ void
    delay_us(double __us)
    {
    	uint16_t __ticks;
    	double __tmp = ((F_CPU) / 4e6) * __us;
    	if (__tmp < 1.0)
    		__ticks = 1;
    	else if (__tmp > 65535)
    		__ticks = 0;	
    	else
    		__ticks = (uint16_t)__tmp;
    	delays(__ticks);
    }
    


    napisz program tak :



    
    
    
     #define F_CPU 16000000
      #include <avr/interrupt.h>
    //  #include <util/delay.h>          //wywalamy ta funkcje, skorzystamy z wlasnej pozwalajacej na uzyskanie wiekszych opoznien w mikrosekundach 
      #define tau0 250;
    
      unsigned char liczt0;
    
    
    // nasza funkcja opozniajaca 
    void delays(uint16_t __count)
    {
    	__asm__ volatile (
    		"1: sbiw %0,1" "\n\t"
    		"brne 1b"
    		: "=w" (__count)
    		: "0" (__count)
    	);
    }
    
    
    static __inline__ void
    delay_us(double __us)
    {
    	uint16_t __ticks;
    	double __tmp = ((F_CPU) / 4e6) * __us;
    	if (__tmp < 1.0)
    		__ticks = 1;
    	else if (__tmp > 65535)
    		__ticks = 0;	
    	else
    		__ticks = (uint16_t)__tmp;
    	delays(__ticks);
    }
    
    
    
    
      SIGNAL (SIG_OVERFLOW0)
    
      {
       TCNT0=tau0;
       liczt0++;
    
       if(liczt0==5)
       {
         liczt0=0;
          PORTB=0xFF;
          delay_us(1500);    // opznienie 1500 us 
          PORTB=0x0;
         }
       }
    
    
     int main(void)
      {
       DDRB=0xFF;
       TIMSK=1<<TOIE0;
       TCNT0=tau0;
       TCCR0=4;
       sei();
       while(1)
    {}
       }
    
    


    Nie wiem jakie chcesz uzyskac dokladnie przebieg ale generowany sygnal wyglada tak: co 380us ustawiane sa wszystkie piny portuB na 1 na 1500us.
    Aha , dodaj na pocztku biblioteki
    #include <avr/io.h>
    #include <stdlib.h>
    #include <stdio.h>

    brak ktorej z nich prawdopodobnie powoduje ze nie dzialaja Ci te funkcje ustawiajace i zerujace poszczegolne bity portu .
  • #24 2485820
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    niezabardzo kumam
    to mam w programie nie dawać include delay.h czy tak?

    bo wgrałem ten program bez tej biblioteki i niedziałało :|

    Może tak żebyś rozumiał
    musze co 20ms generować impuls o długości 1.5ms a docelowo regulowanej od 1 do 2ms
  • #25 2485883
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    ten program co Ci napisalem wyzej dziala, nie masz dodawac tej biblioteki bo Ci wpisalem ta funkcje opozniajaca bezposrednio w programie.
    Poza tym musisz ustawic tak preskaler i timer 0 zeby uzyskac zmiane impulsu co 20ms bo narazie to w twoim programie zmienia sie co 380us tak jak Ci pisalem.
  • REKLAMA
  • #26 2486225
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    A co jest z tym timerem nie tak?
    przecież
    16000000/256/250/5=50Hz
    No chyba że coś pomieszałem
  • #27 2489180
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    Cytat:

    A co jest z tym timerem nie tak?
    przecież
    16000000/256/250/5=50Hz
    No chyba że coś pomieszałem


    Preskaler 256 to się zgadza ,ale pomieszaleś z timerem.
    TCNT0=250; jak zaladujesz do timera 250 to nie zoznacza, ze bedziesz dzielil 250 . Timer zlicza w gore a nie w dol! , jego pojemnosc to 256 wiec 256-250 = 5

    Tak wiec masz podzial pzrez 5 a nie przez 250
    Powinienes napisac
    TCNT0=0x5;
  • #28 2489371
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    adamusx napisał:

    Powinienes napisac
    TCNT0=0x5;

    a nie 6 ?
    256-6=250

    tam tez napisałeś że 256-250=5 (a przeciez to 6)
  • Pomocny post
    #29 2489743
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    To moja pomylka, 256-250 to faktycznie 6 :) ,a nie 5 jak pisalem.

    A tak wogole to powinno byc 255- 250 bo timer zero liczy do wartosci 255, a 256 wynika z tego ze liczy sie takze wartosc 0.
  • #30 2490614
    dzik84
    Poziom 17  
    Posty: 444
    Pomógł: 30
    Ocena: 17
    Dzięki za pomoc

Podsumowanie tematu

✨ Dyskusja dotyczy problemów z kompilacją i działaniem programu AVR w środowisku AVRSIDE, w szczególności błędów linkera oraz sterowania portami mikrokontrolera. Główne problemy to: błędy składniowe przy użyciu nieaktualnych funkcji sbi/cbi, niepoprawne operacje na bitach portów (np. PORTB.0=1 nie działa w GCC), brak definicji F_CPU powodujący ostrzeżenia i nieprawidłowe działanie funkcji opóźniających z , oraz błąd "undefined reference to 'main'" wynikający z niepoprawnej konfiguracji projektu w AVRSIDE (brak utworzenia nowego projektu i ustawienia procesora oraz kwarcu). Zalecane jest używanie operacji bitowych z przesunięciem (np. PORTB |= (1
Wygenerowane przez model językowy.
REKLAMA