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

[Atmega32] Timer0 nie wywołuje przerwania SIG_OVERFLOW0 w skanerze 3D

didijo 10 Maj 2009 15:58 4014 13
REKLAMA
  • #1 6513001
    didijo
    Poziom 10  
    Posty: 22
    Ocena: 2
    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
  • REKLAMA
  • #3 6514357
    didijo
    Poziom 10  
    Posty: 22
    Ocena: 2
    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
  • REKLAMA
  • Pomocny post
    #4 6514555
    skynet_2
    Poziom 26  
    Posty: 1008
    Pomógł: 74
    Ocena: 9
    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  
    Posty: 1502
    Pomógł: 72
    Ocena: 49
    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  
    Posty: 22
    Ocena: 2
    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!
  • REKLAMA
  • #7 6516160
    skynet_2
    Poziom 26  
    Posty: 1008
    Pomógł: 74
    Ocena: 9
    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  
    Posty: 22
    Ocena: 2
    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.
  • Pomocny post
    #9 6516429
    skynet_2
    Poziom 26  
    Posty: 1008
    Pomógł: 74
    Ocena: 9
    Tutaj masz hex'a z tego programu, skompilowanego przez avr-gcc dla atmega32 1Mhz.

    Zobacz czy zadziała, a ja sprawdzę makefile.
    Załączniki:
    • test_avr.hex.zip (400 Bajtów) Musisz być zalogowany, aby pobrać ten załącznik.
  • REKLAMA
  • #10 6527655
    didijo
    Poziom 10  
    Posty: 22
    Ocena: 2
    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  
    Posty: 1008
    Pomógł: 74
    Ocena: 9
    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  
    Posty: 3954
    Pomógł: 468
    Ocena: 51
    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  
    Posty: 22
    Ocena: 2
    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  
    Posty: 3954
    Pomógł: 468
    Ocena: 51
    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ł.

Podsumowanie tematu

✨ Problem dotyczył braku wywołania przerwania TIMER0_OVF_vect (wcześniej SIG_OVERFLOW0) w mikrokontrolerze Atmega32 podczas sterowania silnikiem krokowym w projekcie skanera 3D. Przyczyną był nieaktualny sposób definiowania przerwań (należało zastąpić #include i SIGNAL przez ISR oraz SIG_OVERFLOW0 przez TIMER0_OVF_vect). Dodatkowo zwrócono uwagę na niewłaściwy typ zmiennej overflow (uint8_t nie może przechowywać wartości powyżej 255), co powodowało błędy logiczne w warunkach. Problem z kompilacją pod Linuksem wynikał z ustawień optymalizacji w Makefile, gdzie zmiana z -Os na -O2 nie rozwiązała problemu, ale użycie Makefile wygenerowanego przez AVR Studio pozwoliło na poprawne kompilowanie. Sugerowano także użycie avr-gcc zamiast avr-g++ oraz narzędzi takich jak Eclipse z pluginem AVR dla wygodniejszej pracy. W dyskusji pojawiła się też uwaga, że sterowanie mikrokrokami programowo jest nietypowe i zwykle stosuje się dedykowane układy sterujące silnikami krokowymi, które zapewniają lepszą jakość pracy. Autor potwierdził, że po poprawkach i zmianie Makefile problem został rozwiązany, a sterowanie mikrokrokami realizowane programowo pozwala na uzyskanie rozdzielczości około 5 mm z odległości 5 metrów.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA