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

[atmega8][C] Nie zapisuje danej pomiarowej do zmiennej.

mazur89 11 Paź 2011 06:20 2448 10
  • #1 10014759
    mazur89
    Poziom 10  
    Witam serdecznie.

    mam dziwny problem ze swoją atmegą 8. Wkleję tutaj mniejszą część całego kodu w której jest problem:

    if(przycisk_c(2)) // opcja pomiaru.
    		{
    			min=40;
    			max=0;
    			CzyscLCD();
    			
    			while(1)
    			{
    				for(i=0;i<20;i++)
    				{
    					pom+=(unsigned int)pomiar();
    
    					if(i==19)
    					{pom=(int)(((pom*0.351)/20));}
    				}
    
    				
    				
    				if((int)pom>max) <-TUTAJ NAJPRAWDOPODOBNIEJ PROBLEM.
    				{
    					max=pom;
    					
    				}
    				
    				
    				if(przycisk_c(1))
    				{
    					break;
    				}
    				if(max<10)
    				{cyfry=1;}
    					
    				else if(max<100&&max>=10)
    				{cyfry=2;}
    				else
    				{cyfry=3;}
    
    				CzyscLCD();
    				char buf[4];
    				itoa (max,buf,10);
    				WyswietlLCD(buf, cyfry);
    					
    				
    			}

    Pom, to funkcja robiąca pomiar przetwornika A/C. Działa ona poprawnie i wyświetla poprawne wartości. Mi chodzi jednak o to aby wyświetlona została jedynie maksymalna wartość odczytana przez przetwornik. Jednak przy tak zapisanym kodzie wyświetlana jest wartość którą wpiszę u góry do max, czyli w tym wypadku "0".

    Jeżeli w if zapiszę max=min to wyświetlana zostanie wartość 40.
    jeżeli zapiszę tak:


    if(pom>max)
    {
          max_buf=pom;
          max=max_buf;
    }
    


    i np. max zainicjalizuję z wartością 150,i wyświetlam max_buf to wartość max_buf jest znowu wyświetlana ciągle(zmienia się wraz z wartością pomiaru) ale tylko dla wartości większych od 150.
    Takze moje pytanie:
    Dlaczego do zmiennej max, nie jest zapisywana wartość pom w if?
    Pozdrawiam.
    Mazur.[code]
  • #2 10014813
    michcior
    Poziom 30  
    Podaj może deklaracje zmiennych. To ważne bo różne typy są rożnie porównywane, szczególnie gdy mamy doczyniena ze znakami.

    Dodano po 1 [minuty]:

    BTW, gdzie "pom" jest inicjowane?

    Dodano po 2 [minuty]:

    BTW#2: "if(i==19)..." można wyrzucić poza pętlę. I tak wykonuje się po skończeniu pętli.
    BTW#3: Sprawdź czy "pom" się nie "przekręca" tzn. zsumowanie 20 pomiarów nie jest większe od zakresu "pom"
  • #3 10014947
    dziadzia
    Poziom 15  
    Zrób porządek z tymi rzutowaniami, bo czasami nie wiadomo o co chodzi w tym kodzie.
  • #4 10015045
    mazur89
    Poziom 10  
    Michcior:
    unsigned int pomiar()//Funkcja wykonująca pomiar 
    {
    	// Zezwolenie na konwersję
    	ADCSRA |= _BV(ADEN);
    
    	ADCSRA |= _BV(ADSC);
    	while(bit_is_set(ADCSRA,ADSC)){}
    
    	ADCSRA &= ~(_BV(ADEN));
    
    
    	return ADC;
    }


    zmienna max jest inicjalizowana jako int.
    Pom się raczej nie przekręca bo 256*20 mieści się w zakresie int. Ponadto tak samo zapisana funkcja liczenia wartości średniej działa w porządku w innym programie. A nawet jak tutaj będę wyświetlał pom to wszystko gra i buczy.

    Z góry dzięki za wszelką pomoc ;)
  • #5 10015073
    michcior
    Poziom 30  
    Dzieki,
    Chodzi o to, że "pom+=(unsigned int)pomiar();" jest jedynym miejscem gdzie zmienna "pom" jest przypisywana. Tyle że to jest +=. Czyli nie wiadomo co siedziało w niej wcześniej. Jeśli to zmienna statyczna to może być zerem ale tylko po restarcie. Jeśli jest lokalna to rezerwowana jest na stosie i wtedy jest zupełnie losowa.

    Druga rzecz, jakie są typy zmiennych i czy są volatile czy nie. Ma to czasami znaczenie. Porównywanie zmiennych unisgned z signed bez rzutowania jest bardzo śliskie. Kompilator najprawdopodobniej sam zrzutuje na int i dopiero porównuje, nawet kiedy porównujemy unsigned z unsigned (takie coś już spotkałem). Jak się nie jest pewnym to lepiej rzutować wszystko co popadnie i sprawdzać czy jest lepiej.

    Poza tym, długość bitowa też ma znacznie. Jeśli "pom" jest 16 bitowy to nie tak trudno go przekręcić. Również, "pom>32767" ze znakiem (a tak rzutujesz w if) jest mniejsze od 0!
  • Pomocny post
    #7 10015091
    michcior
    Poziom 30  
    Może pozbądź się tych zmiennoprzecinkowych operacji. Takie rzeczy można zarobić stałoprzecinkowo a różnica w prędkość i rozmiarze kodu jest kosmiczna. To bardzo proste:
    1) Zakładamy 16 bitową rozdzielczość (można 32 jak się chce)
    2) Przlieczamy współczynnik, o tak: 65536*0.351=23003
    3) deklarujemy:
    unsigned short a; //16 bitowa bez znaku
    unsigned long wynik; //32 bitowy wynik
    4) mnozymy o tak:
    wynik=a*23003;
    wynik>>=16; //bierzemy tylko starszą cześć, dolne 16 bitów to jakby część dziesiętna

    Możesz sprawdzić, np.
    -> 10000*0.351=3510
    -> 10000*23003=230030000=0xDB5FAB0 bierzemy górną część 0xDB5 = 3509!!!

    Dodano po 6 [minuty]:

    A int jest 32 bitowy? Bo może być 16, to zależy od kompilatora. Tylko typ "long" gwarantuje 32 bity.
  • #8 10015132
    mazur89
    Poziom 10  
    dondu napisał:
    mazur89 napisał:
    Pom się raczej nie przekręca bo 256*20 mieści się w zakresie int.

    A dlaczego 256, skoro odczytujesz cały ADC a nie tylko 1 bajt pomiaru?

    Słusznie, mój błąd. To jest 1024*20, ale to nadal się mieści w int.

    Problem rozwiązany. Bład polegał na tym, że zmienna pom nie była inicjalizowana z wartością. Teraz jak inicjalizuję ją z wartością 0 wszystko śmiga jak należy.
    Aczkolwiek szczerze mówiąc nie rozumiem dlaczego bez inicjalizowania kod nie chciał działać poprawnie?
    Zmieniłem też wszystkie zmienne na int. Również funkcję pomiar() na int, aby uniknąć rzutowania.

    Dzięki wszystkim za odpowiedzi. Jeżeli by się komuś chciało wytłumaczyć, to chętnie poznał bym powód wcześniejszego problemu.
    Pozdrawiam.
    mazur.
  • #9 10015141
    dondu
    Moderator na urlopie...
    mazur89 napisał:
    Bład polegał na tym, że zmienna pom nie była inicjalizowana z wartością.

    Następnym razem wklejaj cały program tym bardziej że byłeś proszony o podanie fragmentu inicjalizacji zmiennej pom:

    michcior napisał:
    BTW, gdzie "pom" jest inicjowane?
  • #10 10015144
    mazur89
    Poziom 10  
    @dondu
    Źle zrozumiałem i wkleiłem częśc kodu z funkcją pomiar. Nieporozumienie. Calego kodu nie chciałem wklejać, aby nie zaciemniać obrazu.
    "pom" inicjalizowany jest w main (tam gdzie znajduje sie też pętla z problemem - juz rozwiązanym) :)
    Pozdrawiam.
REKLAMA