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

[atmega8][c] Prędkościomierz i pulsometr.

myszarafa 09 Cze 2010 13:11 3960 12
  • #1 8171998
    myszarafa
    Poziom 10  
    Witam, chciałbym zbudować układ który będzie mierzył prędkość i puls podczas jazdy na rowerze. Układ ma działać na podstawie różnic w czasie między impulsami na wejściu uC. Problem w tym, że układ działa poprawnie tylko gdy sygnał jest wysyłany na jedno lub drugie wejście, gdy na oba wtedy pojawiają się błędy.
    Np. przy 1 wejściu prędkość wynosi 24km/h, gdy podłącze oba prędkość oscyluje w granicach 13-26km/h. Aby ustabilizować pomiar, wyciągam średnią z 4 pomiarów.
    treść kodu:
    #include <avr/io.h>
    #include <stdlib.h> 
    #include <inttypes.h>
    #include <util/delay.h>
    #include <hd44780.c>
    
    static void lcd(unsigned long int a)
    {
        signed char i;
    	char str1[12]="------------";
       
    /* Zamiana 32 bitowej liczby bez znaku 
       na ciąg znaków ASCII */    
        for(i=12; i>=3; a/=10 ,i--) 
                    str1[i] = a % 10 +'0';
    
    /* Ustawia kursor w pierwszej kolumnie
       pierwszego wersza */    
        LCD_GoTo(0,0);
    
    /* Wysyła do wyświetlacza ciąg znaków z 
       tablicy str1 */
    LCD_WriteText(str1);
    }
    
    
    
    
    
    int main(void)
    {
    int wynik,i=0,przepelnienie=0,pomiar1,pomiar2,pomocnik1,pomocnik2,z;
    int ppomocnik1,ppomocnik2,ppomiar1,ppomiar2,a,b;
    double sek=0,min=0,godz=0;
    double predkosc1,predkosc2,predkosc4,predkosc3,droga,czas,predsum;
    double puls1,puls2,puls3,puls4,pulssum,wwynik,cczas; 
    char zmienna[10],zzmienna[10],sekundy[2],minuty[2],godziny[2],data[6];
    	
    	DDRC  = 0x00;
    	PORTC = 0x07;	
    	DDRB |= (1 <<0); // Ustaw jako wyjście LED DDRC=0x00;
    	TCCR1B |= (1 <<WGM12); // timer Konfiguracja 1 dla trybu CTC 
    	OCR1A = 15624; // Ustaw wartość CTC porównać do 1Hz 1MHz AVR zegar, z prescaler z 64 
    	TCCR1B |= ((1 <<CS10) | (1 <<CS11));	 // Start timer na Fcpu/64 
    
    
    
    
    
    LCD_Initalize();
    LCD_Clear();
    
    	
    
    while(1)
    {
          if (TIFR & (1 <<OCF1A)) 
          {
            PORTB ^= (1 <<0); // Włącz LED 
    		przepelnienie++;// wyczyścić flagę CTC (pisanie logiki jednego do zestawu flag czyści go) 
    		TIFR = (1 << OCF1A);
    
    
    
    
          }
    	   
    	   if(!(PINC & 0x01))
    	  
    	  
    	  	if(i==1){
    
     
    		pomiar2=TCNT1;
    		pomocnik2=przepelnienie;
    		wynik=(((pomocnik2-pomocnik1)*15624)+(pomiar2-pomiar1));
    		i=0;
    
    		droga=2*3,1415926535*2.144;//obwod kola
    		czas=(wynik*0.000064004);	//czas zmierzony/ilosc impulsow na sek
    		predkosc4=predkosc3;
    		predkosc3=predkosc2;
    		predkosc2=predkosc1;
    		predkosc1=(droga/czas);
    		
    		
    		predsum=(predkosc1+predkosc2+predkosc3+predkosc4)*0.25;
    		dtostrf(predsum,5,2,zmienna);
    		strcat(zmienna," kmph");
    		LCD_GoTo(1,0);
    		LCD_WriteText(zmienna); 
    		
    
    	}else{
    
    		pomiar1=TCNT1;
    		pomocnik1=przepelnienie;
    		i++;
    		}
    	
    	while(!(PINC & 0x01)) {}
    
    	  
    
    if(!(PINC & 0x02))
    	  
    	  
    	  	if(z==1){
    
     
    		ppomiar2=TCNT1;
    		ppomocnik2=przepelnienie;
    		wwynik=(((ppomocnik2-ppomocnik1)*15624)+(ppomiar2-ppomiar1));
    		z=0;
    		ppomiar1=0;
    		ppomiar2=0;
    		ppomocnik1=0;
    		ppomocnik2=0;
    		cczas=(wwynik*0.000064004);
    		
    		puls4=puls3;
    		puls3=puls2;
    		puls2=puls1;
    		puls1=(60/cczas);			//ilosc uderzen serca na min.
    		pulssum=(puls1+puls2+puls3+puls4)*0.25;
    		dtostrf(pulssum,5,2,zzmienna);
    		strcat(zzmienna," bpm");
    		LCD_GoTo(1,1);
    		LCD_WriteText(zzmienna); 
    		
    	}else{
    
    		ppomiar1=TCNT1;
    		ppomocnik1=przepelnienie;
    		z++;
    
    		  }
    
    	while(!(PINC & 0x02)) {}
    
    
    	
    }
    return 0;
    }


    oraz układ:
    [atmega8][c] Prędkościomierz i pulsometr.

    napięcia do lcd i uC narazie nie podłączone, w proteus'ie nie jest to wymagane do działania układu.
  • #2 8172207
    szelus
    Poziom 34  
    Dla mnie wydaje się być dosyć oczywiste, że jeżeli sygnały na dwa wejścia przychodzą jednocześnie i niezależnie, to też jednocześnie, a nie po kolei, należy je obsługiwać. Zatem cała idea Twojego programu jest niepoprawna.

    Poprawnie, to w programie powinny się (z grubsza) jednocześnie i niezależnie wykonywać trzy rzeczy:
    - odczyt czujnika nr 1 (pomiar prędkości)
    - odczyt czujnika nr 2 (pomiar pulsu)
    - wyświetlanie
    Jak bardzo "z grubsza" to zależy od parametrów impulsów - minimalnego czasu trwania i okresu powtarzania.

    Tak jak teraz masz, to kiedy czekasz np. na koniec pierwszego impulsu (albo zakończenie wyświetlania) to nie zauważasz zachodzących w międzyczasie zmian (impulsów) na drugim wejściu.

    Niepotrzebnie sobie chyba utrudniłeś, podłączając te czujniki do portu C zamiast do wejść INT0/INT1 aby wykorzystywać przerwania do pomiaru, a w pętli głównej robić wyświetlanie.

    Dodatkowo, na schemacie masz niepoprawnie podłączony wyświetlacz (pin R/W do potencjometru regulacji kontrastu? 8-O ).
  • #3 8172432
    myszarafa
    Poziom 10  
    faktycznie masz racje, zacznę pisać program zgodnie z przerwaniami na t0 i t1. Czy w przypadku gdy będzie wykonywać się przerwanie na t0 i powstanie impuls na t1, nie będzie konfliktu ? Impulsy będą przychodzić z małą częstotliwością max. 8Hz.

    Co do schematu, jak już mówiłem proteus nie wymaga poprawnego połączenia, więc tym się nie zajmowałem.
    pozdro.
  • #4 8172459
    gaskoin
    Poziom 38  
    myszarafa napisał:
    Czy w przypadku gdy będzie wykonywać się przerwanie na t0 i powstanie impuls na t1, nie będzie konfliktu ? Impulsy będą przychodzić z małą częstotliwością max. 8Hz.


    nie ponieważ po skończeniu wykonywania obsługi przerwania procesor wraca do swojej dalszej pracy. To tak jak byś sprzątał w pokoju i nagle mama krzyczy, że obiad. Jesz obiad i sprzatasz dalej :)
  • #5 8172505
    szelus
    Poziom 34  
    Zazwyczaj podczas obsługi przerwania przyjmowanie kolejnych przerwań jest zablokowane, tzn. jeżeli sam nie będziesz jawnie zezwalał w obsłudze przerwania na przyjmowanie przerwań.
    Przerwania zgłoszone w tym czasie zostaną obsłużone po zakończeniu obsługi bieżącego. Będzie działało poprawnie, o ile czas obsługi będzie wystarczająco krótki, a tu nie widzę żadnego problemu.

    P.S. W życiu, nie jak w symulatorze, mogą pojawiać się zakłócenia, np. od drgań styków kontaktronu odczytującego obroty. Ale z tym powinieneś się uporać ignorując impulsy (przerwania) krótsze od minimalnych oczekiwanych.
  • #6 8172522
    utak3r
    Poziom 25  
    Co do kontaktronu, to niedawno robiłem taki układ i bałem się o drgania (kontaktrony mają rzeczywiście beznadziejne styki). Jak się jednak okazało, w przypadku kontaktronu i obracającego się koła z częstotliwością kilku Hz - problem nie istnieje w ogóle. Zero drgań styków :)

    Niemniej, warto to po podłączeniu do rzeczywistego układu (roweru, nie przycisku symulującego) sprawdzić.
  • #7 8172890
    gaskoin
    Poziom 38  
    utak3r napisał:
    Co do kontaktronu, to niedawno robiłem taki układ i bałem się o drgania (kontaktrony mają rzeczywiście beznadziejne styki). Jak się jednak okazało, w przypadku kontaktronu i obracającego się koła z częstotliwością kilku Hz - problem nie istnieje w ogóle. Zero drgań styków :)

    Niemniej, warto to po podłączeniu do rzeczywistego układu (roweru, nie przycisku symulującego) sprawdzić.


    robiłem kiedyś coś takiego na projekt z systemów mikroprocesorowych. Kontaktron przy wejściu w pole magnetyczne przesyłał 70-200 impulsów (czasem 20, różnie :P) rozwiązaniem może być po prostu równoległy kondensator który ograniczył liczbę wykrywanych impulsów do 1 (bardzo rzadko kiedy 2)
  • #8 8199803
    myszarafa
    Poziom 10  
    Dzięki Panowie za pomoc, poradziłem sobie z konfliktem sygnałów. Zastosowałem 2 przerwania zewnętrzne które odczytują wartość licznika, oraz 1 przerwanie od przepełnienia w którym inkrementuję odliczanie sekundy. Pozostało jeszcze wysłać zebrane dane do jakieś pamięci np. karta SD. W razie pytań będę pisał tutaj.

    #include <avr/io.h>
    #include <stdlib.h> 
    #include <avr/interrupt.h> 
    #include <util/delay.h>
    #include <hd44780.c>
    #include <avr/signal.h>
    #define F_CPU 1000000L
    	
    	int sek,dsek,min,dmin,godz,dgodz,przepelnienie2;
    	int i,b;
    	double czas,cczas,droga,predkosc,puls,srednia[5];
    	char zmienna[10],zzmienna[10];
    
    
    volatile long int przepelnienie,waga,waga2,wwaga,wwaga2,z=0;
    volatile long int pomiar,pomiar2,flaga,ppomiar,ppomiar2,a=0;;
    
    
    void menu1(void){
    		LCD_GoTo(39,1);
    		dtostrf(sek,1,0,zzmienna);
    		LCD_WriteText(zzmienna);
    		LCD_GoTo(38,1);
    		dtostrf(dsek,1,0,zzmienna);
    		LCD_WriteText(zzmienna);
    		LCD_GoTo(37,1);
    		LCD_WriteText(":");
    		LCD_GoTo(36,1);
    		dtostrf(min,1,0,zzmienna);
    		LCD_WriteText(zzmienna);
    		LCD_GoTo(35,1);
    		dtostrf(dmin,1,0,zzmienna);
    		LCD_WriteText(zzmienna);	
    		LCD_GoTo(34,1);
    		LCD_WriteText(":");	
    		LCD_GoTo(33,1);
    		dtostrf(godz,1,0,zzmienna);
    		LCD_WriteText(zzmienna);
    		LCD_GoTo(32,1);
    		dtostrf(dgodz,1,0,zzmienna);
    		LCD_WriteText(zzmienna);
    		
    		LCD_GoTo(22,1);
    		dtostrf(droga,4,1,zzmienna);
    		LCD_WriteText(zzmienna);
    		LCD_WriteText("m");
    
    
    		LCD_GoTo(22,0);
    		dtostrf(predkosc,4,1,zzmienna);
    		LCD_WriteText(zzmienna);
    		LCD_WriteText("km/h");
    		
    		LCD_GoTo(2,1);
    		dtostrf(puls,3,0,zzmienna);
    		LCD_WriteText(zzmienna);
    		LCD_WriteText(" bps");
    		}
    
    SIGNAL(SIG_INTERRUPT0) 
    {
    	if(z==0){
    			z=1;
    			pomiar=TCNT1;
    			waga=przepelnienie;
    			flaga++;
    
    	}else{
    			z=0;
    			pomiar2=TCNT1;
    			waga2=przepelnienie;
    			flaga++;
    		}
    }
    
    SIGNAL(SIG_INTERRUPT1) 
    {
    	if(a==0){
    		ppomiar=TCNT1;
    		wwaga=przepelnienie;
    		a++;
    	}else{
    		a=0;
    		ppomiar2=TCNT1;
    		wwaga2=przepelnienie;		
    		}
    }
    
    ISR(TIMER1_OVF_vect)
    {
       przepelnienie++; //zmienna, sygnalizujaca uplyw sekundy
       TCNT1  = 49911;
    }
    
    
    int main(void)
    {
    	int menu=2;	
    
    	TCCR1B |= ((1 <<CS10) | (1 <<CS11));	 // Start timer na Fcpu/64 
    	GIMSK = _BV(INT0)|_BV(INT1);	  			//przerwania zew na wej int0 i int1
    	MCUCR = _BV(ISC01)|_BV(ISC00)|_BV(ISC10)|_BV(ISC11);	//ustawienie przerwania od zbocza 
    	TIMSK |= (1 << TOIE1);		//ustawienie przerwania od przepelnienia
    	TCNT1  = 49911;		//wart poczatkowa timera
    	sei();				//wlaczenie przerwan
    
    DDRC=0x00;
    LCD_Initalize();
    LCD_Clear();
    sek=-1;
    dsek=0;
    min=0;
    dmin=0;
    godz=0;
    dgodz=0;
    	
    
    
    while(1)
    {
    
    
    		droga=2.205*flaga;			//droga zwiekszana za kazdym razem gdy na wej. int0 pojawi sie zbocze
    		czas=abs((pomiar+(waga*15624))-(pomiar2+(waga2*15624)))*0.000064004;	//obliczenie czasu miedzy zboczami, wyrazone w sek
    		if(czas>0.01)				//zab przed dzieleniem przez 0
    		predkosc=(2.205/czas)*3.6;
    			else	predkosc=0;
    		cczas=abs((ppomiar+(wwaga*15624))-(ppomiar2+(wwaga2*15624)))*0.000064004;	//obliczenie czasu miedzy zboczami, wyrazone w sek
    		if(cczas>0.01)				//zab przed dzieleniem przez 0
    		puls=60/cczas;
    			else	puls=0;
    		if(!(przepelnienie-przepelnienie2)){		//jezeli roznica miedzy w k-1 i k, dodaj sekunde
    		sek++;
    		przepelnienie2++;
    		if(sek==10){
    			sek=0;
    			dsek++;
    			
    			if(dsek==6){
    			dsek=0;
    			min++;
    			if(min==10){
    			min=0;
    			dmin++;
    			if(dmin==6){
    			dmin=0;
    			godz++;
    			if(godz==10){
    			godz=0;
    			dgodz++;
    			if(dgodz==2&&godz==4){
    			godz=0;
    			dgodz=0;
    			}}}}}}}	//calkowity czas treningu
    			
    			menu1();	//wyswietlenie danych na lcd
    	
    }
    return 0;
    }
    

    [atmega8][c] Prędkościomierz i pulsometr.
  • #9 8200344
    Faber33
    Poziom 16  
    Witam. Chciałbym się dowiedzieć w jakim programie kolega wykonuje taką symulację jak na screenie powyżej :)????
  • #10 8200875
    PO.
    Poziom 20  
    Używasz starych deklaracji przerwań, obecnie ISR oraz nazwy z datasheeta.
  • #11 8201378
    myszarafa
    Poziom 10  
    A jest jakaś różnica w przypadku używania starych/nowych deklaracji ? przerabiałem tutorial na avrfreaks.net i tam takich używali.

    Co do programu to używam Proteus do symulacji i WinAVR do kompilacji.
  • #12 8201864
    PO.
    Poziom 20  
    Bo to właśnie stary tutorial chyba? Dopóki kompilator łyka to nie ma różnicy, jak przestanie będzie problem :) .
REKLAMA