logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Timer i ATMEGA8. Zliczanie obrotów na minutę.

Sand_Man 17 Sie 2010 12:38 3946 22
REKLAMA
  • #1 8406996
    Sand_Man
    Poziom 11  
    Mam następujący problem. Musze napisać program do zliczania obrotów na minutę na stanowisku laboratoryjnym. Ale ugrzęzłem w miejscu gdzie trzeba ustawić timer i napisać funkcje liczącą te impulsy. Sygnał mierzony pochodzi z czujników optycznych i jest to sygnał logiczny.
    Program ma zliczać impulsy i wyświetlać prędkość obrotową na wyświetlaczu 4x20.
    Na razie napisałem coś takiego:
    
    *********************************************************************/
    #define F_CPU 1000000ul
    #include <avr/io.h> 
    #include <util/delay.h> 
    //#include <avr/signal.h>
    #include <avr/interrupt.h>
    #include "HD44780.h" 
    #include "HD44780.c"
    
    /***********************************************************************
    Obsługa LCD 4x20
    ************************************************************************/
    int main(void)						 
    {
    
    int a1=0;
    int a2=0;
    int a3=0;
    int i;
    char buffer1 [8],buffer2 [8],buffer3 [8];
    
    DDRD= 0x20;
    PORTD= 0x20;
    
    DDRC= 0x00;
    PORTC=0xff;
    PORTC=PINC;
    i=PINC;
    
    itoa(a1,buffer1,10);
    itoa(a2,buffer2,10);
    itoa(a3,buffer3,10);
    
    TCCR1B |= ((0<< WGM11)|(0<< WGM10));
    TCCR1B |= ((1 << CS10) | (1 << CS11)); 			//Ustawia timer z preskalerem Fcpu/64
    TCCR1B |= ((0<< WGM13)|(1<<WGM12));
    MCUCR= (1<<ISC00) | (1<<ISC01);
    TCNT1L= 0;
    TCNT1H= 0;
    
    LCD_Initalize();								//Inicjalizacja wyświetlacza
    
    	while (1) 
    	{ 
    	
    
    		LCD_GoTo(3,0); 						// LCD_GoTo(x,y)
    		LCD_WriteText("Tachometr v1.0");	//Wyświetlenie tekstu
    		LCD_GoTo(0,1); 						
    		LCD_WriteText("V1=");
    		LCD_GoTo(3,1);
    		LCD_WriteText(buffer1);				//Wyświetlenie prędkości z czujnika 1
    		LCD_GoTo(17,1); 						
    		LCD_WriteText("rpm");	
    		LCD_GoTo(0,2); 						
    		LCD_WriteText("V2=");
    		LCD_GoTo(3,2);
    		LCD_WriteText(buffer2);				//Wyświetlenie prędkości z czujnika 2
    		LCD_GoTo(17,2); 						
    		LCD_WriteText("rpm");
    		LCD_GoTo(0,3); 						
    		LCD_WriteText("V3=");				
    		LCD_GoTo(3,3);
    		LCD_WriteText(buffer3);				//Wyświetlenie prędkości z czujnika 3
    		LCD_GoTo(17,3); 						
    		LCD_WriteText("rpm");
    													
    /*****************************************************************
    				Funkcja licząca impulsy
    *****************************************************************/
    
    		while(1)
    		{	
    			for(i=0;i>=TCNT1;i++)
    			{
    				a1= TCNT1;
    				TCNT1=0;
    			}
    		}	
    		return(0);
    	}
    
    
    }
    
    


    Proszę o pomoc, bo musze to skończyć na wczoraj w
    nie mam pojęcia jak to zrobić. Przejrzałem google wzdłuż i wszerz i nadal wiem, że nic nie wiem. Może ktoś jest mi w stanie wytłumaczyć to łopatologicznie.
  • REKLAMA
  • #2 8407443
    tadzik85
    Poziom 38  
    łopatologicznie wyjaśnione liczniki Link
  • #3 8410159
    Sand_Man
    Poziom 11  
    To co zamieściłem powstało w oparciu o tą stronę. Więc nadal nic to mi nie daje. Nadal nie wiem jak skonfigurować timer aby zliczał impulsy na sekunde a potem zerował wartość.
    może chociaż ktoś mi powie czy to co napisałem ma jakikolwiek sens.
  • #4 8410203
    tadzik85
    Poziom 38  
    Sensu brak w pętli liczącej,która o dziwo jest nieskończona liczysz coś dziwnego i nawet pojęcia nie mam co.
  • #5 8410249
    Sand_Man
    Poziom 11  
    Potrzebuje zliczać impulsy z czujnika optycznego (zwykły enkoder) impulsy to 0 i 1 logiczne. Potem musze to przeliczyć na wartośc odpowiednią dla 1 minuty i wyświetlić tą wartość na wyświetlaczu. Problem w tym że czyjniki zamontowane są w miejscach gdzie częstoliwość generowania impulsów na czujniku będzie różna. Jest ona uzależniona od średnicy elementów na których naklejone są tarcze enkoderów.
  • REKLAMA
  • #6 8410260
    tadzik85
    Poziom 38  
    Więc musisz zdecydować o czasie zliczania. najlepiej wykorzystać wejście licznika. Teraz pytanie czy konieczne w twoim przypadku jest zliczanie wszystkich enkoderów jednocześnie czy wystarczy je zliczać pojedynczo i poklei wystarczająco szybko o ile do możliwe. Innym licznikiem odmierzasz czas zliczania. Tu istotne jest aby po uruchomieniu licznika natychmiast uruchomić zliczanie a po odliczaniu zliczania natychmiast pobrać wartości zliczone i je wyzerować.
  • #7 8410364
    tmf
    VIP Zasłużony dla elektroda
    Albo wykorzystaj wejścia zegarowe timerów, taktując je z enkodera (skoro opptyczny to nie ma problemu z odbijaniem) i zczytując stan licznika co określony czas (drugi timer) dostaniesz ilość impulsów w jednostce czasu. Można też do tego podejść od drugiej strony - timer taktować znaną częstotliwością i wykorzystać wejście ICP - możesz wtedy mierzyć szerokość impulsów z enkodera - przydatne jeśli enkoder nie daje zbyt dużej ilości umpulsów.
  • REKLAMA
  • #8 8444839
    Sand_Man
    Poziom 11  
    Powiedzcie chociaż czy dobrze konfiguruje timer, aby działał w trybie licznika. Czy czegoś nie pominąłem, a jeśli są błędy to powiedzcie jakie. Jak ustawić rejestry aby licznik dawał sobie rade ze zliczaniem 360*2500 impulsów na minute. Jak na razie program pisany jest dla atmegi 8 ale docelowo będzie dla atmegi 1280.

    Ostatnio zmieniła sie koncepcja liczenia prędkości obrotowej. Na jeden obrót przypadnie teraz 360 impulsów. Będzie to na razie wykorzystane tylko do pomiaru prędkości, a z czasem do pomiaru kąta przesunięcia prędkości wałów względem siebie na wyjściu przekładni.
    Dlatego mam pytanie czy wystarczy liczenie samych impulsów czy lepsze będzie liczenie czasu między nimi?
    Mam też pytanie co do listingu. W którym miejscu umieścić kod liczący prędkość przed czy za kodem sterującym LCD. Jak wpłynie to na działanie programu.
  • REKLAMA
  • #9 8445367
    janbernat
    Poziom 38  
    Czy masz jakąkolwiek koncepcję tego co chcesz osiągnąć?
    Próbowałeś chociaż ten "program" skompilować?
    Może najpierw zapoznaj się z podstawami działania licznika/czasomierza na zwykłych bramkach.
    Co to znaczy-"dobrze skonfigurowany timer"?
    Zależy co chcesz osiągnąć.
    Bity WGM ustawiłeś na tryb "fast pwm".
    Nieskończona pętla w nieskończonej pętli nazywa się "funkcja licząca impulsy"- chociaż co ona liczy to trudno zgadnąć.
    Na wyświetlaczu będzie wyświetlona raz zawartość buforów- a nie znaki ASCI- a potem program wejdzie w pętlę nieskończoną w tzw. "funkcji liczącej impulsy" i tam już zostanie.
  • #10 8445526
    gaskoin
    Poziom 38  
    Sand_Man napisał:

    
    TCCR1B |= ((0<< WGM11)|(0<< WGM10));
    TCCR1B |= ((1 << CS10) | (1 << CS11)); 			//Ustawia timer z preskalerem Fcpu/64
    TCCR1B |= ((0<< WGM13)|(1<<WGM12));
    



    Nie prawda, jest ustawione na tryb CTC (MAX = OCR1A)z preskalerem 64 :P

    spójrz jeszcze raz w ten bezsensowny kod :)

    tadzik85 napisał:
    łopatologicznie wyjaśnione liczniki Link


    Sand_Man napisał:
    To co zamieściłem powstało w oparciu o tą stronę.


    Chyba nie do końca, poza tym ściągnij sobie manual, bo tam to jest jeszcze bardziej łopatologicznie wytłumaczone
  • #11 8445570
    janbernat
    Poziom 38  
    Fakt- co ślepemu po oczach- CTC.
    A z drugiej strony- kto zera wpisuje do rejestrów po resecie. :D
  • #12 8445573
    gaskoin
    Poziom 38  
    ORując z zerem, w zasadzie robi się nic. Równie dobrze wszystkie liczby można mnożyć przez 1 i dodawać do nich 0
  • #13 8445629
    Andrzej__S
    Poziom 28  
    Sand_Man napisał:

    
    ...
    TCCR1B |= ((0<< WGM11)|(0<< WGM10));
    ...
    



    gaskoin napisał:

    ORując z zerem, w zasadzie robi się nic. Równie dobrze wszystkie liczby można mnożyć przez 1 i dodawać do nich 0

    Byłoby gorzej, gdyby faktycznie spróbować coś wpisać do bitów WGM11 i WGM10, które są przecież w TCCR1A, a nie w TCCR1B ;).

    Dodano po 13 [minuty]:

    janbernat napisał:

    A z drugiej strony- kto zera wpisuje do rejestrów po resecie.

    W tym konkretnym przypadku masz rację, jednak nie wszystkie bity w rejestrach mają "initial value" równe 0, jak choćby URSEL, UCSZ1 i UCSZ0 w UCSRC. Dlatego wpisywanie zer do rejestrów po resecie nie zawsze jest bez sensu.
  • #14 8445716
    gaskoin
    Poziom 38  
    Andrzej__S napisał:
    Sand_Man napisał:

    
    ...
    TCCR1B |= ((0<< WGM11)|(0<< WGM10));
    ...
    



    gaskoin napisał:

    ORując z zerem, w zasadzie robi się nic. Równie dobrze wszystkie liczby można mnożyć przez 1 i dodawać do nich 0

    Byłoby gorzej, gdyby faktycznie spróbować coś wpisać do bitów WGM11 i WGM10, które są przecież w TCCR1A, a nie w TCCR1B ;).



    niżej i tak je ustawia (CS11 i CS10) :)
  • #15 8445745
    Andrzej__S
    Poziom 28  
    gaskoin napisał:

    niżej i tak je ustawia (CS11 i CS10) :)

    No fakt, w tym przypadku akurat pasuje :), ale generalnie przez taką pomyłkę łatwo sobie skopsać prescaler.
  • #16 8446072
    Sand_Man
    Poziom 11  
    Ok to jak już sie wszyscy wyżyli na mej głupocie, gapiostwie i niewiedzy. Bo zaczynam dopiero zabawę z uC i nie wszystko rozumiem. To odpowiem na pytania, które padły.

    janbernat:
    Koncepcje mam opracowaną.
    Program sie kompilował i kompiluje z 1 warningiem.
    Co do dobrego skonfigurowania timera to nie wiem, czego tu nie rozumiesz. Pytanie jest jasne. Chodzi mi o ustawienie bitów, rejestrów i co tam jeszcze jest potrzebne, aby timer zliczał impulsy zewnętrzne.
    Ale już wiem, że popełniłem kilka błędów.

    gaskoin:
    Kod może jest i bezsensowny. Nie neguje tego. Bo nie jestem w stanie sam ocenić jego poprawności. Ale forum jest chyba po to żeby uzyskać pomoc w jego poprawie.

    Andrzej_S:
    Z tym TCCR1B mógł być czeski błąd. Już to poprawiłem

    A teraz wracając do programu.
    Czy bylibyście w takim razie w stanie wytłumaczyć mi jak prawidłowo ustawić timer aby użyć go, jako licznika. Zacząłem dopiero zabawę z programowaniem i nie łapie niektórych rzeczy. Jak do tej pory to mrugałem diodami i pisałem coś na LCD. Ale dostałem za zadanie zrobić tachometr i musze z tego wybrnąć. A jak na razie nie widzę światełka w tunelu. Zaraz odeślecie mnie do mnóstwa stron i not katalogowych. Ale uprzedzę was, że sporo z nich juz przeczytałem i nadal nie mogę pojąć zasady działania timera. Znam zasady cyfrówki: liczniki modulo itd. Ale nie umiem sie uporać z timerami w avr-ach.
  • #17 8446156
    janbernat
    Poziom 38  
    Timer- np. Timer1- jako licznik zlicza impulsy zewnętrzne.
    Podane na odpowiednią końcówkę- T1 w wypadku ATmega8.
    Nie potrzebuje żadnego preskalera- bo preskaler dzieli impulsy z zegara- a tu nie ma co dzielić.
    Ustawiamy bity CS10-CS12 na external clock source- falling lub rising.
    Czy ustawiamy końcówkę T1 jako wejście- nie pamietam.
    Można ustawić.
    Ilość zliczonych impulsów odczytujemy po pewnym czasie- wyznaczonym przez jakiś inny timer- np. Timer0.
    Jaki to będzie czas- to się nazywa czas bramkowania- zależy jak ustawimy Timer0.
    Wukorzystując przerwanie od Timer0.
    Od przepełnienia albo CTC- jak wygodniej.
    Kasujemy licznik T1- i liczymy od nowa.
    To jest pierwsza koncepcja- mogą być też inne.
    P.S.
    To jest bardzo ogólnie- można wykorzystać synchroniczny reset timerów, trzeba rozważyć dokładność, trzeba rozwiązać sprawę braku impulsów- bo nic się nie kręci- itp.

    Drugi pomysł- przedstawiony przez tmf:
    Podajemy impulsy na wejście ICP1.
    Timer1 teraz będzie bramką- tak go ustawiamy aby wiedzieć co ile liczy.
    Ustawiamy rejestr OCR na jakąś liczbę i jak liczba impulsów z ICP1 się zrówna z tym rejestrem to Timer1 wygeneruje przerwanie.
    A wiemy z co ile liczył.

    Trzeci pomysł- polling.
    Ustawiamy jakiś timer na szybkie przerwanie i w tym przerwaniu sprawdzamy stan jakiegoś wejścia.
    Ustawiamy flagę i w pętli głównej ją sprawdzamy, kasujemy i zliczamy.
    Ale to w tym przypadku- okres impulsu ok. 66us- kwarc powinien być 16MHz.
    P.S.
    We wszystkich tych metodach są szczegóły.
    A diabeł siedzi w szczegółach.
  • #18 8446293
    gaskoin
    Poziom 38  
    przeczytaj mój post dotyczący jak korzystać z manuala:

    https://www.elektroda.pl/rtvforum/topic1721294-30.html

    przeczytaj go proszę, zajrzyj do manuala i postaraj się sprawdzić jak poustawiać bity.

    Aby użyć timera jako licznika impulsów podawanych np z przycisku czy czegokolwiek innego, należy go podpiąć pod odpowiedni pin (sprawdź jaki) i ustawić timer tak, aby jego źródłem zegarowym było zewnętrzne źródło (chociażby przycisk). Nie możesz dać wtedy preskalera - bo wtedy preskalujesz swoje źródło zegarowe (swój przycisk). Czyli jak je podzielisz przez 8, to co 8 przyciśnięć przycisku licznik naliczy Ci 1.

    Z timerem w sumie nie musisz za dużo grzebać. Jeżeli chcesz jedynie zliczać impulsy, to poprostu ustaw mu zewnętrzne taktowanie z pinu i preskaler na 1. W rejestrze TCNT1 będziesz miał wtedy liczbę dotychczasowych przyciśnięć. TCNT1 jest rejestrem z którego można zarówno czytać, jak i go zapisywać. Także nie trudno Ci będzie go wykorzystać.

    Acha i poczytaj o operacjach bitowych bo



    oznacza to, że jeżeli przy takim zapisie, jak wyżej miałeś tzn

    TCCR1A |= (0 << CS11)


    w rejestrze nie zachodzi absolutnie żadna zmiana!!

    zapamiętaj sobie:

    1) ustawienie bitu

    REJEST |= (1 << NRbitu)


    2) skasowanie bitu
    REJESTR &= ~(1 << NRbitu)



    PS - odsyłamy do not, bo tam jest absolutnie wszystko napisane
  • #19 8446329
    janbernat
    Poziom 38  
    "Czyli jak je podzielisz przez 8, to co 8 przyciśnięć przycisku licznik naliczy Ci 1. "
    gaskoin- dasz sobie uciąć?
  • #21 8446405
    janbernat
    Poziom 38  
    Cytat:
    "gaskoin- dasz sobie uciąć?"
    "nie, zgodnie z notą"

    Nota nie daje uciąć...
    P.S.
    Trzeba by zacząć jakiegoś gotowca.
  • #22 8446458
    gaskoin
    Poziom 38  
    a Tobie się 'cytuj' zablokowało ?:P

    Albo przykleić jakieś kursy - do przerwań takich a srakich, do timerów itd.
  • #23 8446539
    janbernat
    Poziom 38  
    Kursy to są- ale zwykle ich autorzy zakładają że czytelnik wie jak działa zwykły stary licznik na bramkach.
    A tak- to tłumaczą jak taki licznik zrobić na procesorze.
    Szukałem nawet dla Sand_Man-a czegoś takiego.
    Ale z kiepskim rezultatem.
    A skanować mi się nie chce- dużo stron.
REKLAMA