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

błędna obsługa przerwania INT1 - ustalenia szerokości impuls

krecik_jg 31 Lip 2009 21:01 1631 1
  • #1 31 Lip 2009 21:01
    krecik_jg
    Poziom 10  

    Witam. Tworzę mały projekcik i natrafiłem na pewną zagwózdkę.

    Na początku wprowadzenie co układ ma robić i jak działać.

    Układ składa się z części analogowej, tzn. dwóch detektorów tonu (LM567) odpowiedzialnych za detekcję "bitów" łącza fizycznego. Chodzi o to, że rozpoznają "swoją" częstotliwość i gdy stwierdzą zgodność z obwodem czasowym, na swoim wyjściu ustawiają stan niski (oczywiście, w przeciwnym przypadku na wyjściu detektora panuje stan wysoki). Następnie wyjścia detektorów doprowadzane są odpowiednio do wejść uC -> 500Hz do wejścia INT1, oraz 200Hz do wejścia INT0 (jak na schemacie). Tutaj właśnie zaczynają się schody.


    Wejście INT1 początkowo ustawione jest na wyzwalanie zboczem opadającym. Wynika to z pracy detektorów, które w stanie "nie wykrycia prawidłowej częstotliwości" mają na wyjściu stan wysoki. Jeśli uC wykryje zbocze opadające na INT1, oznacza to, że detektor wykrył nadchodzący bit "H". W tym momencie w procedurze obsługi przerwania INT1 włączany jest licznik i zostaje przestawione przerwanie INT1 na zbocze narastające - w oczekiwaniu na powrót wyjścia detektora do stanu pierwotnego. Gdy detektor przestanie wykrywać zgodność częstotliwości - na swoim wyjściu ustawi stan wysoki, co powinno wyzwolić przerwanie INT1. W tym momencie licznik jest zatrzymywany, przerwanie INT1 przestawiane na zbocze opadające i uruchamiany jest timer odmierzający czas początkowo połowy impulsu. Po pierwszym wywołaniu przerwania licznika, czas ten zmieniany jest na czas całego impulsu i przerwanie dalej robi swoje. W ten sposób w połowie każdego impulsu badamy stan pinów wejściowych by określić jaki bit odbiera uC. Daje to możliwość rozpoznania czy mamy do czynienia z odebranym bitem „H” czy dwoma sąsiadującymi bitami „H”.

    Proces ten synchronizuje odbiornik z nadajnikiem (w prymitywny sposób ale jednak ;- ). Problem w tym, że pierwsze przerwanie INT1 nie działa jak powinno. Zliczanie szerokości pierwszego impulsu na porcie INT1 nie działa, przez cos nie działa synchronizacja.
    Sprawdzałem część analogową i rzeczywiście stany na wyjściach zmieniają się prawidłowo (z wysokiego na niski przy zgodności). Wydaje mi, się że problem leży w kodzie uC. Od niedawna zabrałem się za programowanie uC, wiec pewnie są w nim błędy, jednak ja ich nie widzę :/

    Prowizoryczny schemat układu:
    błędna obsługa przerwania INT1 - ustalenia szerokości impuls

    Poniżej przedstawiam cały kod uC:

    Code:



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




    //---------------------------
    //INT0-"L"   PORTD6 ="L"
    //INT1-"H"   PORTD7 ="H"
    //---------------------------

    //liczymy od 0 więc: pin2 to INT0, pin3 to INT1
    #define IN_H (PIND&(1<<3)) && !(PIND&(1<<2))
    #define IN_L (PIND&(1<<2)) && !(PIND&(1<<3))


    #define OUT_H_on  PORTD |= 1 << 7
    #define OUT_H_off PORTD &= ~(1 << 7)

    #define OUT_L_on  PORTD |= 1 << 6
    #define OUT_L_off PORTD &= ~(1 << 6)


    volatile unsigned char pomiar = 0;

    volatile unsigned long int takt =0;
    //nsigned char sreg;



    void INT1_vect(void) __attribute__ ((interrupt));
    void TIMER1_COMPB_vect(void) __attribute__ ((interrupt));



    void INT1_vect(void) //obsługa przerwania bitu startu
    {
      cli();                        // Wyłączenie obsługi przerwań
    /*
    zmienna pomiar określa czy oczkujemy na zbocze opadające - sugerujące poczatek
    impulsu, czy na zbocze narastajace - sugerujące konieć właśnie obrabianego
    impulsu.
    */
      if (pomiar==0)
      {//oczekujemy na zbocze opadajace, rozpoczynające impuils na pinie INT1
        TCNT1 = 0;                     // rejest danych licznika/zegara 1 (rejestr 16-bitowy) Zerowanie czasomierza T/C1
        TCCR1B |= (1<<CS10)|(1<<CS12); // Zalaczenie timera1 - preskaler ck/1024
     
        MCUCR = 0;                     // Zerowanie rejestru MCUCR, rejestr sterujący mikrokontroletrem

        MCUCR |= (1<<ISC11)|(1<<ISC10);// Przestawienie przerwania na zbocze narastajace

        pomiar = 1; //od tego momentu na pinie INT1 będzie panował stan niski, więc będziemy oczekiwac na zbocze narastajace

    //   OUT_H_on; //jedną diodę zapalamy,...
    //   OUT_L_off;//... a drugą gasimy.
      }
      else
      {//oczekujemy na zbocze narastajace, kończące impuils na pinie INT1
        TCCR1B &= ~((1<<CS10)|(1<<CS12));   // Wylaczenie timera1,czyli wyzerowanie bitów CS10 i CS12

        MCUCR = 0;                     // Zerowanie rejestru MCUCR, rejestr sterujący mikrokontroletrem

        MCUCR |= (1<<ISC11)|(0<<ISC10);//Przestawienie przerwania spowrotem na zbocze opadające
    /*
    skończyliśmy właśnie zliczanie szerokości impulsu na pinie INT1.
    W rejestrze TCNT1 (składajacym się z TCNT1H i TCNT1L) znajdują się zliczone dane
    */
        takt = TCNT1; //Zapis rejestru TCNT1 do zmiennej takt
    //    synchro=0;    //kończymy proces synchorinzacji, czyli określanie długości pojedyńczego impulsu bitów łącza fizycznego

        pomiar = 0;//od tego momentu na pinie INT1 będzie panował stan wysoki, więc będziemy oczekiwac na zbocze opadajace

    //   OUT_L_on; //jedną diodę zapalamy,...
    //   OUT_H_off;//... a drugą gasimy.




    //--------------------------------------
        GICR &= ~(1 <<INT1); // wyłączenie przerwania na INT1, GICR rejstr sterujący kontrolą przerwań

    /*
    Skończylismy już etap synchronizacji, więc wyłączamy przerwanie INT1. by
    ponownie nie wyliczać szerokości impulsu pojedyńczego bitu.
    */


    //czas = takt/2;//po odebraniu bitu strtu odczekujemy pół szerokości bitu, następnie sprawdzamy stan wejść
    OCR1B = takt;
    //    OCR1B = takt/2; //16-bitowt rejest zawierającym wzorzec do porównania z zawartością rejestru danych licznika
        TCNT1 = 0;    //rejest danych licznika/zegara 1 (rejestr 16-bitowy) Zerowanie czasomierza T/C1
     
        //Zezwalamy na przerwanie od licznika w chwilu gdy OCR1B == TCNT1:
        TIMSK  |= (1<<OCIE1B); //bit zezwolenia na generowanie sygnałów przerwań od układu licznika 1 gdy OCR1B == TCNT1


        //odpalicz licznik w trybie porównywania wartosci OCR1B z warotścią TCNT1:
        TCCR1B |= (1<<CS10)|(1<<CS12); // Zalaczenie timera1 - preskaler ck/1024

    //    czas = takt;  //następnie odczekuejmy już cały okres bitu, by próbkować stan wejść w środku trwania impulsu
    //--------------------------------------
      }

       sei();//skończyliśmy obsługe przerwania, więc możemy spwrotem włączyć obsługę przewań
    }





    //obsługa przerwania (tutaj jest to negowanie wyjścia PC0)
    void TIMER1_COMPB_vect(void) //obsługa przerwania od timera
    {
      cli();                        // Wyłączenie obsługi przerwań

      PORTC ^= 0x01;//wskażnik odczytu bitw wejściowych
    /*
    Chwila zmiany stanu diody odnacza moment odczytu wartosci bitów.
    Gdy dioda zapala się lub gaśnie - w tym momenice odczytywane są
    stany na wejsciach uC
    */



    //liczymy od 0 więc: pin2 to INT0, pin3 to INT1
    //#define IN_H (PIND&(1<<3)) && !(PIND&(1<<2))
    //#define IN_L (PIND&(1<<2)) && !(PIND&(1<<3))




      if (IN_H)//(IN_H) //INT1
      {
        OUT_H_on;
        OUT_L_off;
      }
      else
      if (IN_L) //INT0
      {
        OUT_H_off;
        OUT_L_on; 
      }



    /*
    Pierwszy raz zostanie wywołana w połowie drugiego bitu łącza fizycznego
    (czyli drugiego bitu synchornizacji).
    */
      OCR1B = takt; //16-bitowt rejest zawierającym wzorzec do porównania z zawartością rejestru danych licznika
      TCNT1 = 0;    //rejest danych licznika/zegara 1 (rejestr 16-bitowy) Zerowanie czasomierza T/C1

      sei();//skończyliśmy obsługe przerwania, więc możemy spwrotem włączyć obsługę przewań   
    }



    int main(void)
    {
    //-----------------------------------------------------------
    //-----------------------------------------------------------
    //Inicjalizacja ustawień:
      sei();                            // Włączenie obsługi przewań, by miały szansę w ogóle zadziałać 
      MCUCR = 0;                        // Zerowanie rejestru MCUCR, rejestr sterujący mikrokontroletrem

      MCUCR |= (1<<ISC11)|(0<<ISC10);   // Wyzwolenie przerwania zboczem opadającym
    /*
    rozpoczynamy wyzwalanie zboczem opadajacym, ponieważ gdy detegor tonu LM567 nie wykryje
    prawidłowej częstotliwości, na zwoim wyjscu utrzymuje stan wysoki. Dopiero po wykryciu
    zgodność ustawia na wyjściu stan niski. Dlateog stany rozpoznawane przez uC będą
    logicznym odbiciem stanów wyjscia detektora. Jeśli detektor wykryje informację, ustawia
    stan niski na wysjcie co odpowiada, że pojawił się dany bit informacji na wejsci uC.
    */

     
       GICR |= 1<<INT1;                  // Załączenie przerwania na INT1
    /*
    Z ustawień wynika, że na po strnie INT1 (PD2) będzie podpięte wyjscie z detektora,
    który odpowiada za wykrywanie bitów "H". Po wykrycu zgodnosci częstotliwości, detekto
    podaje na na wejscie INT1 uC stan niski wyzwalając przerwanie INT1, które obsługiwane
    jest przez procedurę obsługi przerwania.
    */

       TCCR1B = 0;                       // T/C1 w trybie czasomierza
    /*
    ICNC1=0 brak eliminacji szumów i zakłóceń
    ICES1=0 wyzwalanie zboczem opadającym
    WGM13,WGM12,WGM11,WGM10,=0, Normalny tryb licznikowy -tryb pracy
    CS12, CS11, CS10 =0, licznik wyłączony. określając żródło i stopień wstępnego podzielnika dla układu zegara/licznika
    */


        OUT_H_off;//gasiby obie diody, bo nie
        OUT_L_off;//odebraliśmy żadnych bitów
    //-----------------------------------------------------------
    //-----------------------------------------------------------

    //Przerwania timerów aktywuje się w rejestrze TIMSK...

      /* Wszystkie linie portu B  będą wyjściami */
     // DDRD  = 0xff;
      DDRB  = 0xff;

       // port PC0  to wyjście
       DDRC = 0x01;
    /* Za linie wejściowe posłużą porty PORTD
    (czy nie będzie to problemu z przerwaniami??)
     */


    //ustawienie bitu DDRD -to wyjscie, wyzerowanie to wejscie
      DDRD  = 0xF3;//tylko pini INT0 i INT1 są wejściami, reszta to wyjścia


    //ustawienie bitu PORTD - to pull'up
      PORTD = 0x0C;//wejściemi z włączonymi pull-up'ami



    /*
    Bez włączonych pull-up-ów, gdy "wisi on w powietrzu", to z powodu
    wysokiej imedancji wejściowej, port "łapie" śmieci, co może
    doprowadzić do błędnych odczytów stanu portu - dając przypadkowe
    wartosci.
    Właczenie pull-up-ów, wymusza stan wysoki, bez konieczności stosowaie
    zewnętrznych rezystorów podciągających.
    */


    /* Początek nieskończonej pętli, w której będzie wykonywany program*/
      while(1)
      {
      }

    }





    Jeśli wiecie co mogłem namieszać, zrobić źle, lub przekombinować, dajcie znać ;-)

    0 1
  • #2 01 Sie 2009 14:35
    lnl
    Poziom 11  

    Masz błąd w ponownym przestawieniu przerwania na zbocze opadające:

    Code:

    MCUCR |= (1<<ISC11)|(0<<ISC10);//Przestawienie przerwania spowrotem na zbocze opadające


    Powyższy zapis nic nie zmienia, bity ISC11 i ISC10 pozostają bez zmian, wystarczy wyzerować bit ISC10 aby przestawić na zbocze opadające:

    Code:

    MCUCR &= ~(1<<ISC10);//Przestawienie przerwania spowrotem na zbocze opadające


    Pozdrawiam,
    Michał

    1