C Mehrere ADCs auslesen

Folienkondensator

Neues Mitglied
28. Mai 2012
89
0
0
Sprachen
  1. ANSI C
  2. Assembler
Hallo

Ich hab die letzten Tage ein neues Projekt zugelegt.
Es ist eigentlich ganz einfach. Es ist ein Wecker mit Textdisplay der per Drucksensor erkennt ob man im Bett liegt oder nicht. Der Witz dabei ist dass der Wecker mit dem "großen aus Knopf" nur in den Schlummermodus geschaltet wird. und dieser nach 5 Min. wider anfängt zu nerven. Der Wecker wird erst dann schweigen wenn der Drucksensor entlastet ist. (wenn man min. 30 Sek. aus dem Bett steigt) :D
Das funktioniert soweit ganz gut. (der Wecker ist eigentlich fertig).

Ich hab mir jetzt eingebildet die Helligkeit des Displays über die Raumhelligkeit zu regeln. (wenn es Tag ist wird das Display hell, wenn es Nacht ist wird das Display dunkel. (ist angenehmer zum einschlafen und schont die Augen).

Nun das Problem:
Ich muss 2 ADCs auslesen und krig das einfach nicht gebacken. Wenn ich den ADC umschalte auf ADC1 (Lichtsensor) kann man den Wecker ausschalten wenn der Lichtsensor dunkel wird. (was eigentlich nicht der Fall sein sollte).

Hier mal der Teil des Codes wie ich das gemacht habe.
Weis jemand wiso es nicht klapt?
Gruß

Code:
#define F_CPU 9830400
#include <avr/io.h>
#include <util/delay.h>
#include <lcd-routines.h>
#include <avr/interrupt.h>


uint8_t		ADC0=0;
uint8_t		ADC1=0;

//PWM
uint8_t		aufloesung=50;
uint8_t		pwm_cnt=0;
uint8_t		CH_1=1;


int main(void)
{
	DDRD=0b00000000;
	DDRB=0b11111111;
	PORTB |= (1<<PB1);
	
	//ADC Init
	//---------------------------
	ADMUX = (1<<REFS0) | (1<<ADLAR);
	ADCSRA = (1<<ADPS1) | (1<<ADPS0);
	ADCSRA = (1<<ADEN);
	
	
	ADMUX &= ~(1<<MUX0);				// Auf ADC0 umschalten
	ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung 
	while (ADCSRA & (1<<ADSC) ) {		// auf Abschluss der Konvertierung warten
	 }								 
	ADC0 = ADCH;						/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen. */
	
	
	ADMUX |= (1<<MUX0);					// Auf ADC1 umschalten
	ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung 
	while (ADCSRA & (1<<ADSC) ) {		// auf Abschluss der Konvertierung warten
	 }								 
	ADC1 = ADCH;						/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen. */
	
 
    while(1)
    {
		
		//ADCs abfragen
		
		ADMUX &= ~(1<<MUX0);				// Auf ADC0 umschalten
		ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung
		while (ADCSRA & (1<<ADSC)) 
		{									// auf Abschluss der Konvertierung warten
		}
		ADC0=ADCL;
		ADC0=ADCH;
	
	
		ADMUX |= (1<<MUX0);					// Auf ADC1 umschalten
		ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung
		while (ADCSRA & (1<<ADSC) ) 
		{									// auf Abschluss der Konvertierung warten
		}
		ADC1=ADCL;
		ADC1=ADCH;
		
		
		//ADC Wert für Drucksensor auswerten
		if (ADC0<=100)
		{
			beep=0;
			PORTB &= ~(1<<PB0);
			sleep_status=0;
			sleep_cnt=0;
		}
		
		//ADC Wert für Lichtsensor auswerten
		
		if (ADC1>120)
		{
			CH_1=50;
		}
		else if ((ADC1<120) & (ADC1>80))
		{
			CH_1=20;
		}
		else if (ADC1<80)
		{
			CH_1=1;
		}
		
		   
	}	//Ende While schlife
}		//Ende Main Schleife
 
Nun das Problem:
Ich muss 2 ADCs auslesen und krig das einfach nicht gebacken. Wenn ich den ADC umschalte auf ADC1 (Lichtsensor) kann man den Wecker ausschalten wenn der Lichtsensor dunkel wird. (was eigentlich nicht der Fall sein sollte).

Hier mal der Teil des Codes wie ich das gemacht habe.
Weis jemand wiso es nicht klapt?

Hallo,

die Ursache für den Fehler finde ich leider in deinem Code-Ausschnitt nicht. Eventuell ist der Fehler an anderer Stelle zu finden.

Noch zwei Hinweise:

ADCL musst du übrigens nicht lesen, wenn du nur 8Bit benötigst (ADLAR=1), es reicht hier direkt ADCH zu lesen.

In der if-Abfrage ADC1 gibt es Werte, die beim Vergleich mit einer Konstanten kein WAHR ergeben (120 und 80), das hast du sicher nicht beabsichtigt, ist hier bestimmt nicht schlimm, der Hinweis könnte dir aber vielleicht helfen um eventuell einen Folgefehler zu vermeiden.

Dirk :ciao:
 
Hallo Dirk

Ich habe den Code Ausschnitt gemacht um den Forum Usern die Sucherei zu ersparen. Ich hab schon vieles probiert aber irgendwie wird das Register "ADC0 und ADC1" wie eins behandelt. Sprich. es ist als ob die Werte von ADC1 in ADC0 kopiert werden würden. :hmpf:
Im Anhang nochmal der gesamte Code.

In der if-Abfrage ADC1 gibt es Werte, die beim Vergleich mit einer Konstanten kein WAHR ergeben (120 und 80),

Hier sollte eigentlich mal eine Pufferzone entstehen damit das Display bei der Dämmerung nicht ununterbrochen von hell nach dunkel springt. Die Zone hab ich jedoch zum testen reduziert. Auch wenn ich jeden Wert eine Funktion zuordne, funktioniert es nicht. Leider ^^

Gruß

Code:
/*
 * LCD_Wecker.c
 *
 * Created: 01.05.2013 15:39:42
 *  Author: Stefan
 */ 


#define F_CPU 9830400
#include <avr/io.h>
#include <util/delay.h>
#include <lcd-routines.h>
#include <avr/interrupt.h>

//Register für Zeit
uint8_t		cnt=0;		//Counter für Sekunden
uint8_t		sek_einer=48;
uint8_t		sek_zehner=52;
uint8_t		min_einer=48;
uint8_t		min_zehner=48;
uint8_t		std_einer=51;
uint8_t		std_zehner=50;
uint8_t		tag=4;

//Register für Weckzeit
uint8_t		w_min_einer=48;
uint8_t		w_min_zehner=48;
uint8_t		w_std_einer=51;
uint8_t		w_std_zehner=50;
uint16_t	sleep_cnt=0;
uint8_t		sleep_status=0;
uint8_t		wecker=0;

uint16_t	i=0;		//Allgemein nutzbares Register
uint8_t		refresh=0;	//Register für Display Aktualisierung
uint8_t		beep=0;		//Alarmton ein/ausschalten
uint8_t		ADC0=0;
uint8_t		ADC1=0;

//PWM
uint8_t		aufloesung=50;
uint8_t		pwm_cnt=0;
uint8_t		CH_1=1;


uint8_t Glocke[8] =			//Glocken Symbol für Wecker
{
	0b00000000,
	0b00000100,		//    X
	0b00001110,     //   XXX
	0b00001110,     //   XXX
	0b00001110,     //   XXX
	0b00011111,     //  XXXXX
	0b00000100,		//    X
	0b00000000
};



int main(void)
{
	DDRD=0b00000000;
	DDRB=0b11111111;
	PORTB |= (1<<PB1);
	
	//ADC Init & erstes Auslesen
	//---------------------------
	ADMUX = (1<<REFS0) | (1<<ADLAR);
	ADCSRA = (1<<ADPS1) | (1<<ADPS0);
	ADCSRA = (1<<ADEN);
	
	
	ADMUX &= ~(1<<MUX0);				// Auf ADC0 umschalten
	ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung 
	while (ADCSRA & (1<<ADSC) ) 
	{									// auf Abschluss der Konvertierung warten
	}								 
	ADC0 = ADCH;						/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen. */
	
	
	ADMUX |= (1<<MUX0);					// Auf ADC1 umschalten
	ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung 
	while (ADCSRA & (1<<ADSC) ) 
	{									// auf Abschluss der Konvertierung warten
	}								 
	ADC1 = ADCH;						/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen. */
	
	
	//Timer Init
	//-------------------------
	TCCR0 |= (1<<CS02) | (0<<CS01) | (0<<CS00);
	TCCR2 |= (0<<CS02) | (1<<CS01) | (0<<CS00);
	TIMSK |= (1<<TOIE0) | (1<<TOIE2);
	sei();
	
	
	//LCD Init
	//-------------------------------
	lcd_init();									//LCD Display initialisieren
	
	
	
//Programmstart
//******************************************************************************************************************


    while(1)
    {
		
		
       if (refresh==1)							//Wenn refresh aktiv ist
       {
		   if (!(PIND & (1<<PD2)))
		   {
			   update();
		   }
		   										//Dann springe zur Displayaktualisierung
		  refresh=0;							// Nach Aktualisierung den Refresh Bit wider auf NULL Setzen
       }
	   
 
		if (PIND & (1<<PD2))					//Wenn Zeit Einstellknopf gedrückt wird
		{
			i=0;								//Dann wird zuerst der Zähler gelöscht
			while (PIND & (1<<PD2))				//Wenn der Einstellknopf weiter gedrückt bleibt
			{
				TIMSK &= ~(1<<TOIE0);			//Dann Zeit Interrupt ausschalten
				min_einer++;					//Minute um eins erhöhen
				update();						//Display aktualisieren
				i++;							//Zählen um eins hoch setzen
				_delay_ms(250);					//Warten
				
				if (i>=20)						//Wenn Zähler auf 20 (20 Sekunden hoch geschaltet)
				{
					while(PIND & (1<<PD2))		//und wenn Einstellknopf immer noch gedrückt
					{
						min_einer++;			//Dann Minute wider um eins hoch stellen
						update();				//Display wider updaten
						i++;					//Zähler hoch zählen
						_delay_ms(100);			//Kürzere Wartezeit wie vorhin
						
						if (i>=90)				// Wenn um weitere 90 Minuten hochgeschaltt wurde, dann wird noch schneller hoch geschaltet
						{
							while(PIND & (1<<PD2))
							{
								min_einer++;
								update();
								i++;
								_delay_ms(5);	
							}
						}
					}
				}
			}
			TIMSK |= (1<<TOIE0);				// Wenn Einstellknopf losgelassen wurde, wird der Zeitinterrupt wider aktiviert
		}
		

		if (PIND & (1<<PD3))					//Weckzeit einstellen (selbes Verfehren wie Uhrzeit einstellen)
		{
			weckzeit();
			i=0;
			while (PIND & (1<<PD3))
			{
				if (PIND & (1<<PD2))
				{
					while (PIND & (1<<PD2))
					{
						w_min_einer++;
						weckzeit();
						i++;
						_delay_ms(250);
						
						if (i>=20)
						{
							while (PIND & (1<<PD2))
							{
								w_min_einer++;
								weckzeit();
								_delay_ms(100);
							}
						}
					}
				}
				asm("nop");
			}
			
		}
		

		if (PIND & (1<<PD5))		//Weckfunktion ein, aus schalten. Wenn der Wecker ausgeschaltet wird, werden alle Wecktöne, Sleepmodes und Weckzeiten ausgeschaltet
		{
			if (wecker==1)
			{
				wecker=0;
				sleep_status=0;
				sleep_cnt=0;
				beep=0;
				PORTB &= ~(1<<PB0);
				update();
			}
			else
			{
				wecker=1;
				update();
			}
			
			while (PIND & (1<<PD5))
			{
			}
			_delay_ms(10);
		}
	
		
		
		
		if ((w_min_einer==min_einer)&(w_min_zehner==min_zehner)			//Weckton einschalten wenn Soll und Istzeit identisch UND wecker eingeschaltet
			&(w_std_einer==std_einer)&(w_std_zehner==std_zehner)
			&(sek_zehner==48)&(sek_einer==48)&(wecker==1))
		{
			beep=1;										//Summer Interrupt starten (PWM) -> Wird von Zeitinterrupt getoggled
			sleep_cnt=0;
			sleep_status=1;
		}
		
		
		if (sleep_cnt>=20)
		{
			beep=1;
			sleep_cnt=0;
		}
		
		
		
		if (PIND & (1<<PD4))			//Weckton ausschalten wen PD4 gedrückt ODER wenn an PA0 min. 2,5V anliegen
		{
			beep=0;
			PORTB &= ~(1<<PB0);
		}
		
		
		//ADCs abfragen
		
		ADMUX &= ~(1<<MUX0);				// Auf ADC0 umschalten
		ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung
		while (ADCSRA & (1<<ADSC)) 
		{									// auf Abschluss der Konvertierung warten
		}
		ADC0=ADCL;
		ADC0=ADCH;
	
	
		ADMUX |= (1<<MUX0);					// Auf ADC1 umschalten
		ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung
		while (ADCSRA & (1<<ADSC) ) 
		{									// auf Abschluss der Konvertierung warten
		}
		ADC1=ADCL;
		ADC1=ADCH;
		
		
		//ADC Wert für Drucksensor auswerten
		if (ADC0<=100)
		{
			beep=0;
			PORTB &= ~(1<<PB0);
			sleep_status=0;
			sleep_cnt=0;
		}
		
		//ADC Wert für Lichtsensor auswerten
		
		if (ADC1>120)
		{
			CH_1=50;
		}
		else if ((ADC1<120) & (ADC1>80))
		{
			CH_1=20;
		}
		else if (ADC1<80)
		{
			CH_1=1;
		}
		
		   
	}	//Ende While schlife
}		//Ende Main Schleife
//**************************************************************************************************




//unterprogramme und Interrupts
//---------------------------------------

ISR(TIMER0_OVF_vect)				//Timer 0 Overflow -> Dieser Interrupt zählt die Sekunden hoch
{
	cnt++;
	
	if (cnt>=150)
	{
		sek_einer++;
		cnt=0;
		DDRB ^= (1<<PB0);
		refresh=1;
		if (sleep_status==1)
		{
			sleep_cnt++;
		}
	}
}

//---------------------------------------



ISR(TIMER2_OVF_vect)
{
	if (beep==1)
	{
		PORTB ^= (1<<PB0);
	}
	else
	{
		PORTB &= ~(1<<PB0);
	}
	
	//PWM Generator
	if (pwm_cnt>aufloesung)
	{
		pwm_cnt=0;
		PORTB |= (1<<PB1);
	}
	if (CH_1<=pwm_cnt)
	{
		PORTB &= ~(1<<PB1);
	}
	pwm_cnt++;
}

//-----------------------------------------




void update(void)
{
	
	if (sek_einer>=58)
	{
		sek_zehner++;
		sek_einer=48;
	}
	
	if (sek_zehner>=54)
	{
		min_einer++;
		sek_zehner=48;
	}
	
	if (min_einer>=58)
	{
		min_zehner++;
		min_einer=48;
	}
	
	if (min_zehner>=54)
	{
		std_einer++;
		min_zehner=48;
	}
	
	if (std_einer>=58)
	{
		std_zehner++;
		std_einer=48;
	}
	
	if ((std_zehner==50) & (std_einer>=52))
	{
		tag++;
		std_einer=48;
		std_zehner=48;
	}
	
	if (tag>=8)
	{
		tag=1;
	}
	
	
	lcd_clear();
	
	switch (tag)
	{
		case 1:
		lcd_string("Mo");
		break;
		case 2:
		lcd_string("Di");
		break;
		case 3:
		lcd_string("Mi");
		break;
		case 4:
		lcd_string("Do");
		break;
		case 5:
		lcd_string("Fr");
		break;
		case 6:
		lcd_string("Sa");
		break;
		case 7:
		lcd_string("So");
		break;
		default:
		break;
	}	
	
	lcd_data(46);
	lcd_setcursor(4,1);
	lcd_data(std_zehner);
	lcd_data(std_einer);
	lcd_data(58);
	lcd_data(min_zehner);
	lcd_data(min_einer);
	lcd_data(58);
	lcd_data(sek_zehner);
	lcd_data(sek_einer);
	
	if (wecker==1)								//Wenn Wecker Aktiv, dann wird "Glocke" Zeichen angezeigt
	{
		lcd_generatechar(LCD_GC_CHAR0, Glocke);
		lcd_setcursor(15,1);
		lcd_data(LCD_GC_CHAR0);
	}
	
}

//-------------------------------------------------------



void weckzeit(void)
{
	if (w_min_einer>=58)
	{
		w_min_zehner++;
		w_min_einer=48;
	}
	
	if (w_min_zehner>=54)
	{
		w_std_einer++;
		w_min_zehner=48;
	}
	
	if (w_std_einer>=58)
	{
		w_std_zehner++;
		w_std_einer=48;
	}
	
	if ((w_std_zehner>=50) & (w_std_einer>=52))
	{
		w_std_einer=48;
		w_std_zehner=48;
	}
	
	lcd_clear();
	
	lcd_setcursor(3,1);
	lcd_string("-WECKZEIT-");
	lcd_setcursor(3,2);
	lcd_data(w_std_zehner);
	lcd_data(w_std_einer);
	lcd_data(58);
	lcd_data(w_min_zehner);
	lcd_data(w_min_einer);
	lcd_data(32);
	lcd_string("Uhr");
}
 
Hier nochmal als Anhang, da die Darstellung irgendwie nicht so das wahre ist ;)
 

Anhänge

  • LCD W.c
    9 KB · Aufrufe: 4
Hi

Ich hab jetzt bei der Abfrage der ADCs noch eine "Sicherheitsabfrage" eingebaut,
um wirklich sicher zu gehen dass die richtigen MUX Bits gesetzt sind bevor der ADC abgefragt wird. -> Problem immer noch vorhanden

Dann habe ich noch die Reihenfolge geändert in der die ADCs abgefragt werden. (ADC1 dann ADC0). -> selbes Problem

Zudem habe ich meinen Aufbau auf Kurzschlüsse unter den ADCs geprüft -> Problem besteht weiterhin

Ich habe den Chip getauscht (von mega32 auf mega16) ->das selbe Problem

Dann habe ich noch von ADC0 und 1 auf ADC1 und 2 gewechselt. -> Problem wandert mit

Zum Schluss nochmal eine Fusebit Kontrolle. (Alles wie es sein soll) -> Problem bleibt

Um das Problem zu vereinfachen:
Es ist egal an welchen der beiden ADCs ich meinen Lichtsensor anschließe. das Display dimmt fleißig mit. :fie:
 
Hmm... vielleicht 'ne dumme Frage, aber reicht die Zeit zwischen Umschalten des Eingangs-Multiplexers und Starten der Konversion aus, den (internen) Sample&Hold-Kondensator umzuladen?
 
Hmm... vielleicht 'ne dumme Frage, aber reicht die Zeit zwischen Umschalten des Eingangs-Multiplexers und Starten der Konversion aus, den (internen) Sample&Hold-Kondensator umzuladen?

Hi

hmm, Wie könnte ich die Zeit denn verlängern? bzw, wo soll ich mal ein delay rein setzen?

gruß
 
Na genau dazwischen. Also zwischen das Umsetzen der MUX-Bits in ADMUX und dem Setzen des "Start-Conversion"-Bits in ADCSRA.

Nen delay ist zwar schrecklich ineffizient, aber das warten aus ADSC=0 ist auch nicht viel besser...
 
Hallo LotadaC,
Hmm... vielleicht 'ne dumme Frage, aber reicht die Zeit zwischen Umschalten des Eingangs-Multiplexers und Starten der Konversion aus, den (internen) Sample&Hold-Kondensator umzuladen?

naja, die Frage ist gar nicht so "dumm".

Die ADC Pins haben keine unendlich kleine Eingangsimpedanz. Es kann schon sein, dass das S&H C nicht richtig umgeladen wird.

Vor dem Starten der Wandlung einfach mal ein _delay_us(100) zum testen einfügen. Gut ist es auch, wenn man eine Dummy-Wandlung nach einen Channel-Wechsel macht.

Zusätzlich: Wenn ausreichend Zeit ist, dann ist es noch besser, wenn man mehrere Wandlungen summiert und einen Mittelwert bildet (4x, 8x, 16x ist gut geeignet, damit die Division durch Rechsshift gemacht werden kann).
 
Hai

Danke für die Antworten :)

Ich hab mal ein paar delays gesetzt. nachdem die 100us nicht funktioniert haben, hab ich ein paar übergroße delays gesetzt.
Leider war das nicht die Lösung :vollkommenauf:

Code:
//ADCs abfragen
		ADMUX =0b01100010;					// Auf ADC2 umschalten
		while (!(ADMUX=0b01100010))
		{
		}
		_delay_ms(10);
		ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung
		_delay_ms(10);
		while (ADCSRA & (1<<ADSC) ) 
		{									// auf Abschluss der Konvertierung warten
		}
		ADC1=ADCH;
		
		
		
		
		ADMUX =0b01100001;				// Auf ADC1 umschalten
		while (!(ADMUX=0b01100001))
		{
		}
		_delay_ms(10);
		ADCSRA |= (1<<ADSC);				// eine ADC-Wandlung
		_delay_ms(10);
		while (ADCSRA & (1<<ADSC)) 
		{									// auf Abschluss der Konvertierung warten
		}
		ADC0=ADCH;
 
Zum Single-Conversion-Mode steht folgendes im Datenblatt:
When changing channel selections, the user should
observe the following guidelines to ensure that the correct channel is selected:

In Single Conversion mode, always select the channel before starting the conversion. The channel selection may be changed one ADC clock cycle after writing one to ADSC. However, the simplest method is to wait for the conversion to complete before changing the channel selection

The MUXn and REFS1:0 bits in the ADMUX Register are single buffered through a temporary register to which the CPU has random access. This ensures that the channels and reference selection only takes place at a safe point dur
ing the conversion. The channel and reference selection is continuously updated until a conversion is started. Once the conversion starts, the channel and reference selection is locked to ensure a sufficient sampling time for the ADC. Continuous updating resumes in the last ADC clock cycle before the conversion completes (ADIF in ADCSRA is set). Note that the conversion star ts on the following rising ADC clock edge after ADSC is written. The user is thus advised not to write new channel or reference selction values to ADMUX until one ADC clock cycle after ADSC is written.

Bist du sicher, dass es an der AD-Wandlung liegt? Konntest du das mal prüfen, zum Beispiel indem du unterschiedliche Werte für CH_1 im Hauptprogramm vorgibst, nicht dass es an der PWM für die Helligkeit liegt.

Noch ein allgemeiner Hinweis:
Für Variablen, die sowohl in ISR, wie auch im Hauptprogramm verwendet werden, solltest du "volatile uint8_t" (Beispiel) bei der Definition verwenden. Zudem solltest du darauf achten, dass im Hauptprogramm keine ISR den Inhalt der Variable ändern kann, wenn gerade im Hauptprogramm damit gearbeitet wird. Eine Möglichkeit ist, im Hauptprogramm kurzzeitig die Interrupts global zu deaktivieren.
 
Gelöst! :)

Jetzt weis ich wieso es nicht funktioniert ;)

Auf ADC0 war der Fotosensor (Spannungsteiler mit Fotowiderstand [5K bis "unendlich"] und Widerstand 10K)
Auf ADC1 war die Drucksensor Folie (Spannungsteiler mit Drucksensor [10K bis "unendlich"] und Widerstand 66M Ohm)

Da der Sensor unglaublich empfindlich ist und ich schon Messwerte ab 50 Gramm benötige, hab ich den Spannungsteiler etwas zu hochohmig gemacht. Zu wenig Strom für den ADC anscheinend :rolleyes:
Jetzt hab ich einen 1,5M Ohm Widerstand eingesetzt und es funktioniert! :D

Vielen Dank für die Unterstützung! :)

Gruß
Folienkondensator
 
Zu früh gefreut
Nach einigen kleinen Tests hat sich herausgestellt dass das Problem weiterhin besteht :(
Ich hab jetzt zwei Pottis angeschlossen (2K Ohm) und selbst hier tritt das Problem auf.

Gibt es irgendwo ein Beispielprogramm für ADC auslesen? damit man sich da evtl etwas abschauen kann?:fie:

gruß
 
Du hast es eigentlich soweit schon richtig gemacht.

Die Umschaltung des Kanals erfolgt ja nachdem du eine Single-Conversion startet. Mach testweise jeweils 2 Messungen mit einem Kanal, die jeweils erste "schmeiss weg".

Ich würde aber prüfen, ob nicht das Problem woanders liegt. In meinem vorherigen Beitrag habe ich hierzu schon einmal etwas geschrieben.

Konntest du den gemessenen Wert überprüfen, zum Beispiel durch Ausgabe auch Display.
Oder, hast du einfach mal den PWM-Wert im Hauptprogramm fest vorgegeben, eventuell mit unterschiedlichen Werten. Funktioniert die PWM, bzw. die Helligkeitseinstellung?
 
Hallo Dirk

Da hast du tatsächlich recht. Die Empfehlung die erste Messung zu ignorieren ist nicht nur eine Empfehlung sondern ein Muss!
Ich hab einen kleinen Test gemacht mit einem extra Programm in dem ich nur 2 Pottis auslese und 2 LEDs leuchten lasse. Wenn man nur eine Messung macht kommt exakt der beschriebene Fehler.

Jetzt habe ich 4 von 5 Messungen weg geworfen und die 5. Messung benutzt. und es funktioniert.
Nach ein paar versuchen hat sich herausgestellt dass die 2. Messung bereits "brauchbare" Daten hat. (zumindest befinden sich in den zwei ADC Registern jetzt auch zwei verschiedene Werte).

Das ist schonmal eine sehr gute Erkenntnis. :)

Bevor ich aber jetzt wider sage dass das Problem gelöst ist, versuch ichs erstmal im richtigen Programm und gebe dann eine Meldung ;)

Danke!!!

gruß
 
oke. Also es sieht tatsächlich so aus als ob es funktioniert.

Ich lese jetzt jeden der beiden ADC Werte 9x aus. der 10. Wert wird verwendet.

Funktioniert prima. Danke :)

Gruß
 
oke. Also es sieht tatsächlich so aus als ob es funktioniert.
Ich lese jetzt jeden der beiden ADC Werte 9x aus. der 10. Wert wird verwendet.

Die Ursache des Fehlers liegt wahrscheinlich an deiner Sensor-Hardware, die einen zu hohen Ausgangswiderstand zu den ADC-Kanälen hat. Die S&H Kapazität wird dadurch nicht schnell genug umgeladen, wenn der Multiplexer auf einen anderen Kanal schaltet.

Du hattest zuvor mal mit Delays getestet, was nichts gebracht hat. Die Delays hattest du direkt nach dem Beschreiben des ADMUX-Registers verwendet. Da aber der Multiplexer erst kurz nach Start der neuen Wandlung (ADSC=1) auf den neuen Kanal umschaltet, hatte dies keine Wirkung.

Anscheinend reicht es ja nun nach dem Umschalten mehrere (9) Dummy-Wandlungen zu machen, was aber nicht so schön ist. Ich würde schauen, ob du an der Hardware etwas ändern kannst, also den Ausgangswiderstand der Sensorschaltung verringern. Dann würde eventuell eine Dummy-Wandlung ausreichen.

Hier ein Auszug aus dem Datenblatt zu dem Thema:

Dirk :ciao:

The Analog Input circuitry for single ended channels is illustrated in Figure 23-6. An analog
source applied to ADCn is subjected to the pin capacitance and input leakage of that pin, regardless
of whether that channel is selected as input for the ADC. When the channel is selected, the
source must drive the S/H capacitor through the series resistance (combined resistance in the
input path).
The ADC is optimized for analog signals with an output impedance of approximately 10 kΩ or
less
. If such a source is used, the sampling time will be negligible. If a source with higher impedance
is used, the sampling time will depend on how long time the source needs to charge the
S/H capacitor, with can vary widely. The user is recommended to only use low impedant sources
with slowly varying signals, since this minimizes the required charge transfer to the S/H
capacitor
.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)