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

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

18 Gru 2010 12:33 1632 17
  • Poziom 9  
    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.

    Code:

    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:
    Code:

     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ć?
  • 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:

    Code:
    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:

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


    a później w main():

    Code:
    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ść.
  • Poziom 9  
    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]
  • 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!!
  • Poziom 9  
    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".
  • 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 ?
  • Poziom 9  
    Wiem że w przerwaniu nie powinno dawać się opóźnienia ale chyba w tym przypadku jest to niezbędne jak myślicie?
  • 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 ;)
  • Poziom 9  
    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.
  • 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 ;)
  • Poziom 9  
    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.


    Code:

    #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??

    Code:
    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:)
  • Poziom 42  
    Code:
    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:

    Code:
    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ć ;)
  • Poziom 9  
    chodziło mi o ustawienie (wpisanie jedynki)
    tak powinno być:

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

    tak?
    Mirek Zamierzam w to brnąc tylko na szybkości potrzebowałem odpalić pewien projekt:)
  • Poziom 42  
    no teraz to już zrobiłeś prawidłowe ustawianie bitów ;) i ładnie napisane, tylko jeszcze średnik na końcu ;)
  • Poziom 24  
    mirekk36 napisał:

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

    Code:
    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.
  • Poziom 42  
    sulfur napisał:

    Albo jeszcze prostsza
    Code:
    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:

    Code:
    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ę ;)
  • 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.
  • 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:

    Code:
    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:

    Code:

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


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