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] - Prosty obrotomierz

merazmus 14 Gru 2012 12:21 1992 2
  • #1 14 Gru 2012 12:21
    merazmus
    Poziom 2  

    Witam,
    Chciałem zbudować bardzo prosty układ, który będzie pozwalał mi odczytywać ilość obrotów tarczy na sekundę. Będą to wielkości rzędu 2-15 obrotów na sekundę. Tarcza przy każdym obrocie generowała będzie impuls. Załóżmy, że na razie będzie ją symulował zwykły przycisk. Chciałem użyć do tego trybu CTC i rejestru porównania TCR2. Kod wygląda następująco:

    Code:
    #include <avr/io.h>
    
    #include <util/delay.h>

    int main(void)
    {
       //ustawienie trybu CTC
       TCCR2 |= (1<<WGM21);
       //preskaler = 1024
       TCCR2 |= (1<<CS22) | (1<<CS21) | (1<<CS20);
       //rejestr porównania
       OCR2 = 255;
       
       LCD_Initalize();
       LCD_Clear();
       
       uint8_t licznik = 0;
       volatile char bufor[20];
       
       PORTD |= (1<<PD7);
       
        while(1)
        {
          if(bit_is_clear(PIND, 7)){
             licznik = TCNT2;
             TCNT2 = 0;
             itoa(licznik, bufor, 10);
             LCD_GoTo(0,1);
             LCD_WriteText(bufor);
          }
       }
    }


    Jeśli taktowanie jest ustawione na 1MHz, preskaler na 1024, a TCR2 na 255, to wychodzi na to, że rejestr TCNT2 "przeleci" od 0 do 255 ponad trzy razy na sekundę. Trochę za szybko. Chciałbym zrobić to za pomocą timera 16-bitowego ale nie do końca mogę się połapać w dokumentacji. Mógłby mi ktoś pomóc?
    Dopiero zaczynam i nie do końca wiem jak się za to zabrać.

    edit:
    Udało mi się zrobić coś takiego:
    Code:
    #include <avr/io.h>
    

    int main(void)
    {
       //ustawienie trybu CTC
       TCCR1A |= (1<<WGM12);
       //preskaler = 1024
       TCCR1B |= (1<<CS12) | (1<<CS10);
       //rejestr porównania
       OCR1BL = 255;
       OCR1BH = 255;
       
       LCD_Initalize();
       LCD_Clear();
       
       uint16_t licznik = 0;
       volatile char bufor[20];
       
       PORTD |= (1<<PD7);
       
        while(1)
        {
          if(bit_is_clear(PIND, 7)){
             licznik = (TCNT1H<<8) | (TCNT1L);
             TCNT1H = 0;
             TCNT1L = 0;
             itoa(licznik, bufor, 10);
             LCD_GoTo(0,1);
             LCD_WriteText(bufor);
          }
       }
    }

    Na razie ma wyświetlać tylko wartość rejestru zliczoną od ostatniego wciśnięcia. Problem w tym, że wyświetla chyba losowe liczby. Nawet częste wciskanie przycisku nie ukazuje żadnej logiki w ukazywanych się liczbach.

    0 2
  • #2 14 Gru 2012 12:44
    maciej_333
    Poziom 33  

    Bardzo złe podejście. Trzeba tu zastosować jeden układ licznikowy, jako Timer do odmierzenia czasu 1s i drugi jako licznik zdarzeń zewnętrznych. Przerwanie od Timera, zajmującego się czasem wzorcowym powinno być zgłaszane co 1s. W przerwaniu należy pobrać i zapamiętać w zmiennej globalnej zliczoną liczbę impulsów. Potem trzeba wyzerować licznik. W przerwaniu ustawiamy też flagę, która wywoła przesłanie danych do LCD w pętli głównej - funkcja main(). Po przesłaniu danych flaga musi być kasowana. Dokładnie tak musi to być zrobione.

    Liczyć impulsy można jakimś 8-bitowym układem czasowo-licznikowym, najlepiej asynchronicznym (o ile pamiętam Timer/Counter 0). Do odmierzania czasu może być dowolny inny układ tego typu.

    Sprawa się komplikuje jeżeli masz drgania styków w takim układzie. Trzeba je odtłumić sprzętowo, albo programowo, poprzez próbkowanie, co jakiś interwał.

    0