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

[C] "Przekręcanie" się zmiennych przy dużych warto

ginar 25 Wrz 2008 11:30 1547 5
  • #1 5569824
    ginar
    Poziom 21  
    Witam
    Mam taką funkcję:
    
    void FREQREG( int F_output)
    {	
      int x=0;
      int *wsk_1;
      int zapisanie_MSB=0;  	//jeśli ta zmienne jest 1 to oznacza, że rejestr Freq MSB jest juz zapisany
      wsk_1=& Freq[3];			
    
    							  
     float y= F_output*10.32444; //wzór z datascheet dla MCLK=26000000
      x=(int)y;
    	
    	if(x>16383)
    		{
    		int a=x/16384;
    		*wsk_1=0x40;
    		 wsk_1--;
    		*wsk_1=a;
    		 wsk_1--;
    		 x=x-a*16384;
    		 zapisanie_MSB=1;
    		}
    	if(x>255)
    		{
    		int y=x/256;
    		switch(zapisanie_MSB)
    		{ case 0:    //oznacza że trza zapisać wszystkie rejestry
    				*wsk_1=0x40;
    				wsk_1--;
    				*wsk_1=0x00;
    				wsk_1--;
    				*wsk_1=y+64;
    				wsk_1--;
    				*wsk_1=x-y*256;
    				break;
    		  case 1:	//oznacza że trza zapisać tylko rejestry  LSB a wsk_1 jest juz prawidłowo ustawiony
    				*wsk_1=y+64;
    				wsk_1--;
    				*wsk_1=x-y*256;
    				break;	
    		}
    		}
    		
    	
    	if(x<=255)
    		{	 
    		 switch(zapisanie_MSB)
    		{ case 0:    //oznacza że trza zapisać wszystkie rejestry
    				*wsk_1=0x40;
    				wsk_1--;
    				*wsk_1=0x00;
    				wsk_1--;
    				*wsk_1=0x40;
    				wsk_1--;
    				*wsk_1=x;
    				break;
    		  case 1:	//oznacza że trza zapisać tylko rejestry  LSB a wsk_1 jest juz prawidłowo ustawiony
    				*wsk_1=0x40;
    				wsk_1--;
    				*wsk_1=x;
    				break;	
    		}
    		}
    }
    
    

    jest to funkcja mająca wpisywać odpowiednie wartosci do rej.FREQREG w AD9833.
    Funkca dobrze działa do wartości zmiennej F_output około 10 000
    poczym (ogladając przebieg na oscyloskopie wartości w rejestrze częstotliwości "przekręcają się" i znowu startuje od 0Hz).
    Funkcję sprawdzałem na PC w DeV C++ i dają poprawne wynik wpisu do rejestu FREQREG.
    Wcześniej zamiast wzoru :
    float y= F_output*10.32444;

    używałem :
    float y= 268435456*F_output/26000000;

    (268435456=2^28 )
    i tutaj zaczynał się "przekręcać" już od F_output=17
    dlatego zamieniłem 268435456/26000000=10.32444;

    Dalszy ciąg programu to tylko wpisanie wyliczonych powyżej wartości
    
    		int FREQ_LSB_0=Freq[0];
    		int FREQ_LSB_1=Freq[1];
    		int FREQ_MSB_0=Freq[2];
    		int FREQ_MSB_1=Freq[3];
    

    Tablica Freq jest deklarowana globalnie.

    Próbowałem double float ale WIN AVR daje error
    Procesor to ATmega 16
    Zmieniłem tytuł(regulamin p.11.1) i przeniosłem do działu Milkrokontrolery AVR
    [zumek]
  • #2 5569948
    mietekn
    Poziom 35  
    Problem wynika z ograniczeń wielkości danych typu int (-32767 do 32768).
    Zacznij od przejścia na typ bez znaku (0 do 65535):
    int x=0; na unsigned int x=0;
    x=(int)y; na x=(unsigned int)y;
    Jeśli nie wystarczy zamień int na unsigned long int (podobnie występujące niżej int a i int y).
  • #3 5570113
    ginar
    Poziom 21  
    Trochę pomógł unsigned long int, ale przy F_output=300 000
    znowu się gubi.
    void FREQREG( int F_output)
    {	
      float y= F_output*10.32444;   										
       unsigned long int x= (unsigned long int)y;
     
       int *wsk_1;
       int zapisanie_MSB=0;  	  //jeśli ta zmienne jest 1 to oznacza, że rejestr Freq MSB jest juz zapisany
       wsk_1=& Freq[3];			  //wsk_1 = & Freq[3]; // wskaźnik pokazuje na FREQ_MSB_1 !!
     	
    	if(x>16383)
    		{
    		unsigned long int a=x/16384;
    		*wsk_1=0x40;
    		 wsk_1--;
    		*wsk_1=a;
    		 wsk_1--;
    		 x=x-a*16384;
    		 zapisanie_MSB=1;
    ....		}
    


    max. F_output=4000000
    a więc max y= 41297760
  • Pomocny post
    #4 5570153
    mietekn
    Poziom 35  
    A co z typem samego F_output ?
  • #5 5570459
    ginar
    Poziom 21  
    Ok, działa
    Dzięki za pomoc!
  • #6 5600562
    szeryf.rm
    Poziom 22  
    dla AVR korzystniej (bo bez pomyłek) korzysta się z typów
    int8_t
    int16_t
    int32_t
    uint8_t
    uint16_t
    uint32_t
    Niezwykle wygodne i nie myli się int na AVR z int na Dev-C++, gdzie odpowiednio w pierwszym przypadku to 16 biotowa liczba a w drugim 32 biotowa.
REKLAMA