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

Kilka programów wybieranych przerwaniem

leonow32 28 Lis 2010 15:34 1122 9
  • #1 8800284
    leonow32
    Poziom 30  
    Robię wielofunkcyjne urządzenie, które ma rezlizować kilka programów, przełączanych przy pomocy przerwani INT0. Tzn, program pierwszy wykonuje się w pętli while(1) tak długo, aż nie pojawi się przerwanie, które zakończy program pierwszy i rozpocznie drugi.

    Mój pomysł wygląda tak:
    
    uint8_t numerprogramu = 1;
    
    void program1(void) {
    	while(1) {
    		....
    	}
    }
    
    void program2(void) {
    	while(1) {
    		....
    	}
    }
    
    ...i tak kilka kolejnych programów
    
    int main(void) {
    	konfiguracje przerwań i innych krzeczy
    wybor:
    	switch(numerprogramu) {
    		case 1:
    			program1();
    			break;
    		case 2:
    			program2()
    			break;
    		itp itd
    	}
    }
    
    ISR(INT0_vect) {
    	++numerprogramu;
    	goto wybor;
    }
    

    no i nie działa. Wywala mi takie błędy:
    label 'wybor' defined but not used
    label 'wybor' used but not defined

    O co chodzi? Co mam zrobić, że przerwanie zakończyło obecną pętlę i wywołało kolejny program? Cykliczne sprawdzanie czy przycisk jest wciśnięty nie wchodzi w grę. Programy będą dosyć długie i zawiłe.
  • #2 8800315
    gaskoin
    Poziom 38  
    Czas na system operacyjny. Przy założeniu jakie wprowadziłeś do programu wygląda to tak:

    Wykonuje się program 1, występuje przerwanie, program 1 idzie w cholerę razem z wynikami jakie obliczył (o ile zdążył), zaczyna się program 2, występuje przerwanie itd...

    skoro tak to ma działać to nie lepiej zwiększać zmienną w przerwaniu i resetować procesor ?

    Jeżeli miało to działać w taki sposób, że przełączane są kolejne zadania, to niestety sprawa nie jest tak prosta a programy trzeba by bardzo rozdrobnić. Lepiej chyba wgrać tam jakiegoś µCOS
  • #3 8800362
    _Robak_
    Poziom 33  
    Cytat:

    ISR(INT0_vect) {
    ++numerprogramu;
    goto wybor;
    }

    Toż to jest masakra.
    Ja bym zrobił to tak że w przerwaniu, jak już chcesz, ustawiasz sobie ten numer programu w jakiś sposób, potem w pętli głównej programu dał
    
    while(1)
    {
     while(program==1)
    {}
    
    while(program==2)
    {}
    }
    

    Ma to tą zaletę że nawet jak zmienisz program to nie przerwiesz go w środku tylko dokończysz bieżący i dopiero zmienisz się na następny.
  • #4 8800376
    leonow32
    Poziom 30  
    Dokładnie tak, w chwili wystąpienia przerwania program ma się natychmiast zakończyć, a dane jakie wytworzył mają zniknąć.

    Nie sądzę, by trzeba było sięgać po jakieś systemy operacyjne. Urządzenie ma być miernikiem pojemności, rezystancji, częstotliwości, generator sygnału, sonda logiczna, itp. Problem polega na tym, że niektóre programy mierzą czas, np jak długo ładuje się kondensator i wtedy program nie może kontrolować przycisku, w związku z tym trzeba go załatwić przerwaniem.

    Jak zresetować procesor? Zmienna wywołująca kolejny program się przecież wyzeruje
  • #5 8800378
    gaskoin
    Poziom 38  
    Przy takiej konstrukcji pętli głównej w ISR wystarczy nr_programu++ i ewentualnie jakiś if, żeby nie wyjechać za liczbę programów.

    Żeby zresetować procesor, uruchamiasz watchdoga i zaraz po jego uruchomieniu robisz pustą pętlę - procesor się resetuje. Nie pamiętam teraz, ale chyba trzeba go po resecie wyłączyć, umieszczając kod jego wyłączenia najlepiej przed wejściem do main - w jednej z sekcji startupu.

    Jeżeli nie będą to częste zmiany, to można numer programu pchać do EEPROMU, jeżeli częste, można nie inicjalizować zmiennej odpowiedzialnej za numer programu (wcisnąć ją w sekcję ".noinit") i z tym kombinować (stara wartość zostanie w RAMie)
  • #6 8800419
    mirekk36
    Poziom 42  
    _Robak_ napisał:
    Cytat:

    ISR(INT0_vect) {
    ++numerprogramu;
    goto wybor;
    }

    Toż to jest masakra.


    To nie jest maskara, to jest MEGA MASAKRA!....

    Po pierwsze to warto się nauczyć jak działają przerwania.

    Po drugie warto zapomnieć o nawykach z Bascoma i ZAPOMNIEĆ najlepjej na zawsze o poleceniu GOTO w języku C a szczególnie żeby tak je używać.

    Po trzecie warto poczytać o tym jak się używa flag w przerwaniu - to od razu i na 100% załatwiłoby twój problem - oczywiście gdybyś go jeszcze dobrze rozwiązał w funkcji main.

    W chwili obecnej to że program nie działa - jest PRAWIDŁOWE ... po prostu to jest działanie z tak napisanym kodem i wygląda mniej więcej tak:

    Działa sobie program 1 jak go nazywasz

    Występuje przerwanie

    Odkłada się na stos parę rzeczy ;) ... (poczytaj o prologu i epilogu procedur obsługi przerwań żeby to było jaśniejsze)

    wtedy zmienia się jakiś tam twój numerek

    i dochodzi do MEGA MASAKRY (samobójstwa) instrukcja GOTO pomijająca epilog czyli na stosie zostają śmieci .....

    dalej to już nie trzeba tłumaczyć nawet bo nie ma sensu - wszystko poszło jak to ktoś się wyraził już w cholerę ;)
  • #7 8800432
    gaskoin
    Poziom 38  
    Nawet jakby działało, to pewnego razu stos by się przewrócił :)

    ------------------------------
    Edytowałem, ale chyba robak był szybszy :P

    Nie ma co kombinować, nawet jak się uda, to program będzie działał np przez 50 przyciśnięć, po czym nastąpi zwiecha. Nie ma też co dyskutować na temat sensu takiegoż programu, gdyż sensu on wówczas mieć nie będzie :)

    Soft reset:

    
    #include <avr/wdt.h>
    
    void soft_reset(){
            wdt_enable(WDTO_15MS);
            while(1);
    
    }
    


    jeszcze gdzieś trzeba dopisać, dla nowszych avr coś takiego:

    
    void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));
    
    void wdt_init(void){
            MCUSR = 0;
            wdt_disable();
            return;
    }
    
    


    goto ma jedyne słuszne użycie - jedynie przy wychodzeniu z bardzo zagnieżdżonych pętli
  • #8 8800438
    mirekk36
    Poziom 42  
    gaskoin napisał:
    Nawet jakby działało, to pewnego razu stos by się przewrócił :)


    No ale po co to jakby - przecież tym dajesz "jakby" nadzieję, że jednak można byłoby dalej kombinować z takim sposobem, tymczasem takie GOTO pokazuje od razu totalny brak zrozumienia działania przerwań co zaowocuje setką innych problemów za chwilę w każdym innym miejscu.
  • #9 8802242
    leonow32
    Poziom 30  
    Póki co wykombinowałem by numer programu zapisać w EEPROMie i zresetować procesor watchdogiem jak gaskoin polecił. Teraz działa.

    mirekk36 pięknie mnie tu zjechałeś. Rzeczywiście, pojęcia nic mam co robię i za głupi jestem, żeby na forum zapytać co jest nie tak. Twoja pomoc bardzo mi pomogła. Wielkie dzięki.
  • #10 8802333
    mirekk36
    Poziom 42  
    gaskoin napisał:

    goto ma jedyne słuszne użycie - jedynie przy wychodzeniu z bardzo zagnieżdżonych pętli


    I to nie zawsze.

    Dodano po 3 [minuty]:

    leonow32 napisał:
    mirekk36 pięknie mnie tu zjechałeś. Rzeczywiście, pojęcia nic mam co robię i za głupi jestem, żeby na forum zapytać co jest nie tak. Twoja pomoc bardzo mi pomogła. Wielkie dzięki.

    Nic takiego nie miałem na myśli a tym bardziej jakiegoś zjechania.

    Natomiast użycie rozkazu GOTO i to w celu opuszczenia przerwania świadczy tylko, że nie do końca rozumiesz działanie przerwań. Dlatego polecałem żeby sobie poczytać na ten temat. Czy to dla ciebie taka ujma ???? Bo to że po prostu tutaj nie użyjesz GOTO nie spowoduje że do końca zrozumiesz przerwania - tak mi się wydaje - aczkolwiek mogę się oczywiście mylić.

    Dlatego podsunąłem ci też konkrety - napisałem o prologi i epliogu. Zamiast się więc sztucznie urażać warto to doczytać - rozwiązałoby to na przyszłość wiele twoich problemów.
REKLAMA