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

[Atmega32][C] Pomiar obciązenia silnika dc

sebke 21 Maj 2009 22:02 2810 10
  • #1 6558866
    sebke
    Poziom 10  
    Witam, tak jak w temacie chce zrobić pomiar obciążenia silnika prądu stałego na Atmega32 z wykorzystaniem 10-bitowego przetwornika ADC w jaki jest wyposażony ten uC. Główny problem to nie bardzo wiem jak napisać program do pomiar napięcia na rezystorze obciążającym.

    Pomiar obciążenia silnika elektrycznego polega to na tym ,że silnik łączy się prądnicą i w trakcie obciążania prądnicy rejestruje się prąd i napięcie obciążenia prądnicy . Moc wyliczoną z tych parametrów należy powiększyć o odpowiednią wartość uwzględniającą sprawność prądnicy i jest to moc na wale silnika.
    np. jeżeli sprawność prądnicy wynosi 97% , to moc na wale silnika będzie równa P=UxIx1.03 [W] gdzie U,I to prąd i napięcie obciążenia prądnicy.

    A teraz jak chce to zrealizować:

    Pomiar bedzie odbywał się za pomocą układu który znalazłem a elektrodzie jakiś czas temu.

    [Atmega32][C] Pomiar obciązenia silnika dc


    Dzięku temu będę miał pomiar napięcia, znając jego wartość i mają wartość rezystora (w tym przypadku 100ohm 1%) wyliczę prąd. Podstawiając do wzoru wartośc obciązenia będę wyświetlał na LCD(2x16)

    Wydaje mi sie ze koncepcja rozwiązania tego przypadku jest dobra.

    Z wykonaniem tego od strony technicznej nie będzie problemu gorzej jest od strony programowej i w tej kwestii prosiłbym o pomoc. Wszelkie wskazówki mile widziane :)
  • #2 6559494
    dawid512
    Poziom 32  
    Najpierw zajrzyj do datasheeta a dokładniej do działu o ADC. Spróbuj sklecić jakiś kod, potem postaramy się coś podpowiedzieć.
  • #3 6563142
    sebke
    Poziom 10  
    Witam

    Po wgłębieniu się w datasheeta napisałem taki kod, narazie prosty ale jak by działał
    #define F_CPU 8000000L
    #include <avr/interrupt.h> 
    #include <avr/io.h>
    #include <avr/delay.h>
    
    unsigned int pomiar;
    
    
    
    void Inicjalizacja(void) 
    { 
    
    DDRC = 0xff; 
    PORTC= 0x00; 
    
    
    ADMUX |= _BV(REFS0); 
    // Wybranie sposobu zapisu wyniku z wyrównaniem do lewej (osiem starszych bitów wyniku w rejestrze ADCH) 
    ADMUX |= _BV(ADLAR); 
    // Wybór kanału wejścia - PC3 (ADC3) 
    ADMUX |= _BV(MUX1)|_BV(MUX0); 
    // Zezwolenie na konwersję 
    ADCSRA |= _BV(ADEN); 
    // Wybranie częstotliwości dla taktowania przetwornika 
    
    ADCSRA |= _BV(ADPS1); 
    ADCSRA |= _BV(ADPS2); //fosc/64= 125kHz z tego co czytałem to powinno sie to zawierać w granicach 50-200kHz
    }
    
    int main(void)
    {
     Inicjalizacja();
    
    
        PORTC |= _BV(0); //dioda jeden zgaszona 
        PORTC |= _BV(1); //dioda dwa 
        _delay_ms(60); 
        PORTC &= ~_BV(1); //zaświeć 
        PORTC &= ~_BV(0); //zaświeć 
        _delay_ms(60); 
        
        while(1) 
        { 
            ADCSRA |= _BV(ADSC); 
            while( ADCSRA & _BV(ADSC)) {}; 
    
    
            pomiar=ADCH; 
            if (pomiar > 64) 
            { 
            PORTC |= _BV(0); 
            PORTC &= ~_BV(1); 
            
            } else 
            { 
            PORTC &= ~_BV(0); 
            PORTC |= _BV(1); 
            
            } 
            _delay_ms(50); 
        }
    
    }


    Program działa na takiej zasadzie ze jesli wartość napięcia będzie wyższa niż 64 to świeci się jedna dioda a jeśli niższa to druga. Teraz pasowało by te wartości wyświetlić na wyświetlaczu LCD.

    Tak wyglada sprawdzony kod do obsługi lcd:

    /*
    Piny/Pins:
    PD1 - RS
    PD2 - E
    PD3 - D4
    PD4 - D5
    PD5 - D6
    PD6 - D7
    */
    
    #define DDR_DB4 DDRD
    #define PORT_DB4 PORTD
    #define DB4 PD3
    
    #define DDR_DB5 DDRD
    #define PORT_DB5 PORTD
    #define DB5 PD4
    
    #define DDR_DB6 DDRD
    #define PORT_DB6 PORTD
    #define DB6 PD5
    
    #define DDR_DB7 DDRD
    #define PORT_DB7 PORTD
    #define DB7 PD6
    
    
    #define DDR_RS DDRD
    #define PORT_RS PORTD
    #define RS PD1
    
    #define DDR_E DDRD
    #define PORT_E PORTD
    #define E PD2
    
    
    #define SET_B1 PORT_B1 |= _BV(B1)
    #define CLR_B1 PORT_B1 &= ~_BV(B1)
    
    #define SET_B2 PORT_B2 |= _BV(B2)
    #define CLR_B2 PORT_B2 &= ~_BV(B2)
    
    #define SET_B3 PORT_B3 |= _BV(B3)
    #define CLR_B3 PORT_B3 &= ~_BV(B3)
    
    #define SET_B4 PORT_B4 |= _BV(B4)
    #define CLR_B4 PORT_B4 &= ~_BV(B4)
    
    #define SET_DB4 PORT_DB4 |= _BV(DB4)
    #define CLR_DB4 PORT_DB4 &= ~_BV(DB4)
    
    #define SET_DB5 PORT_DB5 |= _BV(DB5)
    #define CLR_DB5 PORT_DB5 &= ~_BV(DB5)
    
    #define SET_DB6 PORT_DB6 |= _BV(DB6)
    #define CLR_DB6 PORT_DB6 &= ~_BV(DB6)
    
    #define SET_DB7 PORT_DB7 |= _BV(DB7)
    #define CLR_DB7 PORT_DB7 &= ~_BV(DB7)
    
    #define SET_E PORT_E |= _BV(E)
    #define CLR_E PORT_E &= ~_BV(E)
    
    #define SET_RS PORT_RS |= _BV(RS)
    #define CLR_RS PORT_RS &= ~_BV(RS)
    
    #define LCD_X 16
    #define LCD_Y 2
    
    
    
    union 
    	{
    	int tds;
    	char nds[2];
    	}	ds;
    
    char buf[6]; 
    
    void out_nibble(char x)
    	{
    	CLR_DB4;
    	CLR_DB5;
    	CLR_DB6;
    	CLR_DB7;
    	if(x & _BV(0)) SET_DB4;
    	if(x & _BV(1)) SET_DB5;
    	if(x & _BV(2)) SET_DB6;
    	if(x & _BV(3)) SET_DB7;
    	}
    
    
    void write_to_lcd(char x)
    	{
    	SET_E;
    	out_nibble(x >> 4);
    	CLR_E;
    	SET_E;
    	out_nibble(x);
    	CLR_E;
    	_delay_ms(1);
    	
    	
    	}
    
    void delay(int useconds)
    	{	
    	int s;
    	useconds = useconds;
    	for (s=0; s<useconds;s++);
    	}
    
    void write_command(char x)
    	{
    	CLR_RS;
    	write_to_lcd(x);
    	}
    
    void write_char(char x)
    	{
    	SET_RS;
    	write_to_lcd(x);
    	}
    
    void write_text(char * s)
    	{
    	while(*s)
    		{
    		write_char(*s);
    		s++;
    		}
    	}
    
    void lcd_init(void)
    	{
    	DDR_DB4 |= _BV(DB4);
    	DDR_DB5 |= _BV(DB5);
    	DDR_DB6 |= _BV(DB6);
    	DDR_DB7 |= _BV(DB7);
    	DDR_E |= _BV(E);
    	DDR_RS |= _BV(RS);
    
    	
    	_delay_ms(15);
    	CLR_E;
    	CLR_RS;
    	char i;
    	for(i = 0; i < 3; i++)
    		{
    		SET_E;
    		out_nibble(0x03);
    		CLR_E;
    		_delay_ms(5);
    
    		}
    	SET_E;
    	out_nibble(0x02);
    	CLR_E;
    	_delay_ms(1);
    	write_command(0x28); // interfejs 4-bity, 2-linie, znak 5x7
    	write_command(0x08); // wyłącz LCD, kursor i miganie
    	write_command(0x01); // czyść LCD
    	write_command(0x06); // bez przesuwania w prawo
    	write_command(0x0C); // włącz LCD, bez kursora i mrugania
    	}
    
    
    void LCD_xy(uint8_t x, uint8_t y)
    	{
    	switch(y)
    		{
    		case 1: y=0x40; break;
    		case 2: y=0x14; break;
    		}
    	write_command(0x80+y+x);
    	}
    
    void lcdxy(uint8_t x, uint8_t y)
    	{
    	switch(y)
    		{
    		case 1: y=0x40; break;
    		case 2: y=0x14; break;
    		}
    	write_command(0x80+y+x);
    	}
    void LCD_clr(void)
    	{
    	write_command(0x01);
    	_delay_ms(1);
    	
    	LCD_xy(0,0);
    	}
    
  • #4 6588560
    sebke
    Poziom 10  
    Juz trochę nad tym siedze i utknąłem nad wyświetleniem wyniku napięcia na LCD

    #define F_CPU 8000000L
    #include <avr/interrupt.h> 
    #include <avr/io.h>
    #include <util/delay.h>
    #include <stdlib.h>
    #include "lcd.h"
    
    unsigned int pomiar; 
    unsigned int wynik, i;	
    
    char buffer_n[8];
    
    void Init_ADC(void) 
    { 
    
    ADCSRA = _BV(ADEN)| _BV(ADSC) | _BV(ADIE) | 0x07; 
    	
    ADMUX |= (1<<REFS1)|(1<<REFS0); // Wybranie sposobu zapisu wyniku z wyrównaniem do lewej 
    					//(osiem starszych bitów wyniku w rejestrze ADCH) 
    }
    
    
    
    
    //=============================================================================
    int main(void)
    {
    //DDRC = 0xff; 
    //PORTC= 0x00;
    
    DDRD=0xFF; 
    DDRC=0x00;
    PORTC=0x00; 
    
    
     Init_ADC();
     LCD_init();
     write_text("TEST");
    
     while(1) 
        { 
    		// Wyzerowanie flagi naciśnięcia klawisza
    			wynik=0;
    			i=9;
    			while(i)
    			{	
    				ADCSRA |= _BV(ADSC);         // Rozpoczęcie przetwarzania
    				
    				while(bit_is_set(ADCSRA,ADSC))	// Oczekiwanie na zakończenie przetwarzania
    				{};	
    				pomiar=ADCH;			     // Zapisanie starszych 8 bitów wyniku konwersji do
    											// zmiennej "pomiar"
    				wynik=wynik+pomiar;			 // Sumowanie wyników pomiarów dokonywanych w serii
    				i--;
    			}
    			wynik=wynik/9;		// Wyliczenie średniej 
    			//LCD_clr();         // Czyszczenie wyświetlacza LCD
    			write_text("Wynik pomiaru: \n ");    
    			utoa(wynik, buffer_n, 10);  // Konwersja liczby unsigned int do asci
    			
    			LCD_xy(0,1);
    			write_text(buffer_n);          // Wysłanie na ekran LCD wyniku konwersji
    			
    	}
    }
    
    


    Co prawda wyświetla mi jedną cyfre z przediału (0-3) ale nie bardzo ma się to do faktycznego stanu. Moze ktoś wie jak to rozwiązać?
  • #5 6588793
    PiotrPitucha
    Poziom 34  
    Witam
    Twój układ jest poprawny ale do celu pomiaru prądu na silniku musisz go zmodyfikować, pomiar prądu jest mocno zaszumiony i wartości kondensatorów w filtrze nie będą wystarczające.
    Pierwsze co mogę zaproponować to dziesięciokrotne zwiększenie rezystorów w sprzężeniu i filtrze na wejściu, kondensatory też dałbym większe, obecnie 1uF możesz dostać w SMD więc nie będzie kłopotów z wymiarami.
    Druga sprawa to wzmacniacz, ten zaproponowany nie jest RtoR więc w zakresie niskich prądów nic nie zmierzysz, ponadto nie jest on zbyt stabilny, jeśli chcesz mierzyć dokładnie to proponuję MCP607 Microchipa.
    Piotr
  • #6 6589087
    Dr.Vee
    VIP Zasłużony dla elektroda
    PiotrPitucha napisał:
    Druga sprawa to wzmacniacz, ten zaproponowany nie jest RtoR więc w zakresie niskich prądów nic nie zmierzysz, ponadto nie jest on zbyt stabilny

    RtoR nie ma tu nic do rzeczy, a jeśli już, to raczej przy pomiarze wysokich prądów.

    sebke: musisz podać więcej parametrów, tj. min i max prąd, zakładana precyzja, dokładność i częstotliwość pomiaru itd.

    Program wygląda +/- OK.

    Pozdrawiam,
    Dr.Vee
  • #7 6589189
    PiotrPitucha
    Poziom 34  
    Witam
    RtoR jak najbardziej ma wpływ i to w zakresie małych napięć, przy pojedynczym zasilaniu 5V najmniejsze napięcie jakie według PDFa może pojawić się na wyjściu LM358 to 5-20mV, wzmacniacz zacznie pracować dopiero jak na rezystorze pomiarowym pojawi się takie napięcie, a 20mV na 0,1Ohm to już 200mA, i podejrzewam że na granicy tego napięcia liniowość jest żadna, do tego dodajmy jeszcze napięcia niezrównoważenia i wyjdzie nam byle jaki układ, dla odmiany w zakresie dużych prądów wyjście wzmacniacza może pracować koło 2,5V ( dla napięcia referencyjnego tej wartości w procesorze ) czyli nie mamy ograniczenia liniowości od góry dla zasilania 5V i jak najbardziej pracujemy w liniowym zakresie.
    Pozdrawiam
  • #8 6589431
    Dr.Vee
    VIP Zasłużony dla elektroda
    Faktycznie, nie zwróciłem uwagi na to 5-20mV.

    Pozdrawiam,
    Dr.Vee
  • #9 6591490
    sebke
    Poziom 10  
    Witam

    Dziekuje za odpowiedź.

    Wiem ze tym nie mierze pradu narazie ale od czegoś musiałem zacząć.
    Pomiar prądu min 90mA do 1A większych prądów nie przewiduje nawet przy całkowicie obciązonym(zatrzymamym) silniku. Precyzja wiadomo kazdy chce jak najlepszą ale mi wystarczy na poziomie +/-5mA.

    Pomiar wystarczy co 0,5 sekundy, częstsze sprawdzanie nie wydaje mi sie potrzebne.

    PiotrPitucha: co do wymiarów nie mam jakiś ograniczeń bedę miał tyle miejsca ile będę potrzebował.
  • #10 6592746
    PiotrPitucha
    Poziom 34  
    Witam
    Jeśli chcesz od 90mA mieć dokładny pomiar to polecam MCP607 Microchipa, robiłem na nim kilkaset dokładnych urządzeń pomiarowych i mogę potwierdzić jego poprawną pracę z praktyki.
    Myślę że jeśli chcesz poprawić pracę wzmacniacza w bardzo niskim zakresie napięć to wyjście jego podłącz do masy przez opornik rzędu 4,7kOhm.
    Co do filtrowania to R1 R2 możesz spokojnie zwiększyć 10 razy, podobnie pojemności C1 C3, co do R3 to byłbym ostrożny, teoretycznie jego zwiększenie może poprawić filtrację ale raczej go nie ruszaj.
    Piotr
  • #11 6605536
    sebke
    Poziom 10  
    Witam

    PiotrPitucha: tym układem to się zajmę później teraz chciałbym zeby mi wartości pokazywało zgodne z rzeczywistością.

    #define F_CPU 8000000L
    #include <avr/interrupt.h> 
    #include <avr/io.h>
    #include <util/delay.h>
    #include <stdlib.h>
    #include "lcd.h"
    
    unsigned int pomiar; 
    unsigned int wynik,wynik1, i;	
    
    char buffer_n[18];
    
    void Init_ADC(void) 
    { 
    
    ADCSRA = _BV(ADEN)| _BV(ADSC) | _BV(ADIE) | 0x07 ; //
    
    ADMUX = _BV(REFS1)|_BV(REFS0); // Wybranie sposobu zapisu wyniku z wyrównaniem do lewej 
    					//(osiem starszych bitów wyniku w rejestrze ADCH) 
    					ADMUX=0x01;
    				//	ADCSRA=0x00;
    }
    
    
    
    
    //=============================================================================
    int main(void)
    {
    DDRD=0xFF; 
    DDRC=0x00;
    PORTC=0x00; 
    
    
     
     LCD_init();
     write_text("TEST");
     _delay_ms(100);
    ;
     while(1) 
        { 
    	//	wynik=0	;
    			i=3;
    			while(i)
    			{	
    				Init_ADC();
    				ADCSRA |= _BV(ADSC);         // Rozpoczęcie przetwarzania
    				
    				while(bit_is_set(ADCSRA,ADSC))	// Oczekiwanie na zakończenie przetwarzania
    				{};	
    				pomiar=ADCH;			     // Zapisanie starszych 8 bitów wyniku konwersji do
    											// zmiennej "pomiar"
    				wynik=wynik+pomiar;			 // Sumowanie wyników pomiarów dokonywanych w serii
    				i--;
    			}
    			 
    			wynik1= (int)(wynik/3)/4;
    			LCD_xy(0,0);        // Czyszczenie wyświetlacza LCD
    			write_text("Wynik pomiaru: ");
    			//LCD_clr();    
    			utoa(wynik1, buffer_n, 10);  // Konwersja liczby unsigned int do asci
    	
    			LCD_xy(0,1);
    			write_text(buffer_n);
    			_delay_ms(1);          // Wysłanie na ekran LCD wyniku konwersji
    			
    	}
    	
    }
    


    bo te wartości które otrzymuje nie są takie jak wskazuje woltomierz.

    Prosiłbym o podpowiedź co jest nie tak ?
REKLAMA