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

[Atmega32] Problem z uruchomieniem timera

didijo 10 Maj 2009 15:58 3903 13
  • #1 6513001
    didijo
    Poziom 10  
    cześć,
    od kilku miesięcy robie z kumplem skaner 3D. Wszystko już mamy, jednak okazało się, że silnik krokowy, który używamy ma za małą rozdzielczość i trzeba zrobić sterowanie przez mikrokroki. Od piątku siedze nad datasheetem, tutorialami etc. i nic nie wychodzi (przerwanie SIG_OVERFLOW0 nie jest wywoływane). Postanowiłem wgrać do procesora przykład z avr.elektroda.eu do obsługi timer0 i problem jest taki sam :| Silniczek jest sterowany przez portC, jtag wyłączyłem. Kod kompiluje przez avr-g++ w linuksie. Co może być źle?

    Kod programu:
    // Testowanie timera 0 (przerwania)                                        
    
    #include <avr/io.h>                // dostęp do rejestrów
    #include <avr/interrupt.h>        // funkcje sei(), cli()
    #include <avr/signal.h>                // definicje SIGNAL, INTERRUPT
    
    #define T0_INIT                256-250
    
    #define tbi(PORT,BIT)        PORT^=_BV(BIT)  
    // przełącza stan BITu w PORTcie na przeciwny 1->0 ; 0->1
    
    //unsigned char overflow;
    volatile uint8_t overflow;
    //  |                     
    //  -- volatile jest konieczne ze względu na sprawdzanie
    //     zmiennej overflow poza procedurą obsługi przerwania
    
    SIGNAL (SIG_OVERFLOW0)
    {
      TCNT0 = T0_INIT;                // przeładuj timer 0
      if (overflow>0)
        overflow--;                        // dekrementuj
      //tbi(PORTD,PD5);                // przełącz stan LED na PB1
    }
    
    int main(void)
    {
      DDRC = 0xFF;                // wszystkie linie PORTD jako wyjścia
    //  PORTC = 0xFF;                // wygaś diody LED
      TIMSK = _BV(TOIE0);        // włącz obsługę przerwań T/C0
      TCNT0 = T0_INIT;         // wartość początkowa T/C0
      TCCR0 = _BV(CS00)|_BV(CS02); // preskaler 1024
    
      sei();                        // włącz obsługę przerwań
    
      while(1)                        // pętla nieskończona
      {
    //    cbi(PORTD,PD4);                // zapal LED na PD4
            PORTC = 1 << 1;
        overflow=4;                        // inicjuj zmienną overflow
        while(overflow);                // zmienna overflow jest
                                        // dekrementowana w przerwaniu
        //sbi(PORTD,PD4);                // zgaś LED na PD4
        PORTC = 1 << 3;
        overflow=16;                // inicjuj zmienną overflow
        while(overflow);                // zmienna overflow jest
                                        // dekrementowana w przerwaniu
      }
    }
    
    


    Obsługę przerwań włączam, preskaler jest ustawiony, kod do przerwania też jest. Próbowałem też zmienić SIG_OVERFLOW0 na SIG_OUTPUT_COMPARE0 (tak na jakimś forum znalazłem) ale nic nie dało
  • #3 6514357
    didijo
    Poziom 10  
    Po przerobieniu kod wygląda tak:
    // Testowanie timera 0 (przerwania)
    
    #include <avr/io.h>                // dostęp do rejestrów
    #include <avr/interrupt.h>        // funkcje sei(), cli()
    
    #define T0_INIT                256-250
    
    #define tbi(PORT,BIT)        PORT^=_BV(BIT)
    // przełącza stan BITu w PORTcie na przeciwny 1->0 ; 0->1
    
    //unsigned char overflow;
    volatile uint8_t overflow;
    //  |
    //  -- volatile jest konieczne ze względu na sprawdzanie
    //     zmiennej overflow poza procedurą obsługi przerwania
    
    ISR(TIMER0_OVF_vect)
    {
    	overflow++;
    	if (overflow < 512) {
    		PORTC = 1 << 1;
    	} else {
    		PORTC = 1 << 2;
    	}
    	if (overflow > 1024) {
    		overflow = 0;
    	}
    }
    
    int main(void)
    {
      DDRC = 0xFF;                // wszystkie linie PORTD jako wyjścia
    //  PORTC = 0xFF;                // wygaś diody LED
      TIMSK = _BV(TOIE0);        // włącz obsługę przerwań T/C0
      TCNT0 = T0_INIT;         // wartość początkowa T/C0
      TCCR0 = _BV(CS00)|_BV(CS02); // preskaler 1024
    
      sei();                        // włącz obsługę przerwań
    
      while (1);
    // Tutaj juz nie powinno dojsc
      while(1)                        // pętla nieskończona
      {
    //    cbi(PORTD,PD4);                // zapal LED na PD4
    	PORTC = 1 << 1;
        overflow=4;                        // inicjuj zmienną overflow
        while(overflow);                // zmienna overflow jest
                                        // dekrementowana w przerwaniu
        //sbi(PORTD,PD4);                // zgaś LED na PD4
        PORTC = 1 << 3;
        overflow=16;                // inicjuj zmienną overflow
        while(overflow);                // zmienna overflow jest
                                        // dekrementowana w przerwaniu
      }
    }
    

    i dalej nie działa :/ Program powinien się zatrzymać na pierwszej pętli while. Jedyne co będzie się działo (tak mi sie wydaje) to obsługa przerwania, czyli F_CPU/1024 na sekunde wykonanie tego, co jest w obsłudze przerwania. Ale niestety nie działa :] Wszystkie nóżki portu C mają niski stan (0). Albo ja robię jakiś głupi błąd, albo linuksowe avr-g++ nie potrafi obsługiwać przerwań. Bardziej prawdopodobne jest to pierwsze ;) Taki kod kompiluje się i wgrywa do procesora normalnie?

    ps. w manualu wyczytałem, że TIM0_OVF_vect jest tylko dla atiny. Dla atmegi32 jest TIMER0_OVF_vect
  • Pomocny post
    #4 6514555
    skynet_2
    Poziom 26  
    didijo napisał:
    ps. w manualu wyczytałem, że TIM0_OVF_vect jest tylko dla atiny. Dla atmegi32 jest TIMER0_OVF_vect


    pomyliłem się, sorki.

    i jest błąd bo
    volatile uint8_t overflow;

    uint8_t to 0-255, nie wiem jak to wygląda po skompilowaniu.
       if (overflow < 512) { 
          PORTC = 1 << 1; 
       } else { 
          PORTC = 1 << 2; 
       } 
       if (overflow > 1024) { 
          overflow = 0; 
       }


    to tak na szybko, jeszcze sprawdzę czy nie ma innych błędów

    btw. windowsowe avr-g++ jest przekompilowane z linuksowego avr-g++ ;) tak samo avrdude i chyba cały WinAvr ;)
  • Pomocny post
    #5 6514571
    rpal
    Poziom 27  
    KOlego popatrz w jaki sposób masz ustawioną optymalizację i sprawdź symulatorem jak się faktycznie ma ta zmienna overflow, kompilator może robić tobie psikusy :)
  • #6 6515949
    didijo
    Poziom 10  
    jak kompiluje w avrstudio, to działa dobrze :) Ale już kompilacja przez to samo avr-g++ z którego korzysta avrstudio nie działa, więc problem jest chyba tak jak pisaliście w optymalizacji (Makefile). Zamieniłem z -Os na -O2 ale bez zmian. Później będe jeszcze to męczyć i pewnie napisze jeśli to nie to co myśle. W każdym razie dzięki za pomoc!
  • #7 6516160
    skynet_2
    Poziom 26  
    A jak kompilujesz przez g++ to podajesz wszystkie parametry?
    np. --mcu=atmega32
    Ja korzystam z wtyczki AVR-eclipse, przynajmniej nie trzeba grzebać w makefile ;)
  • #8 6516404
    didijo
    Poziom 10  
    CXXFLAGS= -Wall -mmcu=atmega32 -c
    
    
    atmega: main.o uart.o engine_uni.o laser.o micro_steps.o
            avr-g++ main.o uart.o engine_uni.o laser.o micro_steps.o -o atmega
            avr-objcopy -O ihex -R .eeprom atmega atmega.hex
    
    main.o: main.cpp
            avr-g++ ${CXXFLAGS} main.cpp
    
    uart.o: uart.cpp uart.h
            avr-g++ -Os ${CXXFLAGS} uart.cpp
    
    engine_uni.o: engine_uni.cpp engine_uni.h
            avr-g++ -Os ${CXXFLAGS} engine_uni.cpp
    
    engine_bi.o: engine_bi.cpp engine_bi.h
            avr-g++ -Os ${CXXFLAGS} engine_bi.cpp
    
    laser.o: laser.cpp laser.h
            avr-g++ -Os ${CXXFLAGS} laser.cpp
    
    micro_steps.o: micro_steps.cpp micro_steps.h
            avr-g++ -Os ${CXXFLAGS} micro_steps.cpp
    
    clean:
            rm *.o atmega
    

    Probowalem juz nie dawać nigdzie -Os, albo dać -O2 ale nic nie daje.
  • #10 6527655
    didijo
    Poziom 10  
    pliczek działa :) Udało mi sie też przerobić Makefile z avrstudio tak, że teraz kompiluje dobrze. Pod linuksem niestety dalej są problemy, może jak jeszcze troszke podłubie w makefilu to sie poprawi :) Dzięki jeszcze raz za pomoc
  • #11 6527867
    skynet_2
    Poziom 26  
    Skompilowałem przez avr-gcc pod linuksem, spróbuj zamienić avr-g++ na avr-gcc?

    Albo pobierz eclipse CDT z tąd, zrób update, później dodajesz ścieżkę do pluginu Link instalujesz, update i masz eclipse do AVR możesz nawet programować przez AVRDUDE jednym przyciskiem, a eclipse sam skompiluje program, chyba niema nic bardziej wygodnego do AVR pod linuksa.
    Druga możliwość do wine Link jak widzisz Link AVRStudio już nieźle działa pod wine.

    Nie rozumiem poco się męczysz z makefile itp jak można to zrobić wygodnie z GUI.

    Pozdrawiam
  • #12 6529631
    janbernat
    Poziom 38  
    A ja nie rozumiem jak można próbować sterować mikrokokami silnika krokowego programowo.
    Są dedykowane układy za kilkanaście zł na które podaje się tylko step, dir i enable.
    Choć byś się "wściekł" i tak będą lepsze od programu.
    Zasilanie mają 24-50V- co pozwala na płynną pracę silnika-wykorzystują PWM i indukcyjność uzwojeń.
    Masz silnik np. na 2V- a zasilasz układ z 40V.
    A prąd skuteczny np. 1A-tak jak trzeba.
  • #13 6530637
    didijo
    Poziom 10  
    jeśli cały układ kosztuje kilkanaście zł, to sie opłaca ;) Wszystko już chyba działa dobrze, problem był z Makefile, jak wziąłem to wygenerowane w avrstudio to kompiluje sie nawet pod linuksem :) Jakby kogoś interesowało, to cały układ jest tutaj: http://dijo.w-i.pl/router1.jpg
    Całość będzie pewnie za jakiś czas w DIY ;)

    ps. co do tych mikrokroków, to niewiem nawet czy to jest dokładnie to samo co w prawdziwych układach. Poprostu sobie wygdybałem, że jak atmega będzie zmieniać odpowiednio szybko pomiędzy dwoma krokami to laserek sie ustawi pośrodku. No i sie ustawia :D Z odległości 5 metrów ma rozdzielczość ok. 5mm :)
  • #14 6533437
    janbernat
    Poziom 38  
    Jeśli chodzi tylko o ustawienie "pomiędzy" dwoma krokami -to tak.
    To jest coś w rodzaju "wymuszenia" ustawienia w połowie kroku-jakiś erzatz pracy półkrokowej.
    Można by nawet ustawiać do dokładniej programowo-wypełnieniem impulsów np. krok1-10%-krok 2 90%-albo odwrotnie.
    Wystarczająco szybko.
    Ponieważ nie wiesz jak działa sterowanie mikrokrokowe
    -wymyśliłeś ciekawy sposób pozycjonowania.
    Ponieważ ja wiem-nigdy bym na to nie wpadł.
REKLAMA