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.

[atmega8][C]Pomiar długości trwania impulsu / stanu niskiego

demeus 09 Sie 2008 00:29 6127 3
  • #1 09 Sie 2008 00:29
    demeus
    Poziom 18  

    Witam

    Poniższy program mierzy długość trwania impulsu / stanu niskiego podanego na INT1.

    Pomiar jest wyzwalany przerwaniem, zboczem opadającym, następnie następuje włączenie timera i przestawienie przerwania na zbocze narastające. Gdy ono nastąpi jest wyzwalane kolejne przerwanie, które zeruje zatrzymuje timer. Odczyt timera (rejestr TCNT1) następuje z godnie z dokumentacją przy wyłączonych przerwaniach. Za pomocą rejestru TCCR1B ustawiam preskaler na 1024. I teraz moje obliczenia :)

    Atmega pracuje z wewnętrzym kwarcem 1Mhz
    1Mhz = 1/1000000 = 1us
    czyli 1 takt procesora co 1us
    prescaler jest ustawiony na 1024 czyli licznik jest zwiększany o 1 po 1024 taktach procesora
    1 takt licznika trwa 1us * 1024 = 1024us = 1,024ms
    Żeby otrzymać wynik w ms mnożę wartość licznika przez 1,024.
    Czy moje obliczenia są poprawne?

    Code:
    volatile unsigned char pomiar = 0;
    
    unsigned char sreg;
    float i;
    char czas[8];

    void Inicjalizacja(void)
    {
       LCD_init();                        // Inicjalizacja wyświetlacza
       sei();                            // Włączenie obsługi przewań   
       MCUCR = 0;                        // Zerowanie rejestru MCUCR
       MCUCR |= (1<<ISC11)|(0<<ISC10);      // Wyzwolenie przerwania zboczem opadającym
       GICR |= 1<<INT1;                  // Załączenie przerwania na INT1
       TCCR1A = 0;                      // T/C1 w trybie czasomierza
    }

    SIGNAL (SIG_INTERRUPT1)
    {
       if (pomiar==0)
       {
          TCNT1 = 0;                     // Zerowanie czasomierza T/C1
          TCCR1B |= (1<<CS10)|(1<<CS12);    // Zalaczenie timera1 - preskaler ck/1024
          MCUCR = 0;                     // Zerowanie rejestru MCUCR
          MCUCR |= (1<<ISC11)|(1<<ISC10);   // Przestawienie przerwania na zbocze narastajace
          pomiar = 1;
       }
       else




       {
          TCCR1B &= ~((1<<CS10)|(1<<CS12));   // Wylaczenie timera1
          MCUCR = 0;                     // Zerowanie rejestru MCUCR
          MCUCR |= (1<<ISC11)|(0<<ISC10);   // Przestawienie przerwania na zbocze opadajace
          pomiar = 0;
       }
    }


    int main( void )
    {
       Inicjalizacja();
     
       while(1)
       {   
          LCD_xy(0,0);
          sreg = SREG;                  // Zapis ustawień rejestru SREG
          cli();                        // Wyłączenie obsługi przerwań
          i = TCNT1;                     // Zapis rejestru TCNT1 do zmiennej i
          SREG = sreg;                  // Ustawienie rejestru SREG
          dtostrf(i*1.024,8,2,czas);         // Konwersja float do ascii
          LCD_putstr_P(PSTR("TCNT1: "));
          LCD_putstr(czas);
       }
    }


    Oraz jeszcze jedna wątpliwość, czemu przed każdą zmianą rejestru MCUCR muszę go zerować:
    Code:
    MCUCR = 0;                     // Zerowanie rejestru MCUCR
    
          MCUCR |= (1<<ISC11)|(0<<ISC10);   // Przestawienie przerwania na zbocze opadajace

    Jeśli tego nie zrobię program/procesor nie reaguje na inne ustawienie tego rejestru.

    z góry dziękuję za odpowiedzi i konstruktywną krytykę ;-)

    --
    pozdrawiam
    demeus

    0 3
  • #2 09 Sie 2008 01:30
    *Piotrek*
    Poziom 15  

    Witaj
    Twoje obliczenia wyglądają na poprawne jednak wydaje mi się, że to cli() jest w złym miejscu. Z ustawień timera widze, że mierzysz "powolne" sygnały. Zatem twój program może nie zdążyć złapać przerwania od INT lub złapie tylko zbocze opadające, ale narastającego już nie, bo zostanie wyłączone globalne przerwanie.
    Poniżej przedstawiam mój kod który mierzy czas trwania stanu wysokiego i niskiego.
    Zmienna a jest zwiększana w przerwaniu INT1.

    Code:

    void pwm(void)
    {
       //pomiar czasów na INT1
       a = 0;
       TCNT1 = 0;//czyszczenie licznika timera1
       int1_init(RISING);//wykrywanie narastającego zbocza na INT1
       int1_on_off(ON);//włączenie przerwania od INT1
       do
       {
          switch (a)
          {
             case 1:
                         timer1_on_off(ON1);
                         int1_init(FALLING);
                         ++a;
                         break;
             case 3:
                         timer1_on_off(OFF);
                         impuls_hi_int1 = TCNT1;
                         TCNT1 = 0;
                         timer1_on_off(ON1);
                         int1_init(RISING);
                         ++a;
                         break;
             case 5:
                         timer1_on_off(OFF);
                         impuls_low_int1 = TCNT1;
                         ++a;
                         break;
             default:
                          __asm("nop");
                         break;
          }   
       }while (a < 6);
       //ustawienie pinu PD3 w Hi-Z
       int1_on_off(OFF);//wylaczenie przerwania od INT1

    Jeśli będziesz potrzebował jakiś objaśnień to pisz.
    Pozdrawiam
    Piotrek

    0
  • #3 10 Sie 2008 11:06
    Tomek-85
    Poziom 14  

    Cytat:

    Żeby otrzymać wynik w ms mnożę wartość licznika przez 1,024.


    Żeby otrzymać wynik w ms dzielisz wartość licznika przez 1000

    0
  • #4 10 Sie 2008 20:58
    demeus
    Poziom 18  

    *Piotrek* napisał:
    Witaj
    Twoje obliczenia wyglądają na poprawne jednak wydaje mi się, że to cli() jest w złym miejscu. Z ustawień timera widze, że mierzysz "powolne" sygnały. Zatem twój program może nie zdążyć złapać przerwania od INT lub złapie tylko zbocze opadające, ale narastającego już nie, bo zostanie wyłączone globalne przerwanie.


    cli() jest w dobrym miejscu jest to wzorcowy przykład wzięty z noty katalogowej do Atmegi. Ustawienia timera są narazie przykładowe dla samego faktu uruchomienia pomiaru. I póki co nie spotkałem się z błedem wynikającym z faktu by żądanie przerwania mogło wystąpić w momencie odczytu rejestru.

    Czujnik ten ma mierzyć prędkość wiatru. Na pionowej osi z łopatkami będzie zamontowana tarczka z wąską szczeliną i czujnik będzie mierzył czas trwania szczeliny co będzie proporcjonalne do prędkości wiatru.


    --
    pozdrawiam
    demeus

    Dodano po 5 [minuty]:

    Tomek-85 napisał:
    Cytat:

    Żeby otrzymać wynik w ms mnożę wartość licznika przez 1,024.


    Żeby otrzymać wynik w ms dzielisz wartość licznika przez 1000


    Jednak ja uważam że moje pomiary są właściwe, można to policzyć od drugiej strony.
    1Mhz = 1000000Hz czyli częstotliwość taktowania procka
    1024 to prescaler czyli co 1024 takty procesora licznik zlicza jeden takt
    1000000Hz/1024 = 976,5625Hz czyli to jest częstotliwość licznika w Hz
    1Hz = 1/1s
    1/976,5625 = 0,001024s = 1,024ms czyli długość trwania jednego taktu licznika.

    Więc wynik licznika mnożę przez 1,024s i otrzymuję czas trwania impulsu w ms.

    --
    pozdrawiam
    demeus

    0