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

[mega8][c]przerwania prośba o sprawdzenie

bkawlatow 18 Gru 2010 12:33 1770 17
  • #1 8883129
    bkawlatow
    Poziom 10  
    Witam.
    Proszę o sprawdzenie poprawności kodu.Chciałem zastosować zewnętrzne przerwanie INT0.Po podaniu niskiego poziomu na INT0 chciałbym uzyskać negacje bitów portu C0 i C1, przy czym zawsze mają one mieć wartości przeciwne.

    
    ISR(INT0_vect)
    {
    
    	if( !(PINC & 0x02))//negacja PC0 i PC1
    		{
    		PORTC |= _BV(PC1);
    		PORTC &= ~_BV(PC0);
    		}
             else
    	       {
                    PORTC |= _BV(PC0);
    		PORTC &= ~_BV(PC1);
    	        }
    
    
    }
    

    w Main konfiguruję porty i rejestry następująco:
    
     DDRC = 0xFF;
      PORTC = 0x01;;// PC0-"1"   PC1-"0"
        DDRD= 0x00;//PD wejsciami
        PORTD= 0xFF;//włącza  pull-up
    	GICR|=(1<<INT0);//włącza przerwanie INT0
    	MCUCR &=~0x03;//zeruje ISC01 i ISC00 int0 reaguje na niski poziom
    	sei();
    

    czy coś takiego ma szanse zadziałać?
  • #2 8883150
    mirekk36
    Poziom 42  
    Po pierwsze to wyzwalaj przerwanie zboczem a nie poziomem bo będziesz miał masakrę ;) - zastanów się dlaczego.

    Po drugie do zmiany stanu na przeciwny wystarczy taka prosta operacja logiczna:

    PORTC ^= (1<<PC0);
    PORTC ^= (1<<PC1);


    Po trzecie staraj się wykorzystywać zalety języka C dla przejrzystego pisania kodu, i inicjalizację np portów jako wyjścia dla np diod LED pisz tak:

    #define LED1 (1<<PC0)
    #define LED2 (1<<PC1)


    a później w main():

    DDRC |= LED1 | LED2;   // piny jako wyjścia
    PORTC |= LED1 |LED2;  // podciągnięcie do VCC


    to samo tyczy się pozostałych instrukcji. Bo takie wpisywanie wartości HEX to masakra jeśli chodzi o czytelność.
  • #3 8883189
    bkawlatow
    Poziom 10  
    Cytat:

    Po pierwsze to wyzwalaj przerwanie zboczem a nie poziomem bo będziesz miał masakrę Wink - zastanów się dlaczego.

    no nie mogę wymyślić.Chodzi o to że negacja musi nastąpić NATYCHMIAST po wykryciu przerwania.Dlatego Drgania zestyków chciałem wyeliminować na elementach RC a nie programowo.Dzięki za sugestie:)[/code]
  • #4 8883380
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Nie będziesz miał negacji, tylko będziesz miał generator przebiegu prostokątnego - stan niski na tym pinie od przerwania nie trwa przecież 1ns, tylko może trwać np 100ms, albo równie dobrze 100s. A czas wykonywania przerwania to - np. - 1us. Po tej 1us dalej jest stan niski, więc przerwanie wykona się raz jeszcze, a potem raz jeszcze i raz jeszcze i ...

    4\/3!!
  • #5 8883423
    bkawlatow
    Poziom 10  
    Fredie Chopin rozumiem tylko to potrzebuje do sterowania silnikiem,który jezeli dojdzie do położenia krańcowego włączy przełącznik który zmieni kierunek obrotów silnika i tym samym ten wyłącznik zostanie "puszczony".
  • #6 8883427
    mirekk36
    Poziom 42  
    W ogóle to aż szkoda tracić/zużywać przerwanie INTx na takie rzeczy. Biorąc pod uwagę to, że i elementy RC nie do końca zawsze wyeliminują ci efekt drgania styków to czy nie lepiej podarować sobie te elementy RC i zrobić normalną obsługę klawiszy w programie głównym (w pętli głównej) wykorzystując co najwyżej część jakiegoś przerwania timera ?
  • #7 8883429
    bkawlatow
    Poziom 10  
    Wiem że w przerwaniu nie powinno dawać się opóźnienia ale chyba w tym przypadku jest to niezbędne jak myślicie?
  • #8 8883438
    mirekk36
    Poziom 42  
    bkawlatow napisał:
    Fredie Chopin rozumiem tylko to potrzebuje do sterowania silnikiem,który jezeli dojdzie do położenia krańcowego włączy przełącznik który zmieni kierunek obrotów silnika i tym samym ten wyłącznik zostanie "puszczony".


    No ale obojętnie do czego potrzebujesz to wystąpi ci taki efekt jak opisał Freddie. Coś może nie do końca jeszcze rozumiesz jak programowo w poprawny sposób pozbywać się efektu drgania styków.

    U ciebie to może przez takie wyzwalanie poziomem dojść do sytuacji, że kiedyś zarżniesz ten silnik w pozycji krańcowej.... Pewnie, że "jakoś" to zadziała, ale zrobienie tego w prawidłowy sposób to naprawdę już niewiele.

    Dodano po 1 [minuty]:

    bkawlatow napisał:
    Wiem że w przerwaniu nie powinno dawać się opóźnienia ale chyba w tym przypadku jest to niezbędne jak myślicie?


    Jakiekolwiek opóźnienie w przerwaniu to już totalnie NIEPOROZUMIENIE GENETYCZNE ;)
  • #9 8883446
    bkawlatow
    Poziom 10  
    Mirek właśnie o to chodzi że nie potrzebuje wykorzystywać przerwań do innych rzeczy, więc tak będzie łatwiej, tym bardziej że jestem początkującym w programowaniu.
  • #10 8883477
    mirekk36
    Poziom 42  
    bkawlatow napisał:
    ...., więc tak będzie łatwiej, tym bardziej że jestem początkującym w programowaniu.


    Oczywiście zrobisz jak uważasz, ale właśnie ze względu na to, że czujesz się początkujący to warto od razu drążyć temat i zrobić takie podstawowe rzeczy jak obsługa klawiszy - tak jak się należy a nie na skróty. Bo jak znam życie, to takie skróty szybko "przyrastają" i po niedługim czasie masz pełno mniejszych i większych projektów, które robią się potworkami a nie programami w C.

    Masz przecież w main() jakąś pętlę główną .... nie możesz w niej cyklicznie badać stanu pinów ??? Przecież to nie chodzi o to żeby sobie utrudnić życie tylko je ułatwić. Tymczasem często początkujący właśnie takimi pomysłami komplikują je sobie na maxa i później załamują się, że coś im źle idzie to programowanie.

    Spróbuj gdzieś podejrzeć jak robi się taką prostą obsługę klawiszy .... zapewniam cię że wyjdzie prościej i pewniej niż tak jak ty teraz to forsujesz. Warto.

    Powodzenia ;)
  • #11 8883515
    bkawlatow
    Poziom 10  
    Mirek ok tylko cykliczne sprawdzanie pinów jest niemożliwe bo przejście przez pętle main() zajmuje dwie minuty ze względu na liczne pętle opóźniające.


    
    #include<avr/io.h>
    #include<inttypes.h>
    #include <avr/interrupt.h>
    #define F_CPU 4000000U
    #include<util/delay.h>
    
    
    
    
     void pwm1(int y){
    DDRB |= _BV(PB1);
    TCCR1A =  (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) |(1<<COM1B1) | (1<<COM1B0);
    TCCR1B = _BV(CS10) |_BV(WGM12) ;
    OCR1A = y; 
    }
    
    
    void pwm2(int y){
    DDRB |= _BV(PB2);
    TCCR1A =  (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) |(1<<COM1B1) | (1<<COM1B0);
    TCCR1B = _BV(CS10) |_BV(WGM12) ;
    OCR1B = y;
    }
    
    void pwm3(int y){
    DDRB |= _BV(PB3) ;
    TCCR2 = (_BV(WGM21) | _BV(WGM20) | _BV(COM21) | _BV(COM20) | _BV(CS20));
    OCR2 =y;  
    }
    
    
    void czekajsek(int y){//petla opozniajaca
    int z;
    z=y * 20;
    
    while(z>1)
    {
    _delay_ms(50);
    z--;
    } 
    
    }
    
    ISR(INT0_vect)
    {
    
    PORTC ^= (1<<PC0);
    PORTC ^= (1<<PC1);
    	}
    
       
     int main(void)
    {
    
       DDRC = 0xFF;
      PORTC = 0x01;;//ustawia PC0
        DDRD= 0x00;//PD wejsciami
        PORTD= 0xFF;//włącza  pull-up
    	GICR|=(1<<INT0);//włącza przerwanie INT0
    	MCUCR &=~0x03;//zeruje ISC01 i ISC00 int0 reaguje na niski poziom
    	sei();
    int tab[]={0,70,150,170,190,200,230,245,248,255};
    int i,a;
     
     
     
       while(1)
    {
    i=0;
    a=0;
       while(a<10)
             {
             pwm3(i);
           if(a!=0)  czekajsek(7);
    	   else czekajsek(10);//czeka 10 sek z max jasnosc
    	   while(i<tab[a])//płynne zmniejszanie jasnosci
                    {
                   pwm3(i);
                   if(tab[a]>200) 
    			  		 {i++;
    					 czekajsek(1);
    					 }
    			    else
    					 {
    					 i++;
    					 _delay_ms(50);
    					 }
    
                    }
             a++;   
            }
    
    
    
    
    
       while(a>0)//to samo w druga strone
       {
    
          pwm3(i);
          if(a!=255) czekajsek(7);
    	  else czekajsek (10);//czeka 10 sek przy min jasnosci
    
          while(i>tab[a])
                  {
                   pwm3(i);
                   if(tab[a]>200) 
    					 {
    					 i--;
    					 czekajsek(1);
    			  		 }
    			   else
    			 			{
    						 i--;
    						 _delay_ms(50);
    						 }
    
              	  }
         a--;
          
       }
    
    
    
    
    
    }
       
    } 
    

    tutaj masz cały kod programu.W skrócie procek steruje płynnym rozjaśnianiem diod, a następnie wygaszaniem i tak ciągle.W międzyczasie jeżeli zostanie wykryte krańcowe położenie silnika ma nastąpić zmiana kierunku jego obrotów.

    Dodano po 14 [minuty]:

    i jeszcze jedno pytanie czy w ten sposób prawidłowo ustawiam bity ISC00 i ISC01??

    MCUCR &=(1<<ISC00) | (1<<ISC01)
    [/code][/quote]

    Dodano po 14 [minuty]:

    Program działa elegancko mam nadzieję że nie będzie większych niespodzianek.Dziękuję za pomoc:)
  • #12 8883769
    mirekk36
    Poziom 42  
    MCUCR &=(1<<ISC00) | (1<<ISC01)


    a chodziło ci o ustawianie czy zerowanie bitów ???

    Bo to przecież jest zerowanie tyle że z błędem , powinno być tak:

    MCUCR &= ~( (1<<ISC00) | (1<<ISC01) );


    No widzisz a jeśli chodzi o pętlę w której masz dużo opóźnień - to bardzo źle ;) tzn, może źle się wyraziłem - można całkiem inaczej pisać programy, w ten sposób żeby w pętli głównej nie było użytego ani jednego opóźnienia, funkcje żeby były nieblokujące a dzięki temu można już pisać wielozadaniowe programy.

    Jeśli działa i spełnia w 100% założenia to dobrze ;) .... ale warto brnąć dalej i szybko się uczyć ;)
  • #13 8883809
    bkawlatow
    Poziom 10  
    chodziło mi o ustawienie (wpisanie jedynki)
    tak powinno być:

    MCUCR |=(1<<ISC00) | (1<<ISC01)

    tak?
    Mirek Zamierzam w to brnąc tylko na szybkości potrzebowałem odpalić pewien projekt:)
  • #15 8884979
    sulfur
    Poziom 24  
    mirekk36 napisał:

    Po drugie do zmiany stanu na przeciwny wystarczy taka prosta operacja logiczna:

    PORTC ^= (1<<PC0);
    PORTC ^= (1<<PC1);



    Albo jeszcze prostsza
    Moderowany przez zumek:

    Nie dotyczy ATMega8, a ta jest tematem tego wątku.
    Regulamin p.12



    Moim zdaniem najlepszą metodą eliminacji drgań styków to jest układ RC, a skoro nie eliminuje wszystkich, to znaczy, że jego stała jest źle dobrana.
  • #16 8885106
    mirekk36
    Poziom 42  
    sulfur napisał:

    Albo jeszcze prostsza
    PINC |= PC0;
    PINC  |= PC1;



    Że jak? że co? zapisujesz coś tzn starasz się ustawić na 1 bity w porcie wejściowym PIN ????? coś tu się chyba koledze pomyliło na maxa?

    sulfur napisał:

    Moim zdaniem najlepszą metodą eliminacji drgań styków to jest układ RC, a skoro nie eliminuje wszystkich, to znaczy, że jego stała jest źle dobrana.


    jedni wolą takie inni prostsze metody. Zależy co jest dla kogoś prostsze. Ja np używam procka po to żeby dać jak najmniej zbędnych elementów zewnętrznych skoro tak proste rzeczy jak eleiminację drgań styków może bez mrugnięcia oka "odwalać" przy okazji i tak się mocno nudząc - procek ;) ..... Ale jeśli dla kogoś dużym kłopotem jest zrobienie tego programowo to zrozumiałe że będzie wolał instalować dodatkowe elementy na zewnątrz i bawić się w dobieranie stałej - może się uda może się nie uda ;) a programowo uda się zawsze na 100%. Każdy robi to co lubi.

    Dodano po 1 [godziny] 14 [minuty]:

    sulfur napisał:
    mirekk36 napisał:

    Po drugie do zmiany stanu na przeciwny wystarczy taka prosta operacja logiczna:

    PORTC ^= (1<<PC0);
    PORTC ^= (1<<PC1);



    Albo jeszcze prostsza
    zumek napisał:
    Nie dotyczy ATMega8, a ta jest tematem tego wątku.
    Regulamin p.12

    .


    No teraz aż spojrzałem i rzeczywiście można taką "sztuczkę" zrobić ale tak jak napisał zumek to po pierwsze nie dotyczy ATmega8

    ale też nie dotyczy innych procków takich jak ATmega16/32 kolejnych not już nie chciało mi się sprawdzać.

    A dotyczy na pewno: ATtiny2313 czy serii ATmega48/88/168 itd

    ------------

    Najważniejsze jest jednak to, że to w ogóle nie jest tylko "sztuczka" nie związana ze standardem nawet AVR GCC bo dotyczy tylko niektórych procków. However ;) GCC poprawnie to kompiluje czyli ustawia bit za pomocą asemblerowego sbi - jednak niestety nie bacząc jaki to procek.

    Zatem można się srogo przejechać - stosując takie "prostsze" sposoby.

    Za to warto wiedzieć o takiej ciekawostce na którą zapewne nie każdy od razu zawsze zwórci uwagę ;)
  • #17 8890004
    rs07
    Poziom 20  
    Witam na forum. Korzystam i dołączam się do tematu.
    Mój problem jest dla mnie niezrozumiały. Próbowałem kompilować i testować prościutki programik z przerwaniami, ale nie wychodzi. Oto ten programik.

    #include <avr/io.h> // dostęp do rejestrów
    #include <avr/interrupt.h>

    SIGNAL (SIG_INTERRUPT0)
    {
    PORTD = 0x1d; // zgaś diode LED
    }

    SIGNAL (SIG_INTERRUPT1)
    {
    PORTD = 0x0d; // zapal diode LED
    }

    int main(void) // program główny
    {
    DDRD = 0x10; // bit 4 PortD jako wyjscie (LED) pozostale jako wejścia (przyciski)
    PORTD = 0x0d; // podciąganie bitów 3 i 4 PortD (przyciski)
    GIMSK = _BV(INT0)|_BV(INT1); //włącz obsługę przerwań Int0 i Int1
    MCUCR = _BV(ISC01)|_BV(ISC11); // włącz generowanie przerwań przez opadające zbocze na Int0 i Int1

    sei(); // włącz obsługę przerwań

    while(1); // pętla nieskończona
    }

    W czasie kompilacji jest błąd i komunikat:
    ../przerw.c:13: error: redefinition of 'SIGNAL'
    Używam AVR Studio4
    Co robię nie tak, że kompilator nie rozpoznaje słowa SIGNAL i traktuje je jak definicję zwykłej funkcji. Zdefiniowanie jednego przerwania,też się nie udaje, bo po wywołaniu przerwania, następuje reset, zamiast wykonania obsługi przerwania.

    Proszę o pomoc bardziej doświadczonych kolegów.
  • #18 8890108
    mirekk36
    Poziom 42  
    rs07 -->

    Po pierwsze to powinieneś założyć nowy temat a nie się tak doklejać z całkiem innym problemem poza nazwą.

    Po drugie po co dwa razy powtarzasz to samo w jednym poście - nawet jak wyszło niechcąco to post można wyedytować i poprawić

    Po trzecie jak się wkleja kod to daje się znaczniki CODE bo inaczej to chyba widzisz jaką SIECZKĘ widać w twoim poście a jak ładnie widać kod w postach wyżej - tak trudno?

    Po czwarte - przechodząc do meritum twoich problemów, to skąd żeś pan wziął sobie nazwy tych wektorów przerwań do makr SIGNAL ?????? bo podejrzewam że z kosmosu albo najbardziej odległych zakamarków własnych szarych komórek.

    Po piąte - nie stosuje się już makr SIGNAL tylko ISR

    A na zakończenie powiem, że wystarczy zajrzeć do pliku nagłówkowego własnego procesora w folderze WinAVR (tam gdzie one leżą) a w nim znajdziesz dokładnie wszystkie nazwy wektorów przerwań dla swojego procka. Wtedy wyjdzie.

    aaa i jeszcze jedno. Czy tak trudno przeczytać ci to co wyżej było napisane? POLECAM ci przeczytać drugi POST od góry i wziąć to do siebie.

    Bo im dalej będziesz pisał takie bezeceństwa:

    PORTD = 0x0d; 
    
    PORTD = 0x1d; 
    
    DDRD = 0x10; 
    
    PORTD = 0x0d;  


    tym bdzie gorzej i gorzej i trudniej do opanowania ;)

    a przecież już w kilku linijkach coś cię olśniło i napisałeś już czytelniej:

    
    GIMSK = _BV(INT0)|_BV(INT1); 
    MCUCR = _BV(ISC01)|_BV(ISC11);


    (może warto sięgnąć po jakąś książkę do nauki C ? ;)
REKLAMA