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

Programowanie liczników MSP430

pablos23 16 Kwi 2008 12:42 9276 102
  • Pomocny post
    #31
    Dr_DEAD
    Poziom 28  
    No, to już wszystko wiesz :-). Piszesz w IAR prawda? no to włącz, gdy będziesz debugował, okienko View->Disassembly. I tam będziesz miał instrukcje assemblera czyli wynik pracy kompolatora nad Twoim kodem w C. Wystarczy że zobaczysz co to za instrukcje i policzysz ile mniej więcej zajmują cykli zegarowych.
  • TespolTespol
  • #32
    pablos23
    Poziom 15  
    Ilość cykli CPU w przerwaniu od TimerA to 141 przy założeniach:

    - dla instrukcji jmp i jne, których ilość cykli nie jest podana przyjąłem 6,
    - w przypadku gdy instrukcja nie podaje liczby cykli danej instrukcji w określonym trybie adresowania przyjąłem najczęśniej powtarzającą się wartość z innych trybów - XOR - 5 cykli.

    Tylko co to zmienia dla jednostki centralnej? Jeśli jest taktowana MCLK z określoną częstotliwością może wykonać to przerwanie szybciej lub wolniej. Czy mam rację? Dlaczego nie miałaby czasu na obsługę każdego przerwania?
  • #33
    Dr_DEAD
    Poziom 28  
    pablos23 napisał:

    Tylko co to zmienia dla jednostki centralnej? Jeśli jest taktowana MCLK z określoną częstotliwością może wykonać to przerwanie szybciej lub wolniej. Czy mam rację? Dlaczego nie miałaby czasu na obsługę każdego przerwania?

    No jeżeli MCLK i SMCLK zasilane jest z DCO bez żadnych dzielików, to poprostu MCLK i SMCKL są sobie równe. A Ty zasiliłeś licznik A z zegara SMCLK i robiłeś przerwania co 1 takt tego zegara, czyli otrzymywałeś przerwanie co 1 takt MCLK, czy to nie mogło działać.
  • #34
    pablos23
    Poziom 15  
    Zrozumiałem potrzebę ustawienia fSMLCK < fMCLK. CPU musi zdążyć obsłużyć całe przerwanie czyli np. w programie gdzie MCLK=SMCLK=1MHZ, czwarty warunek TAR=200us nie jest sprawdzony bo CPU jest jeszcze przy wcześniejszych instrukcjach.

    Mam tylko jedną wątpliwość:
    Cytat:
    robiłeś przerwania co 1 takt tego zegara, czyli otrzymywałeś przerwanie co 1 takt MCLK


    Czy jeśli CCR0 = 50 wejście do przerwania nie nastąpi co 50 cykli SMCLK?
  • Pomocny post
    #35
    Dr_DEAD
    Poziom 28  
    pablos23 napisał:

    Czy jeśli CCR0 = 50 wejście do przerwania nie nastąpi co 50 cykli SMCLK?

    TAK jeżeli: SMCLK=CLK=TAR. Chodzi Ci pewno o zapis w przerwaniu: CCR0 += 50; No to wtedy TAR dla kolejnych przerwań będzie wyglądał tak:
    TAR = 50
    TAR = 100
    TAR = 150
    TAR = 200
    ......
    Czyli pomiędzy poszczególnymi przerwaniami będzie 50cykli MCLK.
  • TespolTespol
  • #36
    pablos23
    Poziom 15  
    Nasunęła mi się jeszcze jedna wątpliwość:

    MCLK=1MHz => T=1us
    SMLCK=1MHz/64 = 15,625 kHz => 64us

    Kiedy TAR=200 i CCR0= 200 program wchodzi do rutyny przerwania i sprawdza kolejne warunki. Cykl rutyny to około 141 us, więc 4 warunek będzie sprawdzony po około 110 us. Jeśli dobrze rozumiem, wartość TAR będzie równa wtedy 201 lub 202 więc warunek 4 nigdy nie powinien być spełniony. Mimo to na oscyloskopie mam właściwe sygnały. Jak to możliwe?

    Jaka jest rola funkcji while(1) ?
  • Pomocny post
    #37
    Dr_DEAD
    Poziom 28  
    pablos23 napisał:

    Kiedy TAR=200 i CCR0= 200 program wchodzi do rutyny przerwania i sprawdza kolejne warunki. Cykl rutyny to około 141 us, więc 4 warunek będzie sprawdzony po około 110 us. Jeśli dobrze rozumiem, wartość TAR będzie równa wtedy 201 lub 202 więc warunek 4 nigdy nie powinien być spełniony. Mimo to na oscyloskopie mam właściwe sygnały. Jak to możliwe?

    Bardzo dobrze rozumiesz, ale zauważ że właśnie z tego powodu przepisuje TAR do "temp" na samym początku przerwania i puźniej już tylko "temp" powrównuje.
    pablos23 napisał:

    Jaka jest rola funkcji while(1) ?
    Zatrzymuje program w miescu. To coś jak:

    Code:

    Etykieta
                 jump to Etykieta
  • #38
    pablos23
    Poziom 15  
    Myślę, że teraz rozumiem już całość. Wkrótce biorę się za następny problem. Chcę zmieniać te częstotliwości w czasie. Największym wyzwaniem będzie na pewno napisanie równoważnika przypadku oscylacyjnego w stanie nieustalonym obwodu RLC. Jeśli uda mi się to pomyślę nad dwoma sygnałami przesuniętymi fazowo, gdzie to przesunięcie to zawsze 25% ich okresu. Okres tych dwóch sygnałów będzie zawsze równy (enkoder).
  • #39
    pablos23
    Poziom 15  
    Zastanawiam się nad kodem generującym zmienną częstotliwość na danym pinie. Chcę zmniejszać i zwiększać częstotliwość na tym samym pinie w określonych odcinkach czasu.

    Dla kodu poniżej pomysł był taki, aby przełączać pin coraz wolniej na wielokrotnościach 3. Nie mam jednak żadnego sygnału na wyjściu i nie wiem dlaczego. MCLK = 62.5 ns, SMCLK=4us.
    Nawet gdyby program działał, "zwalnia" bardzo szybko. Gdybym użył mnożnika ułamkowego po najwyżej 50 przejściach przekroczyłbym zakres.

    Code:
    #include  <msp430x20x3.h>
    
     
    #include <intrinsics.h>

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;
      BCSCTL2 = DIVS_3;
      BCSCTL1 = CALBC1_16MHZ;
      DCOCTL = CALDCO_16MHZ;
      P1DIR |= (BIT1 | BIT2 | BIT3 | BIT4);
      TACCR0 = 3;
      TACCTL0 = CCIE;
      TACTL = TASSEL_2 + ID_3 + MC_2 + TAIE;
      __enable_interrupt();
      while(1);
    }
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      int temp;
      temp = TAR;
      int n = 3;
      if( n == temp)
      {
        P1OUT ^= BIT1;
        n = n * 3;
      }
      TACCR0 += 3;
    }


    Proszę o pomoc.
  • #40
    Dr_DEAD
    Poziom 28  
    pablos23 napisał:

    Code:

    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      int temp;
      temp = TAR;
      int n = 3;
      if( n == temp)
      {
        P1OUT ^= BIT1;
        n = n * 3;
      }
      TACCR0 += 3;
    }


    Wiesz że Twoja zmienna "n" jest inicjalizowana na 3 przy każdym wejściu do przerwania? więc zamiast if(n == temp) równie dobrze można by napisać if(3 == temp). Zmienna "n" nie przetrwa pomiędzy wywoływaniami przerwań, bo jest lokalna a nie globalna
  • #41
    pablos23
    Poziom 15  
    Teraz zmienną n deklaruję jako globalną. Po kompilacji dostaję:
    "Warning[Pe177]: variable "n" was declared but never referenced "
    Czy jest błędem deklaracja zmiennej globalnej i odwoływanie się do niej w rutynie przerwania. Wiem,że to są podstawowe błędy,ale to początki.
    Code:
    #include  <msp430x20x3.h>
    
     
    #include <intrinsics.h>

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;
      BCSCTL2 = DIVS_3;
      BCSCTL1 = CALBC1_16MHZ;
      DCOCTL = CALDCO_16MHZ;
      P1DIR |= (BIT1 | BIT2 | BIT3 | BIT4);
      int n = 3;
      TACCR0 = 3;
      TACCTL0 = CCIE;
      TACTL = TASSEL_2 + ID_3 + MC_2 + TAIE;
      __enable_interrupt();
      while(1);
    }
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      int temp;
      temp = TAR;
      if( n == temp)
      {
        P1OUT ^= BIT1;
        n = n * 3;
      }
      TACCR0 += 3;
    }
  • Pomocny post
    #42
    Dr_DEAD
    Poziom 28  
    Zerknij na stronę wcześniej, i odszukaj gdzie ja deklarowałem zmienne Licznik1, Licznik2, Licznik3, Licznik4.
  • #43
    pablos23
    Poziom 15  
    Poprawiłem błąd, ale nadal nie mam sygnału na wyjściu. Celem programu jest przełączanie pinu na 8,16,32,64...us. Zawartość przerwania jest sprawdzana co 8 us. Momenty przełączenia są definiowane przez n. Nie ma błędów po kompilacji ale nie ma też sygnału.
    Code:
    #include  <msp430x20x3.h>
    
    #include <intrinsics.h>
    int n=2;
    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;
      BCSCTL2 = DIVS_3;
      BCSCTL1 = CALBC1_16MHZ;
      DCOCTL = CALDCO_16MHZ;
      P1DIR |= (BIT1 | BIT2 | BIT3 | BIT4);
      TACCR0 = 2;
      TACCTL0 = CCIE;
      TACTL = TASSEL_2 + ID_3 + MC_2 + TAIE;
      __enable_interrupt();
      while(1);
    }
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      int temp;
      temp = TAR;
      if( n == temp)
      {
        P1OUT ^= BIT1;
        n = n * 2;
      }
      TACCR0 += 2;
    }
  • #44
    pablos23
    Poziom 15  
    Mój błąd ( nie wiem czy jedyny) to nieużywanie trybu single sweep w oscyloskopie. Kiedy przetestuję ten program w takim trybie, podzielę się wrażeniami.
    To mój obecny kod:
    Code:
    #include  <msp430x20x3.h>
    
    #include <intrinsics.h>
    long int n=2;
    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;
      BCSCTL2 = DIVS_3;
      BCSCTL1 = CALBC1_16MHZ;
      DCOCTL = CALDCO_16MHZ;
      P1DIR |= (BIT1 | BIT2 | BIT3 | BIT4);
      TACCR0 = 2;
      TACCTL0 = CCIE;
      TACTL = TASSEL_2 + ID_3 + MC_2 + TAIE;
      __enable_interrupt();
      while(1);
    }
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      int temp;
      temp = TAR;
      if( n == temp)
      {
        if ( n < 65536 )
        {
        P1OUT ^= BIT1;
        n = n * 2;
        }
        if ( n == 65536 )
        {
          P1OUT ^= BIT1;
          n = 0;
      }
      TACCR0 += 2;
      }
    }
  • #45
    pablos23
    Poziom 15  
    To mój obecny program zmniejszający częstotliwość eksponencjalnie. Zamiana dwóch parametrów pozwoli uzyskać narastającą częstotliwość. Jutro sprawdzę czy to działa.
    Code:
    #include  <intrinsics.h> 
    
    #include  <msp430x20x3.h>

    unsigned int n=2;
    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;
      BCSCTL2 = DIVS_3;
      BCSCTL1 = CALBC1_16MHZ;
      DCOCTL = CALDCO_16MHZ;
      P1DIR |= (BIT1 | BIT2 | BIT3 | BIT4);
      TACCR0 = 2;
      TACCTL0 = CCIE;
      TACTL = TASSEL_2 + ID_3 + MC_2;
      P1OUT = 0x02;
      __enable_interrupt();
      while(1);
    }
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)

    {
      unsigned int temp;
      temp = TAR;
      if( n == temp)
      {
        if ( n < 65536 )
        {
          P1OUT ^= BIT1;
          n = n * 2;
        }
        else
          n = 2;
      }
      TACCR0 += 2;
    }
  • #46
    pablos23
    Poziom 15  
    Czy mógłbyś wytłumaczyć działanie następujących linijek kodu:
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
  • Pomocny post
    #47
    Dr_DEAD
    Poziom 28  
    pablos23 napisał:
    Czy mógłbyś wytłumaczyć działanie następujących linijek kodu:
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)

    w "wolnym tłumaczeniu"
    Linijka jeden: Adres kolejnej obsługi przerwania zapisany będzie we Flashu pod vectorem przerwania od Timera A0.
    Linijka dwa: Ta funkcja jest obsługą przerwania a więc powinna kończyć się na RETI a nie na RET. (RETI i RET to instrukcje assemblera - nie wiem czym do niego zaglądałeś).
  • #48
    pablos23
    Poziom 15  
    Próbuję konfigurować zegary. Dlaczego mam błędy "RSEL_10 i DCO_3 undefined" dla następujących linijek kodu:

    Code:
    DCOCTL = DCO_3;
    
    BCSCTL2 = DIVS_3;


    Dodano po 2 [godziny] 10 [minuty]:

    Mam jeszcze jeden problem. W programie generującym 4 częstotliwości skonfigurowałem okres MCLK na 1us, zaś okres SMCLK na 64 us. Do przerwanie wchodzę co 25 taktów zegara i wtedy mam sygnał na wyjściu. Problem jest kiedy ustawiam okres SMCLK na 32us. Wtedy nie mam nic. Nie rozumiem tego bo wykonanie przerwania wraz z wejściem i wyjściem to około 140 cykli.
  • #49
    pablos23
    Poziom 15  
    Zmieniając wartości licznik1 i PER1 zmieniałem częstotliwość sygnału na P1.1. Dla okresu MCLK=62.5ns i okresu MCLK = 4us możliwa była generacja sygnału o okresie nie mniejszym niż 160us. Kiedy usunąłem TAIE z TACTL otrzymywałem częstotliwości do 83kHz. Dlaczego tak się dzieje?

    Dodano po 2 [minuty]:

    Mam jeszcze jeden problem. Chcę zrobić przesunięcie fazowe między sygnałami na P1.1 i P1.2. Chcę aby pierwszy sygnał wyprzedzał drugi o 25 % wartości okresu tych sygnałów. Dla poniższego kodu to drugi sygnał wyprzedza pierwszy o tą wartość:

    Code:
    #include <intrinsics.h>
    
    #include  <msp430x20x3.h>

    int counter1=50, counter2=75 ,counter3=150 ,counter4=200;

    #define PER1  50
    #define PER2  50
    #define PER3  150
    #define PER4  200
    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;
      // Clock Setup
      BCSCTL2 = DIVS_3;
      // Timer Setup
      BCSCTL1 = CALBC1_16MHZ;
      DCOCTL = CALDCO_16MHZ;
      P1DIR |= (BIT1 | BIT2 | BIT3 | BIT4);
      TACCR0 = 25;
      TACCTL0 = CCIE;
      TACTL = TASSEL_2 + ID_2 + MC_2;
      __enable_interrupt();
      while(1);
    }
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      int temp;
      temp = TAR;
      if(counter1 == temp)
      {
        P1OUT ^= BIT1;
        counter1 = temp + PER1;
      }

      if(counter2 == temp)
      {
        P1OUT ^= BIT2;
        counter2 = temp + PER2;
      }

      if(counter3 == temp)
      {
        P1OUT ^= BIT3;
        counter3 = temp + PER3;
      }

      if(counter4 == temp)
      {
        P1OUT ^= BIT4;
        counter4 = temp + PER4;
      }
      TACCR0 += 25;
    }
  • #50
    Dr_DEAD
    Poziom 28  
    A dlaczego po prostu nie zamienisz je wartościami?
    Code:

    int counter1=75, counter2=50 ,counter3=150 ,counter4=200;
  • #51
    pablos23
    Poziom 15  
    Zrobiłem to,ale chcę rozumieć mój program.
  • #52
    pablos23
    Poziom 15  
    Mam pytanie do programu z poprzedniej strony generującego 4 częstotliwości.Co się stanie z zawartością zmiennej temp jeśli wpiszemy do niej wartość przekraczającą zakres int? Pytam bo TAR ma zakres od 0 do 65535 zaś zmienna int to <-32768, 32768>.
  • #53
    Dr_DEAD
    Poziom 28  
    pablos23 napisał:
    Mam pytanie do programu z poprzedniej strony generującego 4 częstotliwości.Co się stanie z zawartością zmiennej temp jeśli wpiszemy do niej wartość przekraczającą zakres int? Pytam bo TAR ma zakres od 0 do 65535 zaś zmienna int to <-32768, 32768>.

    Masz rację, to jest błąd !!. Tu wszędzie powinny być "unsigned int". Sorry dopiero raczkuję w "C" :-).
  • #54
    pablos23
    Poziom 15  
    Nie ma sprawy. Cieszę się, że oboje się czegoś nauczyliśmy :D .

    Do czego w programie generującym 4 stałe częstotliwości służy nam TAIE. Czy nie wystarczy wyzwolić przerwania CCIE od rejestru przechwytująco-porównującego?
  • Pomocny post
    #55
    Dr_DEAD
    Poziom 28  
    pablos23 napisał:

    Do czego w programie generującym 4 stałe częstotliwości służy nam TAIE. Czy nie wystarczy wyzwolić przerwania CCIE od rejestru przechwytująco-porównującego?

    TAIE to zezwolenie na przerwanie od przepełnienia licznika. CCIE powinno nam wystarczyć bo tylko z tego przerwania korzystamy.
  • #56
    pablos23
    Poziom 15  
    Czy zmienna temp będzie zmieniała swoją wartość w czasie trwanie ISR? Zakłóżmy,że T(MCLK)=1us,T(SMCLK)=64us, CCR0 =50. Czy przy czwartym warunku temp będzie miało inną wartość niż przy pierwszym?
  • Pomocny post
    #57
    Dr_DEAD
    Poziom 28  
    pablos23 napisał:
    Czy zmienna temp będzie zmieniała swoją wartość w czasie trwanie ISR? Zakłóżmy,że T(MCLK)=1us,T(SMCLK)=64us, CCR0 =50. Czy przy czwartym warunku temp będzie miało inną wartość niż przy pierwszym?

    Zmienna temp właśnie jest po to wprowadzona aby nie zmieniała swojej wartości w czasie ISR'a. Po to aby złapać wartość Licznika w chwili przerwania przepisuje się go do temp. Gdyby obsługa całego przerwania trwałą krucej niż jeden tak licznika to zmienna temp nie byłaby potrzebna.
  • #58
    pablos23
    Poziom 15  
    Przesunięcie fazowe między sygnałami działa już tak jak chcę.

    Jestem na etapie tworzenia programu zmieniającego w czasie częstotliwość na wyjściowym pinie. Zależy mi aby częstototliwość ta zmieniała się wolno np. przyrost z 1kHz do 30 kHz następował w czasie kilku sekund.

    W programie poniżej używam zmiennej var, ponieważ TAR restartuje się zawsze po osiągnięciu FFFF. Dzięki var w drugim przebiegu TAR dla TAR=1 będe miał 65536, dla TAR=2 - var = 65537 itd.Dwie kolejne instrukcje if mają wykonywać się naprzemian w nieskończoność. W czasie pierwszych 800 przebiegów zmiany na wyjściowym pinie nastąpią po 6,18,36,60us....(wiem,że zegary nie są jeszcze skonfigurowane poprawnie)
    W czasie kolejnych 800 powtórzeń pętli for chcę zwiększać częstotliwość. Zmiany stanu sygnałów nastąpią po 2403,2400,2397...us.Ponadto zmienna var musi być restartowana po każdych 1600 przebiegach pętli.

    Program kompiluje się bezbłędnie, ale na oscyloskopie mam stałą częstotliwość o okresie T=8us. Może zna ktoś odpowiedź - dlaczego?

    Code:
    #include  <intrinsics.h> 
    
    #include  <msp430x20x3.h>

    long unsigned int counter1=3;

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;
      BCSCTL1 = CALBC1_16MHZ;
      DCOCTL = CALDCO_16MHZ;
      BCSCTL2 = DIVS_3;
      P1DIR |= 0x1E;
      TACCR0 = 3;
      TACCTL0 = CCIE;
      TACTL = TASSEL_2 + MC_2 + ID_3;
        __enable_interrupt();
      while(1);
    }
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      int k,m;
      unsigned int temp;
      temp = TAR;
      long int var;
      int aux = 0;
      if ( temp == 65535 )
      {
       aux = aux + 1;
      }
      var = temp + 65535 * aux;

      k = 6;

         for (m=1; m <= 1600; m++)
         {

                       if(counter1 == var | m < 800)
                       {
       
                        P1OUT ^= 0x02;
                        counter1 = var + k;
                        k += 3;
           }
     
                      if ( counter1 == var | m >= 800 )
           {
            P1OUT ^= 0x02;
                       counter1 = var + k;
                       k -= 3;
            }
                      if ( counter1 == var | m == 1600)
                      {
                      TAR = 0;
                      aux  = 0;
                      counter1 = 3;
                      k=6;
                      }
                  }
       

      TACCR0 += 3;
    }
  • #59
    pablos23
    Poziom 15  
    Co się stanie jeśli TACCR0 +=x umieścimy na początku ISR zaś w trakcie obsługi ISR TACCR0 zrówna się wartością z TAR?
  • Pomocny post
    #60
    Dr_DEAD
    Poziom 28  
    pablos23 napisał:
    Co się stanie jeśli TACCR0 +=x umieścimy na początku ISR zaś w trakcie obsługi ISR TACCR0 zrówna się wartością z TAR?

    Zostanie ustawiona flaga od przerwania, ale z powodu że przerwania są wyłączone (bo są wyłączane automatycznie przy wejściu w przerwanie) program normalnie zakończy obsługę bierzącego przerwania, wróci do pętli głównej, wykona jedną instrukcję i znowu wejdzię w obsługę przerwania bo ma przecież wystawioną falgę (która ustawiła sie w poprzednim przerwaniu). Sytuacja się powtórzy jeszcze raz albo kilka razy i w końcy przerwania zaczną być gubione i do następnego przerwania licznik będzie musił się przekręcić przez wartość maksymalną czyli 0xFFFF.