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

Miernik prędkości obrotowej

karolczyzycki 19 Lip 2010 22:36 10677 62
  • #1 8309923
    karolczyzycki
    Poziom 20  
    Witam.
    Muszę zbudować miernik prędkości obrotowej.
    Czy to tego (jeśli chodzi o sprzęt) wystarczy Atmega8 + LCD + GP1S51VJ000F (Link)
    Podłączenie tego polegałoby tylko na połączeniu na stałe zasilania na wejście i na wyjściu czujnika zliczać impulsy?
  • Pomocny post
    #2 8310468
    serum
    Poziom 16  
    Jeżeli nie planujesz rozróżniać kierunku obrotów to to właściwie wystarczy, zależy jeszcze w jakich warunkach ma to pracować (problem zanieczyszczeń itp).
  • #3 8310840
    karolczyzycki
    Poziom 20  
    To ma być tylko prototyp, makieta. A co do rozróżniania kierunków to potrzebny byłby jeszcze jeden taki sam czujnik chyba, tak?
  • Pomocny post
    #4 8313917
    Konto nie istnieje
    Poziom 1  
  • #5 8340302
    karolczyzycki
    Poziom 20  
    Znalazłem taki schemat podłączenia mojego czujnika.
    Port Atmegi sprawdzającej stan ma reagować na pojawienie się "0" czy "1"?

    Czy podłączenie jest prawidłowe? Nie mam wartości rezystorów
    Mam dwa schematy:
    Miernik prędkości obrotowej Miernik prędkości obrotowej
  • Pomocny post
    #6 8340674
    kubus_puchatek
    Poziom 18  
    Jeśli to ma być pokazowa makieta to oszczędź sobie mąk. użyj CD4046 i gotowego miliwoltomierza na ICLu.
  • #7 8340708
    karolczyzycki
    Poziom 20  
    Ale to ma być czujnik prędkości obrotowej zrealizowany na czujniku optoelektronicznym...
  • Pomocny post
    #8 8341166
    gaskoin
    Poziom 38  
    to możesz jeszcze spróbować z podczerwienią. Nie wiem czego prędkość badasz więc nic więcej też nie napiszę
  • #9 8341211
    karolczyzycki
    Poziom 20  
    No przecież ten czujnik działa na światło. To ma być obracająca się tarcza z dziurkami, która będzie w szczelinie tego czujnika.
    Miernik prędkości obrotowej
  • Pomocny post
    #10 8341543
    ilmenauer
    Poziom 14  
    Znajdź muzealną myszkę mechaniczną. Tam masz czyjnik prędkości obrotowej enkodera. Dwa takie układy jak pokazałeś na schemacie. Kluczem do sukcesu jest przesunięcie ich względem siebie: kiedy jeden wykrywa przejście jasny-ciemny drugi jest w środku jednego ze stanów, np,. ciemnego.
    Jeśli chodzi o "wystarczy" procesorowe - najmniejszy procek posiadający 2 wolne piny, Atmega8 - sporo na wyrost.
  • #11 8341938
    karolczyzycki
    Poziom 20  
    Ale po co szukać czegoś innego skoro już wszystko mam?
    Przecież ten czujnik ze zdjęcia będzie reagował jeśli coś mu przerwie wiązkę.
    Problem tylko w tym jak to podłączyć, i jak skonfigurować porty w Atmedze.
  • Pomocny post
    #12 8342460
    ilmenauer
    Poziom 14  
    Potrzebujesz 2 takie czujniki. Diodę czujnika zasilasz na stałe a wyjście podłączasz do pinu Atmegi, która jest wejściem (rejestr DDRx.y=0, x-port, y-pin, bez rezystora pull-up PORTx.y=0).
    Teraz musisz wybrać czy chcesz zliczać szybkie impulsy- wtedy Twój program musi w regularnych odstępach czasu sumować impulsy, a jeśli wolne to zliczasz czas jaki upłynie między impulsami.
    Jeśli chodzi o kierunek, stany binarne z czujnika A i czujnika B będą się zmieniały następująco:
    0.0, 0.1, 1.1, 1.0, 0.0 - w jednym kierunku, 0.0, 1.0, 1.1, 0.1, 00 - w przeciwnym.
    Chcąc określić kierunek obrotów musisz wykrywać te sekwencje.
  • #13 8343370
    karolczyzycki
    Poziom 20  
    ilmenauer -> już mi się dużo rozjaśniło. Ale podłączenie tych czujników ma być takie jak na schemacie?
    Próbowałem podłączać ale nie było reakcji.
    Zasilanie czujnika 5V. Atmega reagowała na pojawienie się "0", tylko chyba miałem włączony pullup, nie pamiętam.
    Dla obu schematów konfiguracja ma być identyczna?

    Zbudowałem układzik, w jaki sposób obliczyć prędkość?

    mam taki pomysł:
    zliczać czas między impulsami na wejściu
    (liczenie za pomocą timera) jeśli licznik się przepełni to zwiększ zmienną np. "c"
    i zmienna "c" będzie miała wartość większą lub mniejszą, w zależności od tego ile czasu minęło między impulsami.

    impuls, start licznika
    kolejny impuls, stop licznika
    odczyt wartości ze zmiennej "c"
    ale co później z tym zrobić, w jaki sposób tą wartość wykorzystać, to nie mam pojęcia
  • #14 8386135
    karolczyzycki
    Poziom 20  
    Spróbowałem własnych sił i oczywiście z pomocą forum, stworzyłem taki kod:
    
    int flaga=0; // flaga czy INT0 jest "0" czy "1"
    int a=0; // zmienna zwiększana przy każdym przepełnieniu licznika 0
    
    
    int main(void)
    {
    
    
    		//ustawienia wejścia INT0
    		DDRD&= ~(1<<DDD2); // konfiguracja - WEJSCIE ustawianie zera
    		PORTD|=1<<PIND2; // internal pullup resistor on	
    
    
    		// Konfiguracja zewnętrznego przerwania od INT0
    		GICR=1<<INT0;      //włącz przerwanie  
    		MCUCR=0<<ISC00; //1. ustawiam przerwanie wyzwalane zboczem opadającym --|__
    		MCUCR=1<<ISC01;
    
    
    		//czyszczenie LCD
    		lcd_init();	
    		write_command(0x01);
    
    
    		//włączenie przerwań
    		sei();
    
    
    
    		LCDxy(0,0);
    		write_text("a=");
     
    				while(1)
    
    						{
    
    						}
    
    
    
        return(0);
     
    }
    
    
    
    // kod przerwania, wykonywany w momencie przepełnienia licznika0
    SIGNAL (SIG_OVERFLOW0)
    	{
    		a++;
    
    //wyświetlaj aktualą wartosc zmiennej "a"
    char buffer [8];
    itoa(a,buffer,10);
    LCDxy(3,0);
    write_text(buffer);
    
    
    	} 
    
    
    // kod przerwania, wykonywany w momencie uaktywnienia przerwania INT0
    SIGNAL(SIG_INTERRUPT0)
    {
    
    
    
     // jeśli flaga (stan początkowy "0") jest 0 to wykonaj:
    	if (flaga==0)
    				{ 
    
    
    					MCUCR=1<<ISC00;   //przerwanie wyzwalane zboczem narastającym __|--
    					MCUCR=1<<ISC01;
    
    					TCCR0 = 0b00000011;// prescaler na 1024
    
    					TIMSK |= (1 << TOIE0); // aktywne przerwanie overflow
    
    					TCNT0 = 0;
    
    					flaga=1;
    
    
    
    	// jeśli flaga równa 1, to wykonaj:
    				}else if (flaga==1)	{
    
    
    					TIMSK&=~(1<<TOIE0); // nie zezwalam na przerwanie
    
    					TCCR0 =0; // stop timera
    
    					MCUCR=0<<ISC00; //1. ustawiam przerwanie wyzwalane zboczem opadającym --|__
    					MCUCR=1<<ISC01;
    
    
    					flaga=0;
    					a=0;
    			
    				}
    
    } 
    


    Jak na razie testuję to na guziku, podłączonym do PD2 (INT0) (wewn rez. podciągający) w Atmega8 (Kwarc 16MHz, w ust AVR Studio: 16000000Hz).
    Fuse Bits: Ext. Crystal/Resonator High Freq CKSEL=111 SUT=11

    Problemem jest to że jeśli wcisnę guzik (zwieram do masy) i szybko go puszczę (wewn do 5V), to program rzadko kiedy zaskoczy. Czyli timer startuje zawsze, ale rzadko kiedy się zatrzyma, czyli tak jakby nie reagował na zbocze narastające.

    Moim założeniem było:

    Wciskam guzik i trzymam:
    uaktywniam przerwanie INT0
    włączam licznik
    (jeśli licznik się przepełni wtedy zwiększa się "a")

    jeśli puszczę guzik:
    licznik stop
    wyświetlam "a" i ją zeruje

    i tak w kółko...


    Później zamiast guzika, chcę podłączyć to do czujnika optoelektronicznego, i tak jak w temacie zrobić miernik prędkości obrotowej tarczy.

    Czy ktoś wie dlaczego układ się tak zachowuje?
  • Pomocny post
    #15 8393675
    gaskoin
    Poziom 38  
    a jak przyciśniesz i przytrzymasz guzik dłużej i dopiero potem go puścisz to jest ok?

    zmienne a i flaga powinny być volatile
  • #16 8393781
    karolczyzycki
    Poziom 20  
    no jak wcisnę na dłuugo to też rzadko zadziała...
    nie wiem, może kolejność tego włączania przerwania, zezwalania na przepełnienie itd
  • Pomocny post
    #17 8394195
    asembler
    Poziom 32  
    [quote="emarcus
    Chyba nie tak prosto z dwukierunkowym zliczaniem impulsów (rozpoznaniem kierunku obrotu)!

    e marcus[/quote]

    Warunkiem rozrówniania kierunku obrotów jest tylko to aby dwa czujniki były rozstawione miedzy sobą o kąt rózniacy sie od 180 stopni lub tez w przypadku jednego czujnika otworki lub jezyczki przecinajace czujnik byly rozmieszczone na tarczy z róznym kątem od 180 stopni
    Stosowanie dwoch czujników rozwiazuje problem wywazenia elementu wirującego.
  • Pomocny post
    #18 8394591
    Andrzej__S
    Poziom 28  
    karolczyzycki napisał:

    Jak na razie testuję to na guziku, podłączonym do PD2 (INT0)...

    To może nie być miarodajne, ze względu na drgania styków, chyba że wprowadziłeś jakiś sprzętowy debouncing.

    Jeśli chodzi o kod, nie sprawdzałem, czy cała idea jest prawidłowa, ale zauważyłem:
    
    ...
        MCUCR=1<<ISC00;   //przerwanie wyzwalane zboczem narastającym __|--
        MCUCR=1<<ISC01;
    ...
    

    W drugiej linijce zerujesz bit ISC00, który w poprzedniej linijce ustawiłeś na 1, czyli tak faktycznie to ustawiasz zbocze opadające, a nie narastające. Spróbuj:
    
    ...
        MCUCR= (1<<ISC00) | (1<<ISC01); //przerwanie wyzwalane zboczem narastającym __|--
    ...
    


    Nie wiem, czy to jedyny błąd.
  • Pomocny post
    #19 8396611
    Konto nie istnieje
    Poziom 1  
  • #20 8398276
    karolczyzycki
    Poziom 20  
    Działa świetnie!

    Zmieniłem typ zmiennej z int na volatile, oraz wpisałem:
    MCUCR= (1<<ISC00) | (1<<ISC01); //przerwanie wyzwalane zboczem narastającym __|-- 

    zamiast
        MCUCR=1<<ISC00;   //przerwanie wyzwalane zboczem narastającym __|--
        MCUCR=1<<ISC01; 

    Nie wiem które pomogło, ale jest ok.

    Jedna rzecz jeszcze nie daje mi spokoju. Jeśli timer się przepełni, zmienna a, jest zwiększana, jest to dla mnie trochę za wolno. Prescaler jest na 1. Więc pozostaje wpisać wartosćdo TCNT0, żeby szybciej się przepełniał.

    Wpisuję np. TCNT0=200; ale to nic nie daje, zmienna nadaj zwiększa się za wolno...
    Czy może wstawiłem tą linijkę w złym miejscu?
    int main(void)
    {
    		//ustawienia wejścia INT0
    		DDRD&= ~(1<<DDD2); // konfiguracja - WEJSCIE ustawianie zera
    		PORTD|=1<<PIND2; // internal pullup resistor on	
    
    
    		// Konfiguracja zewnętrznego przerwania od INT0
    		GICR=1<<INT0;      //włącz przerwanie  
    		MCUCR=0<<ISC00; //1. ustawiam przerwanie wyzwalane zboczem opadającym --|__
    		MCUCR=1<<ISC01;
    
    
    		//czyszczenie LCD
    		lcd_init();	
    		write_command(0x01);
    
    		//włączenie przerwań
    		sei();
    
    			while(1)
    
    						{
    	}
    
        return(0);
     
    }
    
    
    
    // kod przerwania, wykonywany w momencie przepełnienia licznika0
    SIGNAL (SIG_OVERFLOW0)
    	{
    TCNT0=200;
    		a++;
    
    		LCDxy(0,0);
    		write_text("a=");
    
    //wyświetlaj aktualą wartosc zmiennej "a"
    char buffer [8];
    itoa(a,buffer,10);
    LCDxy(3,0);
    write_text(buffer);
    	} 
    
    
    // kod przerwania, wykonywany w momencie uaktywnienia przerwania INT0
    SIGNAL(SIG_INTERRUPT0)
    {
    	
     // jeśli flaga (stan początkowy "0") jest 0 to wykonaj:
    	if (flaga==0)
    				{ 
    
    		//write_command(0x01);
    				
    					MCUCR= (1<<ISC00) | (1<<ISC01); //przerwanie wyzwalane zboczem narastającym __|-- 
    					TCCR0 = 0b00000001;// prescaler na 1024
    				
    					TIMSK |= (1 << TOIE0); // aktywne przerwanie overflow
    					TCNT0=200;
    					flaga=1;
    
    
    	// jeśli flaga równa 1, to wykonaj:
    				}else if (flaga==1)	{
    
    
    					TIMSK&=~(1<<TOIE0); // nie zezwalam na przerwanie
    					TCCR0 =0; // stop timera
    					MCUCR=0<<ISC00; //1. ustawiam przerwanie wyzwalane zboczem opadającym --|__
    					MCUCR=1<<ISC01;
    
    
    					flaga=0;
    					a=0;
    				}
    } 
    
  • Pomocny post
    #21 8398332
    Andrzej__S
    Poziom 28  
    napisał:

    Jedna rzecz jeszcze nie daje mi spokoju. Jeśli timer się przepełni, zmienna a, jest zwiększana, jest to dla mnie trochę za wolno. Prescaler jest na 1. Więc pozostaje wpisać wartosćdo TCNT0, żeby szybciej się przepełniał.

    Proponuję użyć trybu CTC timera i przerwań Compare Match. Można ustawić przerwania praktycznie na dowolną ilość taktów, tylko uważaj, żeby procedura obsługi przerwania zdążyła się "wyrobić" :)

    Dodano po 11 [minuty]:

    
    SIGNAL (SIG_OVERFLOW0) 
       { 
    TCNT0=200; 
          a++;
    
    
    /* kod od tego miejsca do końca procedury
       przenieś np. do pętli głównej   */
          LCDxy(0,0); 
          write_text("a="); 
    
    //wyświetlaj aktualą wartosc zmiennej "a" 
    char buffer [8]; 
    itoa(a,buffer,10); 
    LCDxy(3,0); 
    write_text(buffer); 
       }
    


    No i zaznaczony powyżej fragment raczej wyrzuć do pętli głównej. Procedura obsługi przerwania jest zbyt długa. Na pewno nie zdąży się wyrobić w kilkudziesięciu taktach.
  • #22 8404214
    karolczyzycki
    Poziom 20  
    Z obsługi przerwania wyrzuciłem zbędny kod.
    Wpisałem TCNT0=250; i zlicza bardzo szybko.
    Tak jak powinno. Ale...
    Jeśli przysłonię czymś czujnik, zaczyna liczyć, jeśli odsłonię, przestaje i zaraz wyświetla wartość zmiennej a.
    W jaki sposób wykorzystać wartość tej zmiennej do obliczenia prędkości obrotu tarczy?

    Tarcza z wycięciami będzie założona na silniczek, prędkość regulowana zasilaczem.
    Wyczytałem że najdokładniej jest mierzyć prędkość, wykorzystując długość impulsu.
    Jak to teraz ze sobą powiązać...?
  • #23 8404695
    Andrzej__S
    Poziom 28  
    Cytat:

    Z obsługi przerwania wyrzuciłem zbędny kod.
    Wpisałem TCNT0=250; i zlicza bardzo szybko.

    Zlicza bardzo szybko, ale obawiam się, że niedokładnie. 6 taktów to za mało nawet na tak krótką procedurę obsługi przerwania. Pisząc w C nie widzimy tego, ale samo wejście w procedurę to 4 takty + wyjście (RETI) 4 takty. Do tego zwykle w procedurze obsługi przerwania występuje jakieś odkładanie na stos używanych rejestrów (przynajmniej SREG musi być zapamiętany) - po 2 takty na rejestr, później zdejmowanie ze stosu - też po 2 takty na rejestr. Samo wczytanie z RAM wartości zmiennej 'a', inkrementowanie i ponowne zapamiętanie to jakieś 10 taktów (chyba, że kompilator umieścił zmienną 'a' w rejestrach, co jest raczej mało prawdopodobne). Wniosek: przerwania są częściej niż czas trwania procedury obsługi, więc nie wszystkie zostaną obsłużone i tym samym wartość zmiennej 'a' będzie nieprawidłowa. Nie masz prawdopodobnie teraz tego jak sprawdzić, ale uwierz mi na słowo. Jeśli potrzebujesz aż tak dużej szybkości, to ta metoda nie zda egzaminu. Nawet zastosowanie trybu CTC (odeszłaby wtedy konieczność ustawiania stanu licznika - można pominąć 'TCNT0 = 250;') też nie wystarczy.

    Nie wiem jakie prędkości obrotowe chcesz mierzyć, ale przy większych obrotach lepiej zastosować tarczę z większą ilością otworów i zliczać impulsy z czujnika fotooptycznego w jednostce czasu np. 1s. Obliczenie prędkości obrotowej będzie wtedy wyglądało mniej więcej tak:

    (ilość zliczonych impulsów) / ( (czas zliczania [s]) * (ilość otworów w tarczy) ) [obr./s]

    Dla zwiększenia dokładności i zakresu pomiarów można użyć 16-bitowego timera (właściwie to raczej 'countera') taktowanego sygnałem zewnętrznym, czyli impulsami z czujnika.

    Ta metoda daje małe dokładności w zakresie niskich obrotów.

    Inna opcja to zrezygnowanie z inkrementowania zmiennej wewnątrz obsługi przerwania. Można wyzerować licznik (trzeba użyć 16-bitowego bo 8-bitowy będzie miał zbyt mały zakres i co za tym idzie - dokładność) w momencie pojawienia się zbocza opadającego i odczytać jego wartość do zmiennej 'a' w momencie pojawienia się zbocza narastającego. W pętli głównej przeliczasz 'a' na prędkość obrotową i wyświetlasz na LCD.
    Przykładowo, wykorzystując Twoją technikę:
    
    ISR(INT0_vect)
    { 
    
          if (flaga==0)
          {
              TCNT1=0;
              MCUCR= (1<<ISC00) | (1<<ISC01); //przerwanie wyzwalane zboczem narastającym __|-- 
              flaga=1;
           }
           else if (flaga==1)
           {
              a = TCNT1;
              MCUCR=1<<ISC01; //1. ustawiam przerwanie wyzwalane zboczem opadającym --|__ 
              flaga=0;
           }
    }
    
    // na początku funkcji 'main' należy włączyć taktowanie timera 1
    // bez preskalera
        TCCR1B = (1<<CS10);
    // później nie trzeba go wyłączać, wystarczy zerować licznik
    
    

    W tym przypadku nie należy stosować otworów, a raczej jakieś "wypustki" przesłaniające czujnik tylko przez jakiś mały kąt w stosunku do kąta odsłonięcia, najlepiej niezbyt dużą ilość (tych "wypustek"), większą od 1, żeby była możliwość dobrego wyważenia tarczy. Ewentualnie można zmienić procedurę tak, aby timer zliczał czas w momencie przesłonięcia czujnika (a nie jak w naszym przypadku powyżej - czas odsłonięcia) i wtedy można zastosować otwory.
    Kąty odsłonięcia i przesłonięcia czujnika należy dobrać odpowiednio do zakresu mierzonych prędkości obrotowych. Przykładowo, aby uzyskać większą dokładność przy wyższych obrotach należy zastosować jak największy kąt "zliczania timera". Z kolei zbyt duży kąt może spowodować przepełnianie timera przy niższych obrotach.
    No i wykonanie tarczy musi być dosyć precyzyjne (i symetryczne) jeśli oczekujesz precyzyjnych pomiarów. Poprzednia metoda (ze zliczaniem impulsów w jednostce czasu) nie wymaga dużej precyzji.

    Obliczenie prędkości przy wykorzystaniu tej metody wyglądałoby mniej więcej tak:

    (kąt odsłonięcia czujnika [rad]) * F_CPU [Hz] / ( 2 * PI * (ilość zliczonych impulsów) ) [obr./s]

    Zastosowanie tej metody daje mniejsze dokładności przy wyższych obrotach.

    Zależnie od tego, jaki zakres prędkości będziesz mierzył, należy wybrać odpowiednią metodę. Nie ma uniwersalnego rozwiązania. Jeśli zakres będzie zbyt duży (np. od kilku obr./min do kilkunastu tysięcy obr./min) trzeba zastosować obydwie metody z możliwością zmiany zakresu, żeby uzyskać satysfakcjonującą dokładność pomiaru.

    Mam nadzieję, że nie zagmatwałem za bardzo :)

    Dodano po 47 [minuty]:

    Cytat:

    Jeśli przysłonię czymś czujnik, zaczyna liczyć, jeśli odsłonię, przestaje i zaraz wyświetla wartość zmiennej a.

    A ja przyjąłem, że jest dokładnie odwrotnie. Który schemat z tych dwóch przez Ciebie przedstawionych zastosowałeś? Ja sądziłem, że ten po lewej. W każdym razie ja bym tak podłączył. Jeśli zastosowałeś ten po prawej, to będzie działał odwrotnie, czyli musisz "odwrócić" wszystkie wyrazy związane z przesłonięciem lub odsłonięciem czujnika w tekście, który napisałem powyżej (lub zmienić podłączenie czujnika ;)).
  • #24 8413928
    karolczyzycki
    Poziom 20  
    Żeby zrobić pomiar czasu w sek, potrzebuję wykorzystać drugi timer (TCNT1), on jest 16 bitowy.
    Kiedyś dla 8bitowego zrobiłem kalkulator w Excelu, za pomocą którego mogłem łatwo znaleźć czas, dopasowując częstotliwość, wartości w liczniku itd. Zamieszczam ten kalkulator, oraz program. Zrobiłem to samo dla 16 bitowego licznika. Ale nie umiem tego opanować, czasy w ogóle się nie zgadzają...

    volatile a=0; // zamienna do opoznienia wyświetlania
    volatile sek=0;
    
    int main(void)
    {
    
    lcd_init();	
    write_command(0x01);
    
    	TCCR1A = 0;// prescaler na 1024
    	TCCR1B = (1 << CS10) | (1 << CS11); 
    	TCNT1=225;
    	TIMSK|=(1<<TOIE1);// odblokowanie przerwania od licznika 
    
    sei();
    
     	while(1)
    
    				{
    
    						if(a>160)
    						{
    						sek++;
    						}
    
    					char buffer6 [8];
    					itoa(sek,buffer6,10);
    					LCDxy(0,1);
    					write_text(buffer6);
    
    
    					char buffer4 [8];
    					itoa(TCNT1,buffer4,10);
    					LCDxy(0,1);
    					write_text(buffer4);
    
    					char buffer5 [8];
    					itoa(a,buffer5,10);
    					LCDxy(0,0);
    					write_text(buffer5);
    				}
    
        return(0);
     
    }
    SIGNAL (SIG_OVERFLOW1)
    	{
    a++;
    	} 
    
  • #25 8414555
    Andrzej__S
    Poziom 28  
    Napisz konkretnie, jaki zakres obrotów masz zamiar mierzyć. Od tego zależy, jaką taktykę obrać. Trudno będzie Ci pomóc, jeśli nie sprecyzujesz oczekiwań.

    A obliczenie ile taktów (n) musi odliczyć timer, żeby odmierzyć konkretny czas (t) przy częstotliwości taktowania procesora (F_CPU) i preskalerze timera (p) jest bardzo proste:

    n[1] = F_CPU[Hz] * t[s] / p[1]
  • #26 8414570
    kwikam
    Poziom 10  
    Do pomiaru czasu pomiędzy impulsami proponuje zastosować ICP (Timer/Counter1 Input Capture Pin). Po pojawieniu się impulsu z miernika będziesz miał w rejestrze ICR1 (Input Capture Register) wartość licznika Timera1. Możesz obliczyć długość trwania impulsu w taki oto sposób:

    
    volatile uint16_t PulseWidth; 
    volatile bool flPrzerwanieICR1=false;
    
    ISR(TIMER1_CAPT_vect) 
    
    {
         static uint16_t LastCapture; 
    
         PulseWidth = ICR1 - LastCapture; 
         LastCapture = ICR1; 
    
         flPrzerwanieICR1=true;
    }
    
    


    A później w pętli głównej sprawdzić flagę flPrzerwanieICR1 i zrobić co chcesz z wartością PulseWidth.

    Trochę dużo kodu jest w przerwaniu ale czy nie będzie się wysypywać to zależy od prędkości wirowania silniczka
  • #27 8414721
    Andrzej__S
    Poziom 28  
    @kwikam: Wykorzystanie Input Capture to dobry pomysł.

    kwikam napisał:

    Trochę dużo kodu jest w przerwaniu ale czy nie będzie się wysypywać to zależy od prędkości wirowania silniczka


    Dodam tylko, że zależy jeszcze od F_CPU (autor pytania napisał, że stosuje 16MHz, więc nie powinno to stanowić problemu) oraz od konstrukcji tarczy.

    Tak czy inaczej, trudno jest zaproponować jakieś konkretne rozwiązanie nie znając założeń. Mam tu na myśli głównie zakres obrotów.
  • #28 8414966
    karolczyzycki
    Poziom 20  
    To może inaczej, zapomnijmy na chwilę o tym mierniku obrotów na razie chcę się dowiedzieć, co muszę wpisać, żeby zmienna sek zwiększała się co sekundę.
    Wcześniej wklejony kod, działa trochę za szybko...
    W przypadku timera 8-bitowego było prosto bo obliczyłem sobie to z excela.
    Ale dla 16-bitowego mam problem...
    Jeśli zrobię licznik, który odlicza sekundy to później chyba tylko z górki.
  • #29 8415038
    DonQuijote88
    Poziom 14  
    Technicznie wygląda to tak:

    W każdym takcie zegara (np w 1/1000000 s - przy taktowaniu 1 MHz) zliczany jest jeden impuls. Timer 16-bitowy od 8-bitowego różni się tylko tym, że przepełnienie następuje po 65536 taktach a nie po 255. Ale żeby policzyć dokładnie jedną sekundę to musisz nadal odliczyć ten milion taktów. Jak widać zegar będzie leciał wiele razy wkółko zanim odliczy milion taktów. Gwóźdź programu polega na tym, żeby zliczyć ile razy ma się przepełnić timer (odpowiednia flaga), żeby uzyskać jedną sekundę.
    Zapewne dałoby się napisać taką funkcję, żeby odmierzała 1 sekundę z dokładnością do 1 us - wtedy trzeba by skrócić cykl timera np do 50000 taktów. To się da zrobić w odpowiednim trybie. Niestety nie mam przed sobą dokumentacji, więc więcej nie powiem. Może Cię to trochę naprowadzi.

    Pozdrawiam

    P.S. Tak się składa że niedługo też będę sie zajmował enkoderem więc problem tak czy siak mnie czeka.
  • #30 8415158
    karolczyzycki
    Poziom 20  
    Ja wiem jak to zrobić dla 8, ale nie wiem jak to zrobić dla 16, bo to nie tylko sprawa większej ilości zanim nastąpi przepełnienie, ale trzeba te dwa rejestry A i B ustawiać, tego nie rozumiem.
    Dla 8, był jeden rejestr, ładowałem wartość, odczytywałem i było ok.
    A tutaj są dwa...
REKLAMA