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.

Atmega128[C] Program do Miernik Częstotliwości

adamcio84 25 Cze 2010 10:35 2935 16
  • #1 25 Cze 2010 10:35
    adamcio84
    Poziom 8  

    Witam
    Propramuje w WinAvr. Chciałbym mierzyć częstotliwość impulsów podawanych na nóżke T1 mikroprocesora a następnie wynik pomiau wyśwwietlać na LCD. W tym celu napisalem następujący program

    KOD:

    Code:
    #include <avr/io.h>
    
    #include <avr/interrupt.h>
    #include "lcd.h"
    #define F_CPU 1000000UL //czestotliwosc pracy procesora

    int main(void)
    {   //----------Ustawienie Rejestrów Liczników T0 T1---------


     TCCR0= _BV(CS00)|_BV(CS02);      // preskaler clk/1024
     TCNT0 = 0x03;                     // wartość początkowa licznika T0
     TIMSK|=_BV(0);                    //odblokowanie makski przerwania overflow T0
     TCCR1B=_BV(CS12)|_BV(CS11)|_BV(CS10);//wybór liczaania zewnętrznego źródła zegara z pinu T1
     TCNT1H=0x0;                           //wyzerowanie licznikaa T1
     TCNT1H=0x0;
     lcd_init(LCD_DISP_ON);
     unsigned int obroty;
    char buffer [36];
       obroty=TCNT1;
           itoa( obroty, buffer, 10);
           lcd_puts("obroty");                  //wypisz na Lcd
           lcd_putc(buffer);
     sei();                                // włącz obsługę przerwań

    while(1)
        {}
    }
    //--------------Funkcja 1--obsługa przerwania licznika T0--------------------

    SIGNAL (SIG_OVERFLOW0)
    {TCCR0= 0 ;                           //zatrzymaj licznnik T0 na czas obsługi przerwania
     TCCR1B=0;                              //zatrzymaj licznnik T1 na czas obsługi przerwania

    static int licznik;
     licznik++;
        if(licznik==31)     //znaczy że upłynęła 1s
         {     
                         
           
           licznik=0;               
           TCNT1H=0;
           TCNT1L=0;
              }     
    TCNT0 = 0x03;            //wart. pocz. 3 licznka T0 aby wyszła dokładnie.1s                                 




    TCCR0= _BV(CS00)|_BV(CS02);   //ponownie załącz liczniki T0 i T1
    TCCR1B=_BV(CS12)|_BV(CS11)|_BV(CS10); 
    }

    ]
    Niestety program nie dziala poniewaz na LCD wyświetla napis obroty ale wartość pbrotów się nie zmienia.
    Jeżeli częsć odpowiedzialną za wyświetlanie wrzucam do pętli while to LCD wyświetla śmieci
    Code:
    while(1) 
    
        {}
    }
    //--------------Funkcja 1--obsługa przerwania licznika T0--------------------

    SIGNAL (SIG_OVERFLOW0)
    {TCCR0= 0 ;                           //zatrzymaj licznnik T0 na czas obsługi przerwania
     TCCR1B=0;                              //zatrzymaj licznnik T1 na czas obsługi przerwania

    static int licznik;
     licznik++;
        if(licznik==31)     //znaczy że upłynęła 1s
         {     
            unsigned int obroty;
    char buffer [36];
       obroty=TCNT1;
           itoa( obroty, buffer, 10);
           lcd_puts("obroty");                  //wypisz na Lcd
           lcd_putc(buffer);             
           
           licznik=0;               
           TCNT1H=0;
           TCNT1L=0;
              }     
    TCNT0 = 0x03;            //wart. pocz. 3 licznka T0 aby wyszła dokładnie.1s                                 
    TCCR0= _BV(CS00)|_BV(CS02);   //ponownie załącz liczniki T0 i T1
    TCCR1B=_BV(CS12)|_BV(CS11)|_BV(CS10); 
    }

    Proszę o podpowiedź jak można to rozwiązać, chciałbym to zrealizować jak najprostszym kodem

    0 16
  • #2 25 Cze 2010 10:54
    dejmos
    Poziom 23  

    Wrzuć wyświetlanie do pętli while, daj jakieś opóźnienie bo może wświetlacz nie nadążać i zadbaj o to aby zawsze wyło 16 znaków do wyświetlania bo w przeciwnym wypadku wynik będzie Ci pływał po wyświetlaczu. Po każdym wyświetleniu i opóźnieniu możesz też wyczyścić LCD przed ponownym wyświetleniem. Możesz również włożyć wyświetlanie do przerwania żeby LCD odświeżał wartość co 1 s.

    0
  • #3 25 Cze 2010 11:38
    adamcio84
    Poziom 8  

    Poprawilem program w nstępujący sposób ale nadal nie dziala zamiast częstotliwości wświtla "x/". jeżeli dodałem czyszczenie kursora wtedy nic nie wyświetla.
    Kod:

    Code:
    while(1) 
    
        {
       lcd_gotoxy(7,0);
       lcd_putc(buffer);
       
       }

    0
  • #4 25 Cze 2010 13:58
    GienekS
    Poziom 32  

    A funkcja

    Code:
    lcd_putc(buffer); 
    nie wyświetla czasem tylko jednego znaku ?

    0
  • #5 27 Cze 2010 14:19
    dejmos
    Poziom 23  

    Może to Ci coś pomoże. To jest część programu sterującego obrotami silnika elektrycznego. Na początku masz funkcję opóźniającą, obsługę przerwań, później inicjacje wyświetlacza, wyświetlanie znaku i tekstu na wyświetlaczu, funkcję menu gdzie następuje inicjacja wyświetlacza, oraz główny program. W tym programie nie trzeba używać biblioteki do obsługi LCD bo wszystko znajduje się na miejscu :-)


    Code:

    void czekaj (unsigned long pt)         // funkcja generująca opóźnienie
    {
       #define tau 10.38;
       unsigned long gg;
       gg=pt*tau;
       unsigned char pt1;
       for(;gg>0;gg--)
       {
          for(pt1=255;pt1!=0;pt1--);
       }
    }
    SIGNAL (SIG_OVERFLOW0)               //funkcja obsługująca przerwanie od timera0
    {
       TCNT0=11;                     //wpisanie do licznika timera0 wartosci poczatkowej
       stala0++;                     //w clu sktócenia cyklu zliczania(powinno byc 10 dla rezonatora 8MHz
       if(stala0>249)                  //ale ze względu na to że rezonator ma 8.000400MHz wpisane jest 9 w celach kompensacji)
       {                           //timer0 zlicza impulsy zegara podzielone przez 4 czyli w ciągu sekundy było by 2000000 impulsów(zakładając że do TCMC0 wpisujemy za każdym razem 5) (pojemność timera0 i tak wynosi tylko 255)
          stala0=0;                  //dzięki preskalerowi = 2 tych impulsów będzie 1000000 czyli 16 * 250 * 250.
          stala1++;
          if(stala1>15)
          {
             stala1=0;
             autoo=autoobroty*czestotliwosc;
             autoobroty=0;
          }
       }
       TIFR=1<<TOV0;      
    }



    SIGNAL(SIG_INTERRUPT0)
    {
       autoobroty++;
    }

    void piszilcd (unsigned char instr)      
    {
       cbi(PORTA, lcd_rs);               
       sbi(PORTA, lcd_e);               
       PORTA=(PORTA&0x0f)|(instr&0xf0);   
       asm("nop");                     
       asm("nop");
       asm("nop");
       cbi(PORTA, lcd_e);               
       czekaj(0.5L);                  
       sbi(PORTA, lcd_e);               
       PORTA=(PORTA&0x0f)|((instr&0x0f)<<4);   
       asm("nop");
       asm("nop");                  
       asm("nop");
       cbi(PORTA, lcd_e);            
       czekaj(0.5L);                  
    }

    void piszdlcd (char dana)            
    {
       sbi(PORTA, lcd_rs);
       sbi(PORTA, lcd_e);
       PORTA=(PORTA&0x0f)|(dana&0xf0);
       asm("nop");
       asm("nop");
       asm("nop");
       cbi(PORTA, lcd_e);
       czekaj(0.5L);
       sbi(PORTA, lcd_e);
       PORTA=(PORTA&0x0f)|((dana&0x0f)<<4);
       asm("nop");
       asm("nop");
       asm("nop");
       cbi(PORTA, lcd_e);
       czekaj(0.5L);
    }


    void czysclcd (void)               //funkcja czuszcząca LCD
    {   
       piszilcd(0x01);                  //swysłanie instrukcji 0x01 do lcd
       czekaj(1.64);                  //odczekanie opóźnie na wyczyszczenie wyswietlacza
       kolumna=0;                     //ustawienie kursora w pozycji 0
    }


    void piszznak (char znak)            //funkcja pisząca znak na LCD
    {
       unsigned char p;
       if(kolumna<8)
       {
          p=kolumna;                  //pierwsza połówka wyswietlacza
       }
       else
       {
          p=kolumna+56;               //przesuniecie dla drugiej połówki wyswietlacza
       }
       piszilcd(p|0x80);
       kolumna=kolumna!=15?++kolumna:0;   //ustaw nastepną kolumne
       piszdlcd(znak);                  //wyświetl znak na LCD
    }

    void pisztekst(char *tekst)            //wyswietla tekst na LCD wskazywaney przez *tekst
    {
       char nr=0;
       char zn;
       while(1)
       {   
          zn=PRG_RDB(&tekst[nr++]);      //pobranie znaku z pamieci programu
          if(zn!=0)                  //sprawdzenie czy nie ma końca tekstu
          {
             if(zn==CR)               //czy wystapił znak nowej lini
             {
                kolumna=0;            //tak -> ustaw kursor na początek wiersza
             }
             else
             {
                piszznak(zn);         //nie -> pisz nastepny znak
             }
          }
          else
          {
             break;                  //przerwij petlę jeżeli koniec tekstu
          }
       }
    }


    void nalcd(unsigned char z)         //umieszczanie danej na wyswietlaczu
    {
       piszznak((z&0x0f)+0x30);      //wyswietlanie na lcd znaku po konwersji z HEX na ASCII
       
    }


    void wyswietlpredkosc(long x)
    {
       char *obroty[1]={   
                         PSTR(" obr/min ")
                   
                   };
       piszznak(' ');
       nalcd((x/100000)%10);
       nalcd((x/10000)%10);
       nalcd((x/1000)%10);
       nalcd((x/100)%10);
       nalcd((x/10)%10);
       nalcd(x%10);
       pisztekst(obroty[0]);
       czekaj(2);
    }

    void menu()
    {                                   //inicjacja wyświetlacza
       DDRC=0x00;             
       PORTC=0xff;
       unsigned char i;
       unsigned char q;         
       czekaj(20);               
       for(i=0;i<3;i++)
       {
          sbi(PORTA,lcd_e);
          PORTA=(PORTA&0x0f)|0x30;
          asm("nop");
          asm("nop");
          asm("nop");
          cbi(PORTA,lcd_e);
          czekaj(2);
       }
       sbi(PORTA, lcd_e);
       PORTA=(PORTA&0x0f)|0x20;      
       asm("nop");
       asm("nop");
       asm("nop");
       cbi(PORTA,lcd_e);
       czekaj(0.5L);
       piszilcd(0x28);               
       piszilcd(0x0c);               
       piszilcd(0x01);               
       czekaj(1.64);

    // funkcja obsługująca menu

    }

    int main(void)               
    {
    // inicjacja procesora i portów

    menu();    //wywołanie funkcji menu

    sei();    // odblokowanie przerwań


    while(1)    // pętla nieskończona
    {

    //program główny
    wyswietlpredkosc(x); // wyświetlanie prędkości
    //
    }
    }

    0
  • #6 01 Lip 2010 10:17
    adamcio84
    Poziom 8  

    Witam
    Przerobilem program w nastepujacy sposob. Licznik T0 odmierza czas 1s a w tym samym czasie licznik T1 zlicza impulsy. W momencie odmierzenia 1s zostaje wyswietlona wartość licznika T1 na wyswietlaczu LCD. Nie wiem tylko czemu wartość nie jest wyświetlana. Moze Będziecie wiedzieli dlaczego nie działa bo mi wydaje się ze jest to dobrze. Prosze o pomoc. Kod programu wyglada w następujacy sposób
    KOD:

    Code:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "lcd.h"
    #include <util/delay.h>
    #include <stdlib.h>
    #define F_CPU 1000000UL //czestotliwosc pracy procesora



    volatile uint8_t T0;
    unsigned int T1;
    volatile uint8_t licznik;
    char bufor1[10];

    //Przerwanie licznika T0
    SIGNAL (SIG_OVERFLOW0)
    {
     TCNT0=0;                               
     
     licznik++;
    }



    //Funkcja Glowna
    int main (void)
    {

    lcd_init(LCD_DISP_ON);
    TIMSK|=_BV(0);
    TCNT1=(1<<CS12)|(1<<CS11)|(1<<CS10);  //T1 zlicza impulsy zewnetrzne
    TCNT0=_BV(CS02)|_BV(CS01)|_BV(CS00);  //T0 dziala na wew. preskalerze 1024
    lcd_puts("Hz");
    T1=TCNT1;   
    itoa(T1,bufor1,10);                    //zmiana inta na string

    sei();
    while (1)
    {
     if(licznik==4)             //gdy dojdzie do 4 przerwan minie 1s 
         {     
           lcd_putc(bufor1);    //nastepnie zostanie wyswietlona wartosc licznika T1
           licznik=0;           //wyzerowanie licznika przerwwań
           TCNT1=0;             //wyzerowanie liczniczka T1
          }
    }
     
    }

    0
  • #7 05 Lip 2010 19:21
    Andrzej__S
    Poziom 28  

    Code:

    //Przerwanie licznika T0
    SIGNAL (SIG_OVERFLOW0)
    {
     TCNT0=0;    // niepotrzebne; po przepełnieniu licznik sam się zeruje
     
     licznik++;
    }


    Code:

    TCNT1=(1<<CS12)|(1<<CS11)|(1<<CS10);  //T1 zlicza impulsy zewnetrzne
    TCNT0=_BV(CS02)|_BV(CS01)|_BV(CS00);  //T0 dziala na wew. preskalerze 1024


    Po pierwsze: chyba chodziło o rejestry TCCR0 i TCCR1B.
    Po drugie: staraj się być konsekwentny. Używaj albo notacji (1<<CS12), albo _BV(CS12).
    Po trzecie: skąd przypuszczenie, że "T0 działa na wew. preskalerze 1024". Przecież to, co napisałeś ustawia bity CS02:0 na wartość "0b111".

    Code:

    T1=TCNT1;   
    itoa(T1,bufor1,10);                    //zmiana inta na string


    Jako że T1 jest "unsigned" proponuję utoa(T1, bufor1, 10). Ponadto powyższy fragment powinien znajdować się wewnątrz bloku warunkowego if(licznik==4). Inaczej konwersja zostanie wykonana tylko raz, przed wejściem do pętli i wyświetlacz siłą rzeczy musi wyświetlać zawsze to samo, bo "bufor1" nie jest aktualizowany nową wartością.

    Mogę jeszcze dodać, że zaproponowany sposób pomiaru będzie obarczony pewnym błędem. Po pierwsze timer 0 nie będzie odliczał 1s tylko 4*(256*1024)/F_CPU, czyli dokładnie 1,048576s. Po drugie w bloku warunkowym (czytaj komentarze):
    Code:

     if(licznik==4)             //gdy dojdzie do 4 przerwan minie 1,048576s 
         {     
           lcd_putc(bufor1);     // te instrukcje
           licznik=0;           //  zajmują trochę czasu
           TCNT1=0;           // w tym miejscu WYZERUJESZ impulsy, które mogą
                              // być zliczone podczas wykonywania poprzednich instrukcji
          }

    Nie wiem, jakiej dokładności oczekujesz, ale myślę, że lepszym rozwiązaniem byłoby np. coś takiego:
    Code:

      if(licznik==4)
        {     
          T1=TCNT1;
          utoa( (T1-prev_T1), bufor1, 10 );  // konwertujesz różnicę obecnego i
                                         // poprzedniego stanu licznika
          lcd_putc(bufor1);  // chyba raczej powinno być coś w stylu "lcd_putstring"
          licznik=0;
          prev_T1 = T1;
        }

    I nie przejmuj się przepełnieniem TCNT1. Przy zmiennych "unsigned" różnica będzie prawidłowa, nawet jeśli dojdzie do odejmowania wartości większej od mniejszej. Np. dla zmiennych "unsigned" 8 bitowych:
    Cytat:
    3 - 255 = 4

    Oczywiście flaga przeniesienia C w SREG zostanie ustawiona, ale można ją zwyczajnie zignorować.

    0
  • #8 05 Lip 2010 20:24
    siarczanmiedzi
    Poziom 1  

    Code:

      if(licznik==4)
        {     
          T1=TCNT1;
          utoa( (T1-prev_T1), bufor1, 10 );  // konwertujesz różnicę obecnego i
                                         // poprzedniego stanu licznika
          lcd_putc(bufor1);  // chyba raczej powinno być coś w stylu "lcd_putstring"
          licznik=0;
          prev_T1 = T1;
        }


    Czy przy stabilnej częstotliwości zawsze tej samej wartości TCNT1 nie spowoduje to wyświetlania zerowego wyniku ?

    0
  • #9 06 Lip 2010 09:09
    Andrzej__S
    Poziom 28  

    Dlaczego wartość TCNT1 miałaby być zawsze taka sama przy stabilnej częstotliwości? Zwróć uwagę, że TCNT1 nie jest zerowany. Zapamiętujemy tylko jego wartość w zmiennej "prev_T1", on liczy dalej i przy następnym wykonaniu bloku warunkowego "if(licznik==4)" od nowej wartości odejmujemy poprzednią.

    0
  • #10 06 Lip 2010 12:42
    adamcio84
    Poziom 8  

    Witam
    Po trzecie: skąd przypuszczenie, że "T0 działa na wew. preskalerze 1024". Przecież to, co napisałeś ustawia bity CS02:0 na wartość "0b111". Ten zapis wziołem z dokumentacji Atmega128 w którm pisze że ustawienie tych bitów powuduje dzialanie licznika T0 na preskalerze 1024. Moge sie myslic poniewaz jestem początukący i te zagadnienia nie sa mi dobrze znane. Przerobilem program program według wskazówek Andrzeja_S i wygląda następująco

    Code:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "lcd.h"
    #include <util/delay.h>
    #include <stdlib.h>
    #define F_CPU 1000000UL //czestotliwosc pracy procesora



    volatile uint8_t T0;
    unsigned int T1;
    volatile uint8_t licznik;
    char bufor1[10];

    //Przerwanie licznika T0
    SIGNAL (SIG_OVERFLOW0)
    {
     TCCR0=0;                               
     
     licznik++;
    }



    //Funkcja Glowna
    int main (void)
    {

    lcd_init(LCD_DISP_ON);
    TIMSK|=_BV(0);
    TCCR1B=_BV(CS12)|_BV(CS11)|_BV(CS10);  //T1 zlicza impulsy zewnetrzne
    TCCR0=_BV(CS02)|_BV(CS01)|_BV(CS00);  //T0 dziala na wew. preskalerze 1024
    lcd_puts("Hz");
       
       
    sei();
    while (1)
    {
     if(licznik==4)
        {     
          T1=TCNT1;
          utoa( T1, bufor1, 10 );  // konwertujesz różnicę obecnego i
                                         // poprzedniego stanu licznika
          lcd_putc(bufor1);  // chyba raczej powinno być coś w stylu "lcd_putstring"
          licznik=0;
          TCNT1=0;
          }
    }
     
    }

    Podpinam generator pod T1 ustawiam czestotliwosc 100Hz i progream dalej nic nie wyswietla (wyswietla jedynie "HZ"). Moze bedziecie wiedieli dlaczego nie dziala.
    Cytat:

    0
  • #11 06 Lip 2010 13:20
    Andrzej__S
    Poziom 28  

    Code:

    TCCR0=_BV(CS02)|_BV(CS01)|_BV(CS00);  //T0 dziala na zewnętrznym źródle

    Nie przeczytałeś uważnie moich uwag. Taki zapis ustawia bity CS02=1, CS01=1, CS00=1, czyli zewnętrzne źródło impulsów. Żeby ustawić wewnętrzny zegar z preskalerem 1024 powinieneś użyć:
    Code:

    TCCR0 = _BV(CS02) | _BV(CS00);  //T0 dziala na wew. preskalerze 1024

    czyli CS02=1, CS01=0, CS00=1.
    Poza tym polecałbym raczej stosowanie:
    Code:

    ISR(TIMER0_OVF_vect)

    zamiast:
    Code:

    SIGNAL (SIG_OVERFLOW0)

    Ten drugi zapis jest "Deprecated". Cytat z avr-libc-user-manual:
    Cytat:

    Do not use SIGNAL() in new code. Use ISR() instead.

    Chyba, że używasz jakiejś starej wersji WinAvr.

    0
  • #12 06 Lip 2010 14:52
    adamcio84
    Poziom 8  

    Poprawilem program zgodnie z wskazowkami niestety nic nie wyswietla (poza "Hz"). Wyglada nastepujaco:

    Code:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "lcd.h"
    #include <util/delay.h>
    #include <stdlib.h>
    #define F_CPU 1000000UL //czestotliwosc pracy procesora



    volatile uint8_t T0;
    unsigned int T1;
    volatile uint8_t licznik;
    char bufor1[10];

    //Przerwanie licznika T0
    ISR(TIMER0_OVF_vect)
    {
     TCCR0=0;                               
     
     licznik++;
    }



    //Funkcja Glowna
    int main (void)
    {

    lcd_init(LCD_DISP_ON);
    TIMSK|=_BV(0);
    TCCR1B=_BV(CS12)|_BV(CS11)|_BV(CS10);  //T1 zlicza impulsy zewnetrzne
    TCCR0=_BV(CS02)|_BV(CS00);  //T0 dziala na wew. preskalerze 1024
    lcd_puts("Hz");
       
       
    sei();
    while (1)
    {
     if(licznik==4)
        {     
          T1=TCNT1;
          utoa( T1, bufor1, 10 );  // konwertujesz różnicę obecnego i
                                         // poprzedniego stanu licznika
          lcd_putc(bufor1);  // chyba raczej powinno być coś w stylu "lcd_putstring"
          licznik=0;
          TCNT1=0;
          }
    }
     
    }

    Byc moze problem lezy po stronie generatora ale jesli podlaczam go pod diode to dziala(mruga).

    0
  • #13 06 Lip 2010 16:46
    Andrzej__S
    Poziom 28  

    Code:

    ISR(TIMER0_OVF_vect)
    {
     TCCR0=0; // w tym miejscu wyłączyłeś sobie taktowanie timera 0
     
     licznik++;
    }


    Przedtem tego nie zauważyłem (początkowo miałeś w tym miejscu "TCNT0=0;") . Wyrzuć to "TCCR0=0;" z obsługi przerwania, bo podczas obsługi pierwszego przerwania TIMER0 OVEFLOW wyłączasz sobie taktowanie timera, inaczej mówiąc - zatrzymujesz go - i następne przerwanie już się nie pojawi. W zupełności wystarczy:
    Code:

    ISR(TIMER0_OVF_vect)
    {
     licznik++;
    }

    0
  • #14 07 Lip 2010 10:01
    adamcio84
    Poziom 8  

    Niby dziala i niedziała ponieważ przy 10000HZ na LCD wyświetla 0666. Czy tak duza różnica może być z tego

    Code:

    ISR(TIMER0_OVF_vect)
    {
                                   
     
     licznik++;
    }


    a potem

    Code:

    if(licznik==4)
        {     
          T1=TCNT1;
          utoa( T1, bufor1, 10 );  // konwertujesz różnicę obecnego i
          lcd_gotoxy(3,0); 
         lcd_puts(bufor1);// poprzedniego stanu licznika puts                                                                                                                                                           
          TCNT1=0;
          }

    dodam że waartości 10hz juz nie wyswietla

    0
  • Pomocny post
    #15 07 Lip 2010 12:42
    Andrzej__S
    Poziom 28  

    adamcio84 napisał:

    ...przy 10000HZ na LCD wyświetla 0666...


    No to prawie jak liczba szatana :)

    adamcio84 napisał:

    Code:

    if(licznik==4)
        {     
           T1=TCNT1;
           utoa( T1, bufor1, 10 );
           lcd_gotoxy(3,0);
           lcd_puts(bufor1);

          TCNT1=0;
          }



    Widzę, że dodałeś pozycjonowanie kursora, żeby wynik za każdym razem był wyświetlany w tym samym miejscu wyświetlacza. Trzeba by jeszcze pomyśleć o kasowaniu poprzednio wyświetlanej wartości, bo jeśli pierwszy wynik pomiaru będzie np. czterocyfrowy a drugi dwucyfrowy, to dwie ostatnie cyfry z poprzedniego pomiaru pozostaną na wyświetlaczu.

    Nie wiem tylko DLACZEGO WYRZUCIŁEŚ LINIĘ "licznik=0;. Jeśli go nie wyzerujesz, pomiar będzie dokonywany co ok. 67 sekund!!! Poza tym zastanów się ile impulsów zliczy timer 1 w tym czasie?

    Spróbuj tego:
    Code:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "lcd.h"
    #include <stdlib.h>

    #define F_CPU 1000000UL //czestotliwosc pracy procesora
    #include <util/delay.h>

    uint16_t T1;
    volatile uint8_t licznik;
    char bufor1[10];

    //Przerwanie licznika T0
    ISR(TIMER0_OVF_vect)
    {
       licznik++;
    }


    //Funkcja Glowna
    int main (void)
    {
    uint16_t prev_T1=0;

       lcd_init(LCD_DISP_ON);
       TIMSK|=_BV(TOIE0);
       TCCR1B=_BV(CS12)|_BV(CS11)|_BV(CS10);
       TCCR0=_BV(CS02)|_BV(CS00);
       lcd_puts("Hz");

       sei();

       while (1)
       {
          if(licznik==4)
          {
             T1=TCNT1;
       // konwertujesz różnicę obecnego
       // i poprzedniego stanu licznika
             utoa( (T1-prev_T1), bufor1, 10 );
       // tutaj wstaw funkcję, która "czyści" cały wyświetlacz
       // lub jego fragment w którym jest wyświetlany wynik
       // nie wiem, jak ona u Ciebie się nazywa
             lcd_gotoxy(3, 0);
             lcd_puts(bufor1);
             licznik=0;
             prev_T1 = T1;
          }
       }
    }



    Nic nie zmieniaj, tylko dodaj funkcję czyszczącą wyświetlacz w miejscu, które zaznaczyłem. Daj znać, jaki jest efekt.

    0
  • #16 07 Lip 2010 14:13
    adamcio84
    Poziom 8  

    Program który wrzuciles nie dziala mi dokladnie ale ten ktroy wrzucam dziala idealnie ale wzruć uwage na miejsce

    Code:

    if(licznik==4)
        {     
         
         T1=TCNT1*2;

    mnożę T1 *2 i wtedy wyswietla mi idealnie bo jezeli tego nie zrobie to wyswietla mi wartosc o polowe mniejsza. ale robiac takiego knifa dziala dobrze. Wrzucam kod gotowego programu

    GOTOWY PROGRAM
    Code:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "lcd.h"
    #include <util/delay.h>
    #include <stdlib.h>



    unsigned int T1;

    volatile uint8_t licznik;
    char bufor1[10];

    //Przerwanie licznika T0
    ISR(TIMER0_OVF_vect)
    {
                                   
     
     licznik++;
    }



    //Funkcja Glowna
    int main (void)
    {
    DDRB= 0xff;
    lcd_init(LCD_DISP_ON);
    TIMSK|=_BV(0);
    TCCR1B=_BV(CS12)|_BV(CS11)|_BV(CS10);  //T1 zlicza impulsy zewnetrzne
    TCCR0=_BV(CS02)|_BV(CS00);  //T0 dziala na wew. preskalerze 1024
     
       
       
    sei();
    while (1)
    {
     
     if(licznik==4)
        {     
         
         T1=TCNT1*2;
         utoa( T1, bufor1, 10);  // konwertujesz różnicę obecnego i
          lcd_clrscr();
         lcd_puts("HZ");
         lcd_gotoxy(3,0); 
         lcd_puts(bufor1);// poprzedniego stanu licznika puts 
         _delay_ms(950);
         TCNT1=0;
         }
       
    }
     
    }

    0
  • #17 07 Lip 2010 17:54
    Andrzej__S
    Poziom 28  

    adamcio84 napisał:

    Program który wrzuciles nie dziala mi dokladnie...


    A czy dokładnie zrobiłeś tak jak napisałem?
    Code:

          if(licznik==4)
          {
             licznik=0;
             T1=TCNT1; // WAŻNE
             utoa( (T1-prev_T1), bufor1, 10 ); // WAŻNE
             lcd_clrscr();
             lcd_puts("HZ");
             lcd_gotoxy(3, 0);
             lcd_puts(bufor1);
    //      _delay_ms(950);  // BEZ TEGO
             prev_T1 = T1; // WAŻNE
          }


    Bo ja widzę u Ciebie nadal "TCNT1=0;" w ostatniej linijce bloku warunkowego "if(licznik==4)'. Już wcześniej próbowałem Ci wytłumaczyć, że w przypadku zerowania timera 1 ("TCNT1=0;") - i to w dodatku po funkcjach obsługi wyświetlacza - Twój program nie będzie działał poprawnie. Linie oznaczone jako WAŻNE we fragmencie kodu powyżej są kluczowe dla uzyskania prawidłowego wyniku. Oczywiście musisz wtedy mieć zadeklarowaną zmienną uint16_t prev_T1=0; globalnie lub wewnątrz funkcji "main" (patrz: program z mojego poprzedniego postu).

    No i może jeszcze spróbuj przesunąć instrukcję zerującą zmienną licznik na początek bloku (tak jak w kodzie powyżej), tak na wszelki wypadek, bo nie wiem, jak długo trwa wykonanie tych funkcji do obsługi wyświetlacza.

    Tak jak napisałem wcześniej, ta metoda da wynik z pewnym błędem wynikającym z tego, że czas pomiaru to nie 1 sekunda lecz 1,048576 sekundy. Niby nieduża różnica, ale jak dokładniej policzyć to prawie 5%. Przykładowo dla 100Hz powinno wyświetlić 104 lub 105Hz. Trzeba by było to później przeliczyć przed wyświetleniem.

    Jeśl i już tak koniecznie musisz zerować ten timer, to zrób to natychmiast po "T1=TCNT1;", a nie na końcu bloku, bo podczas obsługi wyświetlacza "gubisz impulsy" i stąd prawdopodobnie nieprawidłowy wynik pomiaru. Można ewentualnie dodać opóźnienie ok. 48ms, żeby skorygować tę różnicę czasu założonego i faktycznego, np.:

    Code:

          if(licznik==4)
          {
             licznik=0;
             T1=TCNT1;
             _delay_ms(48.574);
             TCNT1=0;
             utoa( T1, bufor1, 10 );
             lcd_clrscr();
             lcd_puts("HZ");
             lcd_gotoxy(3, 0);
             lcd_puts(bufor1);
          }


    W przybliżeniu powinno być OK, chociaż i tak uważam, że mój sposób jest dokładniejszy.

    Tak czy inaczej, z tym mnożeniem przez 2 to chyba niezbyt dobry pomysł.

    0
  Szukaj w 5mln produktów