Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Atmega8 - problem podczas powrotu z przerwania

09 Sty 2010 01:38 1821 14
  • Poziom 11  
    Witam!

    Napisałem w C program do sterowania silnikiem przy pomocy mostka L293D. Docelowo całość będzie pracować w robocie z dwoma silnikami i dyferencjałem, czyli prostym robocie dwukołowym.
    Ale do rzeczy... w robocie będzie krańcówka, której wciśnięcie nastąpi po wjechaniu w przeszkodę. W tym momencie zostanie wywołany program do omijania przeszkody. Chciałem zrealizować to w przerwaniu, żeby funkcja omijania była napisana tylko raz i jedynie wywoływana w odpowiednim momencie.
    Na razie robię wszystko na płytce testowej, gdzie funkcję zderzaka pełni microswitch.
    W programie poniżej w głównej jego pętli jest pewna przykładowa sekwencja ruchów silnika. Wciskam przycisk, wykonuje się przerwanie, które w przykładowym programie ma jedynie zatrzymać silnik. No i w tym momencie pojawia się problem. uC wraca do wykonywania głównego programu, jednak silnik dalej stoi, gdyż ustawiona w przerwaniu wartość PORTC obowiązuje do chwili zmienienia jej w głównej pętli.
    Jak temu zaradzić? Czy jest możliwość, aby po powrocie z przerwania na PORTC pojawiła się ostatnia wartość sprzed wywołania tegoż przerwania?

    Code:

    #define F_CPU 1000000L
    #define    PWM1    PB1

    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>

    SIGNAL (SIG_INTERRUPT0)
    {
       while(!(PIND & (1<<2))) // zapalenie diody w czasie, gdy wciśnięty jest przycisk
       PORTC |= (1<<2);
       PORTC &= ~(1<<2);

       if(!(PIND & (1<<2)))
       { 
          _delay_ms(20);
          PORTC &= ~(_BV(1) | _BV(0));  //ustawienie wartości zatrzymującej silnik
         _delay_ms(20);
        
       }
    }




    int main (void)
    {
       DDRC |= (1<<0) | (1<<1) | (1<<2); //sterowanie silnikiem i ustawienie wy dla diody
       DDRD &= ~(_BV(2));   //przycisk
       DDRB |= _BV(PWM1);  //pwm
       PORTB &= ~ (_BV(PWM1));
       PORTD |= _BV(2);
       PORTC |= _BV(0) | _BV(1);
       
       /* aktywacja przerwania itp */
       GICR = _BV(INT0);
       MCUCR &= ~(_BV(ISC00) | _BV(ISC01));
       sei();

       /* aktywacja pwm */
       ICR1 = 495;
       OCR1A = 1;
       TCCR1A = _BV(WGM11);
       TCCR1A |= _BV(COM1A1) | _BV(COM1A0);
       TCCR1B |= _BV(CS10); // bez Preskalera
     
       while (1)
       {
           /* przykładowa sekwencja obrotów */
           OCR1A=410;
       PORTC |= _BV(0);
       PORTC &= ~(_BV(1));
       _delay_ms(4000);
       OCR1A = 462;
       _delay_ms(3000);
       PORTC &= ~(_BV(0) | _BV(1));
       _delay_ms(3000);
       OCR1A = 465;
       PORTC &= ~(_BV(0));
       PORTC |= _BV(1);
       _delay_ms(10000);
       }
       return 0;
    }

  • Pomocny post
    Poziom 10  
    Wydaje mi się że po prostu użyj jakieś flagi i zmiennej globalnej która zapamięta wartość PORTC w momencie wejścia do przerwania. Aby rzeczywiste wartość ta była zachowane użyj zmiennej
    Code:
    volatile char
    to znaczy wchodząc do przerwania funkcja będzie wykonywana na tej zmiennej a nie na jej kopii.
  • Poziom 11  
    Jutro popróbuję, bo dzisiaj już późno.
    Byłbym jeszcze wdzięczny za kod, jak to konkretnie zapisać w moim programie.
    O przerwaniach wiem póki co bardzo nie wiele i nie zgłębiłem jeszcze o co chodzi dokładnie z tymi flagami. Wiem, że powinienem o tym doczytać, ale myślę, że znacznie szybciej się nauczę, jak będę miał działający przykład ;)
  • Poziom 33  
    Code:

    SIGNAL (SIG_INTERRUPT0)
    {
       while(!(PIND & (1<<2))) // zapalenie diody w czasie, gdy wciśnięty jest przycisk
       PORTC |= (1<<2);
       PORTC &= ~(1<<2);

       if(!(PIND & (1<<2)))
       { 
          _delay_ms(20);
          PORTC &= ~(_BV(1) | _BV(0));  //ustawienie wartości zatrzymującej silnik
         _delay_ms(20);
         
       }
    }

    Delaye w przerwaniu ? Nie dziwne ze sie program krzaczy.
  • Poziom 11  
    Zamieniłem w takim razie delay na pętlę for, która się tam trochę powtarza, żeby silnik jednak chwilę postał w miejscu w czasie przerwania i efekt jest ten sam co z delayem. Zresztą, jak w przerwaniu tylko i wyłącznie dam ustawienie portu na wartość zatrzymującą silniki to efekt jest również ten sam.
    Będę próbował z tym co zaproponował henxa, bo widać cały czas, że po prostu ustawienie jakiejś wartości na porcie podczas przerwania obowiązuje nawet po wyjściu z niego, co mi się bardzo nie podoba.
  • Poziom 33  
    Cytat:
    Zamieniłem w takim razie delay na pętlę for, która się tam trochę powtarza

    Rozwiazanie rownie zle co i delay.
    Cytat:

    bo widać cały czas, że po prostu ustawienie jakiejś wartości na porcie podczas przerwania obowiązuje nawet po wyjściu z niego, co mi się bardzo nie podoba.

    W takim razie jedyne wyjscie jakie widze to zmiana upodoban :>
  • Poziom 42  
    pepek0206 ---> można wszystko w pętli głównej pięknie zrobić i to bez żadnych _delay_ms(xxx) , można zrobić wszystko tak, żeby każdy proces z osobna, który sobie wymyślisz działał w odrębnym odcinku czasowym a do tego spokojnie obsługa klawiszy czy pilota itp - no ale to trzeba się nauczyć inaczej programować - tzn ciężko jest to ot tak w kilku słowach przekazać. Rozważ skorzystanie z moich kursów ;) na które serdecznie zapraszam. Wtedy zobaczysz jak można coś takiego robić i wykorzystywać już zawsze w każdym następnym programie ;)
  • Pomocny post
    Moderator Mikrokontrolery Projektowanie
    pepek0206 napisał:
    Czy jest możliwość, aby po powrocie z przerwania na PORTC pojawiła się ostatnia wartość sprzed wywołania tegoż przerwania?


    O ile dobrze zrozumialem twoj problem to rozwiazanie jest proste - na poczatku przerwania zapamietaj stan PORTD w jakiejs zmiennej i odtworz go na koncu obslugi przerwania.
    Co do delay w przerwaniu to sie nie przejmuj tym co pisza - wszystko mozna stosowac tylko trzeba wiedziec po co i jak. Akurat w twoim programie to delay niczemu nie przeszkadza.
  • Poziom 33  
    Cytat:
    Co do delay w przerwaniu to sie nie przejmuj tym co pisza - wszystko mozna stosowac tylko trzeba wiedziec po co i jak.
    To stwierdzenie jest tak samo wartosciowe jak "a ja nie daje 100nf przy Vcc i mi dziala". Oczywiscie, swiadomy programista poradzi sobie z dlugimi przerwaniami, ale sadzac po poscie kolega dopiero zaczyna.
  • Poziom 42  
    Widać, że autor jeszcze nawet nie do końca rozumie na czym polega praca z przerwaniami i stąd takie kuriozalne sposoby podejścia do pisania programu. Gdzie część jego funkcjonalności (jak sam autor napisał w pierwszym poście) próbuje przenieść właśnie do przerwania. Otóż TAK NIE MOŻNA


    no ale z drugiej strony jak się spojrzy na tego typu porady:

    tmf napisał:
    Co do delay w przerwaniu to sie nie przejmuj tym co pisza - wszystko mozna stosowac tylko trzeba wiedziec po co i jak. Akurat w twoim programie to delay niczemu nie przeszkadza.


    to skóra cierpnie na plecach.

    tmf --> ja nawet nie pisałem o poleceniach _delay_ms() w przerwaniu żeby się ich pozbyć, ja pisałem, że można ich w ogóle nie używać w pętli głównej. Bo używanie w przerwaniu i to jeszcze w takim tylko na razie testowym programie jest po prostu całkowicie bez sensu. Aż się zastanawiam czy to ten sam tmf pisze ? ;) co w innych postach

    pepek0206 --> proponuję ci w ogóle z kolei dać sobie spokój z poradą kolegi tmf i całkowicie wywalić z przerwania tę obsługę klawisza. Już kolega enxa dał ci dobrą podpowiedź aby skorzystać z mechanizmu tzw flag, nawet przy okazji zwrócił słusznie uwagę na volatile żebyś za chwilę z tym nie miał problemu. I będzie dla ciebie lepiej jeśli od początku zaczniesz szukać takich dróg do prawidłowego pisania programów. Przy okazji - spróbuj gdzieś w necie poszukać i poczytać n/t tzw wykorzystania mechanizmu timerów programowych. Tyle mogę naprowadzić bo zbyt dużo trzeba by się było rozpisywać. Nazwa może brzmi trochę jak jeż - ale zapewniam cię że implementacja czegoś takiego nawet przez początkujących nie jest trudna. A jak o tym poczytasz to od razu zrozumiesz jak pisać prawidłowo programy zamiast w taki liniowy sposób jak ty teraz próbujesz i to wplatając do tego jeszcze procedury obsługi przerwań.
  • Moderator Mikrokontrolery Projektowanie
    Ok, wszyscy sobie narzekaja, a ktos potrafi napisac sensownie czemu *w tym* programie nie uzywac delay w obsludze przerwania? Wszystko mozna rozwiazac na rozne sposoby, ale akurat tu to nie ma znaczenia - jest jedno przerwanie, nawet jesli bedzie trwalo wiecznosc nic sie nie stanie. Oczywiscie w wiekszym programie takie podejscie zwykle sie nie sprawdza, ale w pokazanym nie stwarza najmniejszych problemow.

    Dodano po 1 [minuty]:

    Flagi z kolei w pokazanym programie sa bez sensu - nie zadzialaja jak nalezy ze wzgledu na ogromne opoznienia, zanim program dojdzie do odczytu flagi moze minac ponad 10s! Wymagaloby to zmiany calego programu - co zreszta moze i nie byloby takim glupim pomyslem :)
  • Poziom 38  
    "Alkohol używany w rozsądny sposób można pić w dowolnej ilości"- to cytat z wypowiedzi przedwojennego pułkownika.
    "Opóźnień czasowych używanych w rozsądny sposób można dawać w programie dowolną ilość"- to taka popularna zasada.
    To pozwala na ominięcie problemów- jak alkohol.
    Pięć nop- pięć kieliszków.
    "czekaj 10ms"- beczka wódki.
    Są wyjątki- jak ten pułkownik.
    Ale nie należy próbować go naśladować.
  • Poziom 11  
    Dzięki wszystkim za rady.
    Kurka mam pod ręką fajny tutorial o timerach. Broniłem się rękami i nogami, ale wygląda na to, że muszę go w końcu przeczytać ;)
    Dobrze byłoby znać jednak wszystkie możliwe podejścia, więc i metody ze zmienną wypróbuję. Ehhh, najłatwiejsze rozwiązania czasem przechodzą koło nosa niezauważone.
    No ale jeszcze mam prośbę o jakieś konkretne linki z tutorialami na temat przerwań. Znalazłem co nieco, ale nie ma tam wiadomości podanych od podstaw dla żółtodzioba.
    Na razie składam informacje i próbuję coś sklecić, co chociaż próbuje zadziałać i zdaję sobie sprawę, że moje podejście do programowania może być nieco... prowizoryczne.
  • Poziom 42  
    tmf napisał:
    Ok, wszyscy sobie narzekaja, a ktos potrafi napisac sensownie czemu *w tym* programie nie uzywac delay w obsludze przerwania?

    to nie jest test w którym trzeba zakreślić jedną prawidłową odpowiedź (więc nie chodzi o narzekanie - tylko próby wskazania całkiem innej i bardziej efektywnej drogi)


    tmf napisał:
    Flagi z kolei w pokazanym programie sa bez sensu

    zapewniam cię , że mają sens i to ogromny

    tmf napisał:

    - nie zadzialaja jak nalezy ze wzgledu na ogromne opoznienia, zanim program dojdzie do odczytu flagi moze minac ponad 10s!

    dlatego trzeba się ich pozbyć

    tmf napisał:

    Wymagaloby to zmiany calego programu

    to jest jedyna droga

    bo inaczej to ktoś kto nauczył się już budować "babki z piasku za pomocą foremek w piaskownicy" nie będzie w stanie tylko na podstawie różnych kombinacji robienia takich babek - w stanie zbudować domu. Żeby zbudować dom - będzie się musiał nauczyć jeszcze kilku następnych etapów jak należy dalej postępować z tym piaskiem i jak zamienić foremki na inne narzędzia.

    Tak więc jeśli widzisz, że ktoś zabiera się za budowę domu za pomocą foremek z piaskownicy - to postaraj się podać pomysły jak przejść do następnych etapów początkującemu - a nie wymyślaj jak ma sobie nadal radzić za pomocą tych samych foremek. Bo pewnie! masz rację, za pomocą tych foremek też kiedyś zbuduje dom - tylko po jakim czasie i jaki??????
  • Poziom 16  
    Z tego co widzę, chcesz osiągnąć 'wielowątkowość' molestując przerwania (bo tylko tak można określić delaye w przerwaniach)

    Koledzy mają rację - timery to chyba najprostsze rozwiązanie Twojego obecnego problemu.

    Ale - sądząc po poście - starasz się oprogramować robota. I wiem z doświadczenia że czeka Cię duuużo nauki, więc może warto żebyś zainteresował się przy okazji np. FemtoOS. Ostrzegam - nie jest to 'super łatwe' - ale odpadnie Ci zastanawianie się nad sposobem rozwiązania wielu bardzo istotnych problemów programistycznych - wystarczy zajrzeć na listę features FemtoOS