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

Jak zmierzyć częstotliwość ATmegą8?

5657jz 05 Sty 2011 00:41 2235 15
REKLAMA
  • #1 8959471
    5657jz
    Poziom 14  
    Potrzebuje zmierzyć częstotliwość w zakresie do 200kHz(w tym przypadku 3,2MHz) procek: to ATmega8
    Kombinuje jak koń pod górę, na czym polega mój błąd ?
    Timer 2 odmierza czas 1s.
    Timer 1 w założeniu ma zliczać impulsy z zewnatrz.
    (wartość 0xFF w OCR1A,-impulsy dochodzą z T1,-po zrównaniu TCNT1H/L zerują się-i cykl się powtarza.)

    Oróż Timer2 wchodzi w przerwania - czyli odmierza 1s.
    Natomiast Timer1 nie chce zaskoczyć przerwania (Tz. jakby go nie było)

    Może Ktoś podpowiedzieć ?

    /******** Przerwania od zrownania Timer counter1****************************/ 
    ISR( TIMER1_COMPB_vect)  //SIG_OUTPUT_COMPARE1B 
    {								
    		obroty1++;	     // ma ich być 49  (0x31) zegar 8Mhz
    }
    /******** Przerwania od zrownania Timer counter2****************************/ 
    ISR(TIMER2_COMP_vect ) 	 //SIG_OUTPUT_COMPARE2
    {
    		czy_sekunda++;   // ma ich być 31372 (0x7A8C) zegar 8Mhz
    }
    
    
    #ifdef POMIAR_KHZ
    									
    									// ustawienia licznika impulsow
    									TC1_NORMAL_A();
    									TC1_NORMAL_B();			// Tryb NORMAL 0xFFFF
    									TCCR1A|=_BV(FOC1A); 	// Wymuszenie trybu OUTPUT COMPARE DLA KANALU A
    									TIMSK|=_BV(OCIE1A);		// Odblokowanie przerwań OUTPUT COMPARE L1
    									TC1_PRES_FALLING(); 	// zbocze opadajace START TIMERA1
    									
    									// ustawienie odmierzania czasu 1 s
    									TIMSK|=_BV(OCIE2);	// Odblokowanie przerwań OUTPUT COMPARE L2
    									TC2_PRES_1(); 		// bez preskalera START TIMER2
    									
    									while(czy_sekunda==0x7A8B)						
    										if (czy_sekunda==0x7A8C)
    										{
    											wartoscH=TCNT1H;				
    	 					      			    wartoscL=TCNT1L;
    											wartoscH=(wartoscH<<8)^TCNT1L;
    											licznik=(65535*obroty1)+wartoscH;
    											obroty1=0;
    											czy_sekunda=0;
    							
    							
    											sprintf(bufor,"Czestotliwosc =%u Hz",licznik);
    												for(i=0;i<=27;i++) {USART_TXR_znak(bufor[i]);} // Wyśli wynik
    											przen_linie();
    											licznik=0;
    										}//end czy_sekubda		
    							#else
    								USART_TXR_text(info_d);	//Brak uslugi częstosciomierza 
    							#endif
    							break; KONIEC POMIARU Hz
    
  • REKLAMA
  • #2 8959598
    asembler
    Poziom 32  
    Nie rozumiem do czego używasz OCR1A skoro wystarczy zadeklarować przerwanie od przepelnienia licznik T1. A to że sie nie zgłasza przerwanie to może za małą częstotliwość doprowadzasz do wejścia T1 >65536 Hz
    Poza tym lepiej byś zrobił gdyby odczyt następował w przerwaniu T2 a przerwanie ustawił na 1S co można osiągnąc używając licznika T2 z kwarcem 32kHz a atmege puscić na RC.
  • #3 8961040
    5657jz
    Poziom 14  
    jak jeden problem usunę, to pojawia sie następny. Chyba wymiękam !!
    Otóż: Powyższy kod poprwiłem, przerwania chodzą jak powinny.
    Lecz, w spirinf() umieszcza w buforze tylko liczbę 16 bitową
    tz. licznik=0x9FFF6 -> w buforze 0xFFF6 Dlaczego ?? O co chodzi??

    To kod:
    uint32_t licznik=0;
    	uint16_t wartoscH;
    	uint8_t wartoscL=0;
    	uint16_t volatile czy_sekunda =0;  
    	unsigned char volatile obroty1;



                                  wartoscH=TCNT1H;
    						wartoscH+=TCNT1L;
    			licznik=((65535*obroty1)+wartoscH);

    licznik= 0x9FFF6
    sprintf(bufor,"Czestotliwosc =%lu Hz",licznik);

    Podgląd bufora: Czestotliwosc = 65526 Hz ( to własnie 0xFFF6 )
    Gdzie podziała się '9' przed FFF6 ?
  • REKLAMA
  • #4 8961163
    szelus
    Poziom 34  
    5657jz napisał:

    Lecz, w spirinf() umieszcza w buforze tylko liczbę 16 bitową
    {...}
    sprintf(bufor,"Czestotliwosc =%u Hz",licznik);



    Zamiast "%u" daj "%lu", bo to long.
  • REKLAMA
  • #5 8961176
    dondu
    Moderator na urlopie...
    Radziłbym także zastosować się do prawidłowego pobierania wartości z TCNT1.
    W dokumentacji jest zalecane:

    unsigned int TIM16_ReadTCNT1( void )
    {
     unsigned char sreg;
     unsigned int i;
     /* Save Global Interrupt Flag */
     sreg = SREG;
     /* Disable interrupts */
     _CLI();
     /* Read TCNT1 into i */
     i = TCNT1;
     /* Restore Global Interrupt Flag */
     SREG = sreg;
     return i;
    }
    
  • #6 8961332
    5657jz
    Poziom 14  
    szelus - Jesteś Wielki.
    Ale czego teraz mam: Czestotliwosc =655350 Hz Skąd to ostatnie '0' ?
    Oczywiście odczyt z TCNT1 poprawiłem.
  • REKLAMA
  • #10 8961631
    5657jz
    Poziom 14  
    Dziewiatka (9) jest. Przybyło 'zero' na końcu.
    Nie wiem moze z AVR Studio coś jest ? Bo nie moge wyłączyć:
    TC1_PRES_FALLING()	TCCR1B|= _BV(CS12) | _BV(CS11)    

    poleceniem:
    TC1_PRES_STOP()	TCCR1B &=~(_BV(CS12)) | ~(_BV(CS11)) 

    Chyba zapisze ten kod w procka, i zobacze jak to bedzie chodziło, ale później bo musze wyjść.
  • #12 8961974
    5657jz
    Poziom 14  
    No i gut. CS.. wyłączone. Ile to się można nauczyć.( chociaż , jestem ciekaw dlaczego tak się dzieje)
    Lecz zero na końcu jak było ,tak jest. Nie wiem !!
  • #13 8962064
    dondu
    Moderator na urlopie...
    Z zerem ktoś inny musi Ci pomóc.

    TCCR1B &=~(_BV(CS12)) | ~(_BV(CS11))



    TCCR1B & = ~(1) | ~(1)
    
    czyli
    
    TCCR1B & = 0 | 0
    
    czyli 
    
    TCCR1B &=0
    
    a w konsekwencji
    
    TCCR1B = 0 

    czyli powinno być ok bo CS12-CS10 będą wyzerowane czyli licznik zatrzymany, ale w ten sposób zerujesz cały rejestr TCCR1B, a nie o to Ci chodziło.

    No chyba że się mylę bo nie używam makra _BV().



    Dodano po 9 [minuty]:

    Dodam jeszcze wyjaśnienie:

    TCCR1B  &= ~((1<<CS12) | (1<<CS11))
    czyli TCCR1B  &= ~(0x04 | 0x02)    
    czyli TCCR1B  &= ~(0x06)    binarnie 0b00000110
    czyli TCCR1B  &= 0xF9    binarnie 0b11111001
    czyli zerujesz tylko 2 bity
  • #14 8962129
    krzemowy
    Poziom 19  
    TCCR1B &=~(_BV(CS12)) | ~(_BV(CS11))


    Ww. zapis oznacza tyle co TCCR1B &= ~(1 << 2) | ~(1 << 1), to znowuż jest równoważne TCCR1B &= ~4 | ~2. W zapisie zerojedynkowym będzie TCCR1B &= 1111 1011 | 1111 1101, przy czym po wykonaniu operacji OR na tych ślicznych liczbach postanie z nich 1111 1111 i dlatego taka operacja niczego nam nie da. Żeby zatrzymać licznik zerując bity CS12 i CS11 należałoby napisać:
    TCCR1B &= ~_BV(CS12) & ~_BV(CS11);

    Albo krócej(ale mniej czytelnie):
    TCCR1B &= ~7; //wyzerowanie bitów CS10, CS11 i CS12


    No ale ja się nie znam ;)×
  • #15 8962208
    Freddie Chopin
    Specjalista - Mikrokontrolery
    krzemowy napisał:
    TCCR1B &=~(_BV(CS12)) | ~(_BV(CS11))


    Ww. zapis oznacza tyle co TCCR1B &= ~(1 << 2) | ~(1 << 1), to znowuż jest równoważne TCCR1B &= ~4 | ~2. W zapisie zerojedynkowym będzie TCCR1B &= 1111 1011 | 1111 1101, przy czym po wykonaniu operacji OR na tych ślicznych liczbach postanie z nich 1111 1111 i dlatego taka operacja niczego nam nie da. Żeby zatrzymać licznik zerując bity CS12 i CS11 należałoby napisać:
    TCCR1B &= ~_BV(CS12) & ~_BV(CS11);

    No i przerobiłeś zły kod na zły kod, bo to co podałeś jest przecież identyczne z tym co było wcześniej... Co jedna porada to lepsza - dondu też zastosował jakąś swoją matematykę na tych operatorach, bo jego wytłumaczenie nie ma nic wspólnego z rzeczywistością...

    Najpierw się bity ORuje
    ((1 << x) | (1 << y) | (1 << x))
    a potem dopiero robi się odwrotność CAŁOŚCI:
    ~(...)

    A więc:
    rejestr &= ~((1 << x) | (1 << y) | (1 << x));

    4\/3!!
  • #16 14458472
    5657jz
    Poziom 14  
    Dzięki za pomoc
REKLAMA