-         

Ergebnis 1 bis 9 von 9

Thema: ATMEGA32 ADC Beschaltung für diff. +20dB Mesung

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150

    ATMEGA32 ADC Beschaltung für diff. +20dB Mesung

    Anzeige

    Hi,

    Für die Beleuchtung meines Bots wollt ich ne schöne Cree mit konstantstrom betreiben, aber ich habe ein Problem:
    Die Spannung über meinem 0,51Ohm Messwiderstand welcher sich oberhalb des PWM gesteuerten Mosfets befindet wird von max. 1A durchflossen. Es ist also eine minimal wellige Spannung zwischen 0 und 0,5V über dem Widerstand zu messen. Problem ist nur, dass der Mosfet gegen masse schaltet und demzufolge das Potential am Messwiderstand im 20kHz takt um ca 7,4V angehoben wird. Einfach ADC0 und ADC1 über den Widerstand anzuschließen funzt nicht, da lösen die Überspannungsschuzdioden aus.
    Muss ich also zwei Spannungsteiler (vor und hinter dem Messwiderstand gegen masse) verwenden, um die Spannungen zunächst in das richtige Potential zu verschieben und um dann zwischen den zwei Spannungsteilern differentiell zu messen?
    Oder geht das auch einfacher?
    Wo müssen Schutz oder Ausgleichskondensatoren bzw Antialiasingfilter hin, wenn ich differentiall messen möchte?

    Vielen Dank für eure Tips!
    mfg Sirvivor
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken konstantquelle.jpg  
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150

    Idee

    Also mein oben beschriebener Löungsvorschlag sieht so aus, funktioniert das so, wenn ich nastelle des kanal 2 meine ADC0 und ADC1 eingänge anschließe, stimmen die dimensionen der Bauteile so in etwa?

    mfg WarChild alias "Sirvivor" *g*
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken l_sungsansatz.jpg  
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150
    hmmm...

    Eigentlich wollte ich keinen Monolog halten, aber nun denn:

    Ich hab die schaltung heute getestet und alles funktioniert wunderbar. Ich verliere durch den zusätzlichen Spannungsteiler die halbe ADC Auflösung, weil ich aufgrund anderer Messungen, die ich nebenher mit AREF mache nicht die Vergleichsquelle wechseln möchte.

    Nun aber zu meinem jetzt auftretendem Problem: Wenn ich das PWM auf 0 setze, und somit die Lampen eigentlich ausschalte, fließt durch die insgesammt vier Spannungsteiler, weil ich mit zwei Konstantstromquellen zwei Crees betreibe ein nicht unerheblicher Strom. Die haben einen Ersatzwiderstand von (2*10kOhm)/4=5kOhm. Bei 8,4V fließen also knapp 2mA "Leckstrom". Das ist sehr hübsch sichtbar. Wie groß kann ich die Widerstände maximal wählen, ohne dass das ADC Messergebnis verfälscht wird? am liebsten würde ich mit 100kOhm Teilen, aber im Tutorial steht, dass die zu mesende Quelle eine Impedanz von weinger als 20kOhm besitzen sollte. Da bleibt also nicht viel spiel. Wenn ich dann das signal noch mehr Puffern muss, damit der ADC genug Ladung bekommt, dann fürchte ich, dass es vor allem im niedrigen Strommessbereich zu hässlichen schwingungen kommt.
    Also das ADC signal korrigiert das PWM Signal der Strom ändert sich, die Spannung am ADC hängt aber aufgrund der hohen Impedanz und großen Kapazität hinterher und wenn die änderung erkannt wird muss stark gegengeregelt werden un dann schwingt es halt.

    bin für tipps offen:

    mfg WarChild
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  4. #4
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Bei der Differentiellen Messung darf der Eingang noch deutlich hochohmiger sein. Da sollten die 100 K schon noch gehen. Nach dem Datenblatt aber auch nicht viel mehr, vermutlich wegen Leckströmen am Eingang. Der Eingang des ADs selber sollte als CMOS Verstärker sehr hochohmig sein.

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150
    vielen Dank!

    Allmählich habe ich alle Probleme im Griff, nur sieht meine Schaltung mittlerweile recht spektakulär aus. Von ursprünglich 40 patzierten Bauteilen habe ich 5 entfernt und 18 hinzugefügt (Luftferdrahtung *g*) sowie 8 zusätzliche Leitungen. Ich denke jetzt ist es Zeit für eine Version 2 des Boards... 8-)

    mfg WarChild
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150

    Erneute Probleme

    Hallo Zusammen,

    lang ist es her, da habt Ihr mir bei meinen ADC Problemen bei der Bike Control V1.0 geholfen, und jetzt bei Version 2.1 steh ich schon wieder auf dem Schlauch.

    Folgendes Problem:
    Ich erzeuge ein 15,6kHz PWM und versorge über zwei Step Down Wandler mit P-FET zweiHochleistungs-LEDs.

    Es Funktioniert alles bis auf dass die gegenkopplung des PWMs duch den ADC mysteriöse Verhaltensmuster aufweist. Solange der Sollstrom unter 500mA (=512 ADC) liegt, wird dieser nur minimal von 10 bis 30 mA erhöht. überschreite ich diesen Punkt wird stark aufgedreht bis zu dem hier abgebildeten Betriebspunkt. Eigenartigerweise stecken in der ADC-Eingangsspannung hohe Peaks obwohl da ein 1,5kHz Tiefpass vorgeschaltet ist. Vielleicht gibt es da ein Masseproblem? habe ich Irgendwas im Code falsch gemacht, weil gerade 512 eine so charakteristische Zahl ist. 0-1A durch den 0,5 Ohm Widerstand entsprechen 0-0.5V mit 10-facher verstärkung und 10 Bit Auflösung ergibt dies bei 5V Referenz genau eine Proportionalität zwischen ADC und Strom von 1 zu 1mA.


    Außerdem erreiche ich bei 16 MHz Controllertakt und 128 prescaler einen 125kHz internen ADC-Takt und bei 3 kanälen mit 8samples und einem verworfenem Messwert eine Frequenz von 320Hz je Kanal. Geht das nicht auch schneller? Derzeit starte ich nach jedem ADC interrupt den ADC neu, geht das nicht auch direkt fortlaufend?

    Code:
    
    // Programm for the Bike-Control V2.0 of S.Heidkamp//
    
    //**************************************************//
    //Includes:											//
    #include <avr/io.h> 								//
    #include <avr/interrupt.h>							//
    #include <math.h>						 			//
    #include <stdint.h>									//
    #include <avr/eeprom.h>								//
    													//
    #define F_CPU		16000000UL						//
    #include <util/delay.h>								//
    //													//
    //**************************************************//
    
    //INPUTS: A7=ADCBAT;A1=CUR1;A2=CUR2;D2=DOWN(INT0);D3=UP(INT1);C3=LOCKED;B2=ALERT(INT2); D1=POWEROFF
    
    volatile uint8_t SOUNDRISE=1;
    volatile uint8_t WARNINGS=0;
    volatile uint16_t COUNTDOWN1=0;
    volatile uint8_t STATUS;
    
    volatile uint16_t UBAT=740;
    volatile uint16_t I1=100;
    volatile uint16_t I2=100;
    volatile uint16_t I_SET=100;
    
    volatile uint8_t ADC_CHANNEL=0;
    volatile uint8_t ADC_COUNT=0;
    volatile uint16_t ADC_TMP=0;
    
    
    volatile uint8_t GREEN_ENABLE=0;
    volatile uint8_t GREEN_TIMER=0;
    volatile uint8_t BACK_ENABLE=0;
    volatile uint8_t BACK_TIMER=0;
    volatile uint8_t SIDES_ENABLE=0;
    volatile uint8_t SIDES_TIMER=0;
    
    //**************************************************//
    //Defines											//
    #define TAKT		16000000UL						//
    #define EEPROM		__attribute__((section(".eeprom")))// new symbol
    //INPUTS											//
    #define LOCKED		PINC & (1 << PC3)				// highactive
    #define OFFSWITCH	!(PIND & (1 << PD1))			// lowactive
    #define VIBRATION	PINB & (1 << PB2)				// highactive
    //OUTPUTS											//
    #define	REDON		PORTC &= ~(1<<PC7);				// lowactive
    #define	REDOFF		PORTC |=  (1<<PC7);				//
    #define REDISON		!(PINC &  (1<<PC7))				//	
    #define	GREENON		PORTC &= ~(1<<PC6);				// lowactive
    #define	GREENOFF	PORTC |=  (1<<PC6);				//
    #define GREENISON	!(PINC &  (1<<PC6))				//
    #define	BACKOFF		PORTB &= ~(1<<PB1);				// highactive
    #define	BACKON		PORTB |=  (1<<PB1); 			//
    #define BACKISON	PINB  &   (1<<PB1)				//
    #define	SIDESOFF	PORTC &= ~(1<<PC4);				// highactive
    #define	SIDESON		PORTC |=  (1<<PC4);				//
    #define SIDESAREON	PINC  &   (1<<PC4)				//
    #define	POWEROFF	PORTD &= ~(1<<PD0);				// highactive
    #define	POWERON		PORTD |=  (1<<PD0);				//
    #define SIRENOFF	TCCR2 &= ~(1<<COM20);			//(OC2)
    #define SIRENON		TCCR2 |=  (1<<COM20);			//
    #define LIGHTSOFF	TCCR1A&= ~((1<<COM1A1)|(1<<COM1B1));//
    #define LIGHTSON	TCCR1A |= (1 << COM1A1)|(1 << COM1B1);//
    #define NEARON		TCCR1A |= (1 << COM1A1);		//(OC1A) PD5
    #define NEAROFF		TCCR1A &=~(1<<COM1A1);			//
    #define FARON		TCCR1A |= (1 << COM1B1);		//(OC1B) PD4
    #define FAROFF		TCCR1A &=~(1<<COM1B1);			//
    #define VIBSENSOFF	GICR &=~(1<<INT2);				//
    #define VIBSENSON	GIFR |= (1<<INTF2);GICR |=(1<<INT2);//
    //STATUS											//
    #define LIGHT 		0								//
    #define ALLCLEAR 	1								//
    #define NOISE		2								//
    #define ATTENTION	3								//
    #define ALERT		4								//
    #define LOWBAT		5								//
    #define SLEEP		6								//
    //BRIGHTNESS
    #define ULOW 		0								//  50 mA
    #define LOW		 	1								// 100 mA
    #define MEDIUM		2								// 350 mA
    #define HIGH		3								// 700 mA
    #define PULSE		4								//1000 mA
    //ADJUSTMENTS										//
    #define ADC_ADJUST	-24								//
    //**************************************************//
     
    void tasks(void)
    {
    }
    
    
    int main(void) 
    { 
    //Initiator
    	
    	DDRA = 0b00000000;								// Output Select
    	DDRB = 0b00000010;								// Back
    	DDRC = 0b11010000;								// RD GN SIDES
    	DDRD = 0b10110001;								
    	
    	PORTD |=  (1<<PD5);								// NEAR- & FAR-Lights are Lowactive so PD5&4 
    	PORTD |=  (1<<PD4);								// should be set to Prevent LEDs from Damage
    	
    	MCUCR |= (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00);//External Interrupts at rising edge
    	MCUCSR |= (1<<ISC2);							// External Interrupt at rising edge
    	GICR |=(1<<INT0)|(1<<INT1);						// Enable Buttons
    
    	POWERON;
    
    
    	cli();
    	//Timer 0										
    	TCCR0 |= (1 << CS00)|(1 << CS02);				// normal mode, prescaler 1024
    	TCNT0 = 256 - 156;								// Timer0 mit 156 neu vorladen: 156*1024/4MHz = 9,984ms ~ 10ms
    	TIMSK |= (1 << TOIE0);							// Timer0 Interrupt freigegeben
    
    	//Timer 1
    	TCCR1A |= (1 << WGM11)|(1 << WGM10);			// 10-Bit PWM mode
    	TCCR1B |= (1 << CS10)|(1 << WGM12);				// prescaler 1, freq. fixed, 16MHz/2^10=15,625kHz 
    	OCR1A = 900;									// Standard 10% as start Value
    	OCR1B = 900;									//
    	TIMSK |= (1 << TOIE1);							// enable overflow interrupt
    
    	//Timer 2
    	TCCR2 |= (1 << CS21)|(1 << WGM21);				// Prescaler 8 ,PWM 1:1, Freq.=16Mhz/(2*OC2+1*Prescaler)
    	OCR2 = 50;
    
    	//ADC
    	ADCSRA|= 0b11101111;							// ON/start/cont./Int.en./prescaler 128 ->125kHz 	
    	ADMUX |= 0b01000111;							// AREF/right/8 unipol./ADC7
    	sei();
    
    	GREENOFF
    	REDOFF
    //Mainprogramm
    	while(1)
    	{
    		
    		if(UBAT==0) REDOFF;
    		while(OFFSWITCH)
    		{
    			LIGHTSOFF;
    			GREEN_ENABLE = 0;
    			BACK_ENABLE = 0;
    			SIDES_ENABLE = 0;
    			BACKOFF;
    			SIDESOFF;
    			SIRENOFF;
    			POWEROFF;}
    
    		//SIRENON;
    		//GREEN_ENABLE = 1;
    		BACK_ENABLE = 1;
    		SIDES_ENABLE = 1;
    		//NEARON;
    		//FARON;
    		//VIBSENSON;
    		LIGHTSON;
    	}
    	
    	return 1; 
    }
    
    SIGNAL(SIG_INTERRUPT0)								//DOWN Button
    {
    	if(I_SET >60) I_SET-=50;
    
    	GIFR |=(1<<INTF0);
    }
    
    SIGNAL(SIG_INTERRUPT1)								//UP Button
    {
    	if(I_SET <950) I_SET+=50;
    
    	GIFR |=(1<<INTF1);
    }
    
    SIGNAL(SIG_INTERRUPT2)								//ALERT signal
    {
    	GIFR |=(1<<INTF2);		
    }
    
    
    SIGNAL(SIG_OVERFLOW0)								//0,01s Timer Unit
    {
    	TCNT0 = 256 - 156;								//new Preload
    
    	if(SOUNDRISE){									//Alternating Noise
    		if(OCR2<180){
    			OCR2+=10;}
    		else{
    			SOUNDRISE = 0;}}
    	else
    	{
    		if(OCR2>30){
    			OCR2-=10;}
    		else{
    			SOUNDRISE = 1;}
    	}
    
    	
    	
    	if(GREEN_ENABLE)								//Green LED Control
    	{
    		GREEN_TIMER++;
    		if(GREEN_TIMER == 0)
    			GREENON;
    		if(GREEN_TIMER == (UBAT>>2))
    			GREENOFF;
    
    	}
    
    	if(BACK_ENABLE)									//Back LED Control
    	{
    		BACK_TIMER++;
    		if(BACK_TIMER == 25)
    			BACKON;
    		if(BACK_TIMER>=50){
    			BACKOFF;
    			BACK_TIMER = 0;}
    	}
    
    	if(SIDES_ENABLE)									//Side LEDs Control
    	{
    		SIDES_TIMER++;
    		if(SIDES_TIMER == 20)
    			SIDESON;
    		if(SIDES_TIMER>=40){
    			SIDESOFF;
    			SIDES_TIMER = 0;}
    	}
    }
    
    SIGNAL(SIG_OVERFLOW1)
    {
    
    }
    
    SIGNAL(SIG_ADC)
    {
    
    	if(ADC_COUNT)
    		ADC_TMP+=ADC;								//akkumulate by dropping first measurement
    
    	ADC_COUNT++;									//increase measurement counter
    	if(ADC_COUNT > 8)								//every 8 measurements
    	{
    		switch(ADC_CHANNEL)							//store value and change channel
    		{
    		case (0):
    			UBAT=(ADC_TMP>>3);
    			ADMUX|= 0b01001001;						// AREF/right/2-CH amp./10*ADC1->0
    			ADC_CHANNEL++;
    			break;
    		case (1):
    			I1=(ADC_TMP>>3);
    			ADMUX|= 0b01001101;						// AREF/right/2-CH amp./10*ADC3->2		
    			ADC_CHANNEL++;
    			if((I_SET+10>I1) && (OCR1A>500)){
    				REDOFF
    				GREENON
    				OCR1A--;}
    			else if((I_SET-10<I1) && (OCR1A<1022)){
    				REDON
    				GREENOFF
    				OCR1A++;}
    			break;
    		case (2):
    			I2=(ADC_TMP>>3);		
    			ADMUX|= 0b01000111;						// AREF/right/8 unipol./ADC7
    			ADC_CHANNEL=0;	
    			if((I_SET+10>I2) && (OCR1B>500)){
    				OCR1B--;}
    			else if((I_SET-10<I2) && (OCR1B<1022)){
    				OCR1B++;}	
    		break;
    		}
    		ADC_COUNT=0;
    		ADC_TMP=0;
    	}
    
    	ADCSRA|= (1<<ADSC);								//start next Conversion
    }

    Hier ein Paar Dokumente:

    Danke für eure Hilfe!
    Angehängte Dateien Angehängte Dateien
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  7. #7
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Man kann den ADC auch durchlaufen lassen. Das bringt aber nur relativ wenig Geschwindigkeitsvorteil. Dafür wird das zuordnen der Kanäle schwieriger. Bei etwas Verzögerung vor der ISR besteht auch die Gefahr, das man mit dem Umschalten des MUX genau zur kritischen Zeit macht, dann wenn die nächste Konversion gerade gestartet wurde.

    Wenn es schneller werden soll, könnte man ggf. die Zahl der Mittlungen reduzieren oder den ADC-Takt auf 250 kHz erhöhen. Wenn man darauf verzichten will, noch Werte zu verwerfen, müsste man ggf. den Kondensator des Tiefpass noch vergrößern ( > 15 nF). Ob das mit verstärkung auch geht, weiss ich aber nicht. Ohne Verstärkung geht es jedenfalls auch ohne das man Werte verwirft.

    Ein Fehler ist mir nicht aufgefallen, aber es fehlt auch der Teil wo der ADC wert im Hauptprogramm weiter benutzt wird.

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150
    @Besserwessi
    Der ADC Wert wird nur gespeichert und direkt im Interupt verwendet um das Tastverhältnis des Timer 2 anzupassen.
    Hier liegt auch mein Problem:

    Ich konnte den Fehler jetzt stark eingrenzen. Wenn ich nur einen Kanal ausführen lasse, dann funkioniert es. Abgesehen von einem Faktor 2 den ich mir nicht erklären kann. Wenn 500mV am Shunt anliegen erhalte ich anscheinend 512 als ADC wert. Bei 10 facher Verstärkung und 5V referenz sollten es aber 1024 sein. Aber ansonsten funktioniert jeder Kanal für sich. Erst wenn ich im Interupt den Kanal wechseln will, klappt nichts mehr.

    Das Problem liegt in den drei ADMUX Befehlen im ADC Interrupt.
    Darf ich vielleicht nicht das ganze admus neu schreiben sondern nur die entsprechenden Bits toggeln lassen? Ich kann mir das Problem nicht erklären.

    Code:
    SIGNAL(SIG_ADC)
    {
    	if(ADC_COUNT)                     //drop first Measurement
    		ADC_TMP+=(ADC<<1);         //eigenartigerweise Anpassung der ADC WERTE
    	
    	ADC_COUNT++;
    	
    	if(ADC_COUNT>1)
    	{
    		switch(ADC_CHANNEL)
    		{
    		case(0):									// BATTERY
    			UBAT=ADC_TMP;
    			ADC_CHANNEL=1;
    			ADMUX|= 0b01001001;						// AREF/right/2-CH amp./10*ADC1->0
    		break;
    
    		case(1):									// NEAR LED
    			I1=ADC_TMP;
    			if((I_SET>I1) && (OCR1A>400)){
    				OCR1A--;}
    			else if((I_SET<I1) && (OCR1A<1022)){
    				OCR1A++;}
    			ADC_CHANNEL=2;
    			ADMUX|= 0b01001101;						// AREF/right/2-CH amp./10*ADC3->2
    		break;
    		
    		case(2):									// FAR LED
    			I2=ADC_TMP;
    			if((I_SET>I2) && (OCR1B>400)){
    				REDOFF
    				GREENON
    				OCR1B--;}
    			else if((I_SET<I2) && (OCR1B<1022)){
    				REDON
    				GREENOFF
    				OCR1B++;}
    			ADC_CHANNEL=0;
    			ADMUX|= 0b01000111;						// AREF/right/8 unipol./ADC7
    		break;
    		}
    		ADC_COUNT=0;
    		ADC_TMP=0;
    	}
    
    	ADCSRA|= (1<<ADSC);								//start next Conversion*/
    }
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  9. #9
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150
    Fehler gefunden:
    Ich habe :
    ADMUX|= 0b01001001; // AREF/right/2-CH amp./10*ADC1->0
    geschrieben.
    muss aber kein odergleich sondern ein istgleich sein. Also

    Code:
             ADMUX= 0b01001001;                  // AREF/right/2-CH amp./10*ADC1->0
    mfg WarChild
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •