Bitte um Hilfe beim Xmega a1

Status
Für weitere Antworten geschlossen.

fenomaen

Neues Mitglied
21. Dez. 2010
33
0
0
Sprachen
Hallo

Mein Projekt: Ich entwickle gerade mit einem Kollegen ein Messgerät, um Infrarot-Sendeleistung der Fernbedienung zu messen.
Dazu will ich so schnell wie möglich Werte die von der Fernbedienung über einen Transimpedanzwandler erzeugt werden in meine ADC vom Xmega A1 aufnehmen und in ein Array speichern.

Da ich nicht so begabt bin beim Programmieren würde ich euch um so ein kleines Programm bitten, ihr habt sicher so ein enfaches ADC programm irgendwo herumliegen.

Ein großes Dankeschön im voraus.
 
Hallo

und willkommen im AVR-PRAXiS-Forum.

Ein fertiges Programmbeispiel für deine Anwendung habe ich leider nicht, wahrscheinlich wird dir auch kein anderer User etwas fertiges liefern. Schau dir am besten einmal die Application Note AVR1300: Using the XMEGA ADC an. Dort wird erklärt, wie man den ADC des Xmega initialisiert.

Das sollte dir eigentlich schon weiterhelfen.

Grüße,
Dirk
 
Hallo,

auch von aus willkommen.

Vielleicht nennst Du mal ein paar Eckdaten, zum Beispiel warum es denn gleich ein XMega sein soll. Damit hab ich mich noch nicht beschäftigt.
Für einen Atmega hab ich so was schon gemacht, auch für ARMs.

Wieviele Werte willst Du speichern?
Welche Abtastrate benätigst Du?
Welchen Spannungsbereich kann man erwarten?
Welchen Transimpedanzwandler willst Du einsetzen?

Gib mal etwas mehr Infos, dann kann man evtl. auch gezielter unterstützen.

Michael
 
Wir haben eine Taktfrequenz von 56kHz haben bei den Infrarot Sendedioden und müssen daher ca. 10 mal so schnell abtasten damit wir einen sinnvollen Wert erhalten. Deswegen nehmen wir den xmega a1 her da er 2MSPS hat.

Weiter hat eine Fernbedienung bzw IR-Senderdiode eine ausstrahlfläche von 90° das heißt wir würde alle 5° einen Wert messen.

Wir habe eine einfache Transimpedanzverstärkerschaltung aufgebaut mit einem ausreichen schnellen OPV (AD812ANZ).

Den Spannungsbereich habe ich noch nicht festgelegt. aber so um die 5V herum denk ich mal.

Ich hoffe ihr könnt mir weiterhelfen

MFG feno
 
Wir haben eine Taktfrequenz von 56kHz haben bei den Infrarot Sendedioden und müssen daher ca. 10 mal so schnell abtasten damit wir einen sinnvollen Wert erhalten. Deswegen nehmen wir den xmega a1 her da er 2MSPS hat.
OK das ist ein klares Argument für den A1. Mann könte allerdings auch einen externen ADC-Wandlerbaustein nehmen, z.B.: per SPI.

Habt Ihr denn schon ein Modul? Entwicklungsumgebung?

Also mal so aus der Schublade hat hier sicher keiner was für den A1. Wenigstens einen Rahmen müßt Ihr je nach Modul schon bauen, dann kann man unterstützen.

Michael
 
Hallo feno,

ich hatte auf die

AppNote AVR1300: Using the XMEGA ADC

von Atmel hingewiesen. Dort wird ziemlich genau erklärt, wie man mit dem ADC des XmegaA umgeht, Programmbeispiele sind auch vorhanden. Hast du dir die AppNote angesehen? Du müsstest eigentlich nur eines der Beispiele (Pollen, Interrupt ...) 1:1 übernehmen und dein Array mit dem ADC Ergebnis "befüllen".

Dirk
 
Hi
Willkommen auch von mir.
Aber
Hallo

Mein Projekt: Ich entwickle gerade mit einem Kollegen ein Messgerät, um Infrarot-Sendeleistung der Fernbedienung zu messen.
Dazu will ich so schnell wie möglich Werte die von der Fernbedienung über einen Transimpedanzwandler erzeugt werden in meine ADC vom Xmega A1 aufnehmen und in ein Array speichern.

Da ich nicht so begabt bin beim Programmieren würde ich euch um so ein kleines Programm bitten, ihr habt sicher so ein enfaches ADC programm irgendwo herumliegen.
das geht gar nicht. ICH... 8der Esel nennt sich immer zuerst, hab ich mal gelernt) entwickle ein Gerät....
Gut,dann soll es auch so sein. Meine Frage: für's Studium? fur die Firma ? für die Schule ? für den Eigengebrauch ?
Als nächstes... hast du dich bei den Elektronikern auch schon erkundigt, ob die vieleicht schon was Fertiges haben. Ach ja, ein fertiges ADC-programm... hmmm da könnt ich schon mit dienen. Ist zwar für den Atmega8, aber das läßt sich ja anpassen...
Code:
  Init_ADC:			; Analogkanal initialisieren 
  ldi     a0, (1<<REFS0) | (1<<ADLAR)
  out     ADMUX, a0    
  ldi     a0, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0)   
  out     ADCSRA, a0
	
RET
und dazu die Routine zum Lesen eines Analogwertes auf Port C1
Code:
Read_Analog:	
	in      Temp_Reg, ADCL		; immer zuerst LOW Byte lesen
    	in      Temp_Reg, ADCH		; danach das mittlerweile gesperrte High Byte
	 STS		Poti_Wert,Temp_Reg   
	
RETI
Mehr Hilfe wirst du ohne ein Wenig Eigenleistung nicht erwarden können.
Gruß oldmax
 
Hallo oldmax
... Ist zwar für den Atmega8, aber das läßt sich ja anpassen...

Xmega ist mit AVRMega oder AVRTiny nicht mehr vergleichbar, man kann hier also nicht die Initialisierung von dem ADC eines Atmega8 als Grundlage verwenden.

Wenn man die AppNote von Atmel verwendet und die fertigen Routinen von Atmel nutzt, ist der ADC mit drei oder vier Funktionsaufrufen fertig initialisiert. Wenn man die fertigen Funktionen nicht nutzen möchte, schaut man sich die einfach mal an, welche Register wie initialisiert werden, so kann man sich das alles an sein eigenes Programm/Programmierstil anpassen.

Grüße,
Dirk
 
Also wir haben das Modul (den xmega a1) schon. Auch haben wir eine Jtagice mk2 zum debuggen.

Ich habe auch schon ein programm geschrieben (siehe unten), wo der ADC auf Free Run mode arbeitet und Werte vom PIN2 aus PortA liest. Auf diesem Pin kann ich eine Spannung von 0-1V variieren da ich die interne Referenz zurzeit verwende. Beim Deubuggen werden auch in der temp variable die Werte von 0-4095 angezeigt soweit so richtig.

Nur beim Durchdebbugen will der ADC diese Werte nicht in eine Variable speichern schon gar nicht in ein array???



#include <avr/io.h>

int main(){

//int schleife=1;
uint16_t temp=0;
uint16_t mittel=0;
uint16_t summe=0;
//uint16_t a[10];

uint16_t i=0;

ADCA.CTRLA = 0x01; // enable adc
ADCA.CTRLB = 0x08; //ADC_RESOLUTION_12BIT_gc;
ADCA.REFCTRL = 0x00; // internal 1.0V Reference
//ADCA.PRESCALER = ADC_PRESCALER_DIV4_gc;
//peripheral clk/8 (2MHz/4=500kHz)

ADCA.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc;
// single ended
ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN2_gc; // PORTA:2

for(i=0; i<10; i++){

temp = ADCA_CH0RES;
summe=summe+temp;
//temp=a;

}
mittel=summe/10;

return 0;
}
 
Hallo feno,

bevor du das Ergebnis aus dem Result-Register liest, musst du erst prüfen, ob die Wandlung fertig ist.

Das sieht dann in etwa so aus:

Code:
uint16_t data;

data = 0;

for (i=0; i<8; i++)
{
  while(!ADCA.CH0.INTFLAGS) { };  // IF gesetzt? Ja, dann Wandlung fertig, ansonsten warten

  data += ADCA.CH0RES;  // hier lese ich das Ergebnis und summiere 8 mal

  ADCA.CH0.INTFLAGS = ADC_CH_CHIF_bm; // IF wieder löschen
}

data = data >> 3; // entspricht geteilt durch 8 (ist günstiger als durch 10)
Du solltest vor return 0; in main noch eine while(1) {}; setzen.

Ich nehme an, du hast noch etwas code entfernt, denn mit //temp=a; schreibst du nichts in das Array a[].

Vielleicht hilft dir das schonmal weiter.

Noch einen schönen Sonntag,
Dirk
 
Hallo,

auch wenn ich keinen A1 hier habe, versuch ich mal zu helfen.
Also so wie der Code jetzt aussieht, kann das auch nicht gehen. Wenn Ihr auf SongleConversation umstellt, muss auch jedes Mal ein erneuter Start ausgelöst werden. Außerdem muss natürlich gewartet werden, bis die conversation zu Ende ist. Am einfachsten prüft man ab, wenn das gesetzte Startbit wieder "erlischt". Besser ist allerdings mit den Events zu arbeiten.
Ich hab mal versucht Euren Code zu ergänzen. Praktisch testen kann ich es allerdings nicht, das müßt Ihr übernehmen.
Code:
#include <avr/io.h> 

int main()
{ 

	//int schleife=1; 
	uint16_t temp=0; 
	uint16_t mittel=0;
	uint16_t summe=0;
	//uint16_t a[10];

	uint16_t i=0;

	ADCA.CTRLA = 0x01; // enable adc 
	ADCA.CTRLB = 0x08; //ADC_RESOLUTION_12BIT_gc; 
	ADCA.REFCTRL = 0x00; // internal 1.0V Reference 
	//ADCA.PRESCALER = ADC_PRESCALER_DIV4_gc; 
	//peripheral clk/8 (2MHz/4=500kHz) 

	ADCA.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc; 
	// single ended 
	ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN2_gc; // PORTA:2

	for(i=0; i<10; i++)
	{
		// Start single conversation Channel 0
		ADCA.CTRLA |= ADC_CH0START_bm;
		// warten, bis fertig (Startbit geht auf 0 am Ende der Conversation)
		while ( ADCA.CTRLA & ADC_CH0START_bm )
			;

		// Wert entnehmen
		temp = ADCA_CH0RES;
		summe=summe+temp;
		//temp=a[i];

	}
	mittel=summe/10;

	return 0;
}
Probiert es aus und berichtet über das Ergebnis.
 
Hallo Michael,

das ist schon soweit richtig gedacht!

Es ist aber noch der FreeRunningMode gewählt: ADCA.CTRLB = 0x08;

Im CTRLA Register wird ADC_CH0START_bm beim Start der Conversion zurückgesetzt, nicht beim Ende, wenn das Ergebnis gültig ist. Man muss also das IF Bit im Register ADC0.CH0.INTFLAGS überprüfen und manuell zurücksetzen (siehe meinen Beitrag vor deinem).

Grüße,
Dirk
 
Code:
#include <avr/io.h>     
	 
	
int main(){	
		
	uint16_t temp=0;	
	uint16_t mittel=0;
	uint16_t summe=0;
	//uint16_t a[10];

	uint16_t i=0;

	ADCA.CTRLA = 0x01; 	// enable adc 
	ADCA.CTRLB = 0x08; //ADC_RESOLUTION_12BIT_gc; 		// 12 bit conversion 
	ADCA.REFCTRL = 0x00; // internal 1.0V Reference //ADC_REFSEL_INT1V_gc | 0x02; 	// internal 1V bandgap reference 
	//ADCA.PRESCALER = ADC_PRESCALER_DIV4_gc; 	// peripheral clk/8 (2MHz/4=500kHz) 
	ADCA.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc; 	// single ended 
	ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN2_gc; 	// PORTA:2	

	for(i=0; i<10; i++){

		// Start single conversation Channel 0
		ADCA.CTRLA |= ADC_CH0START_bm;
		while(!ADCA.CH0.INTFLAGS) { };
		// warten, bis fertig (Startbit geht auf 0 am Ende der Conversation)
		while ( ADCA.CTRLA & ADC_CH0START_bm );
		
		temp = ADCA_CH0RES;
		summe=summe+temp;
		//temp=a[i];
		ADCA.CH0.INTFLAGS = ADC_CH_CHIF_bm; // IF wieder löschen
		
	}

	mittel=summe/10;

           return 0;
}

Also ich habe das nun so ausgeführt und beim durchdebuggen bleibt er bei dieser while hängen while ( ADCA.CTRLA & ADC_CH0START_bm );

Wenn ich dann diese Zeile auskommentiere, werden die Werte in die temp Variable geschrieben aber dann nicht in der variable summe aufsummiert.
Und im watch fenster steht bei summe: location not valid
 
Hallo,

folgende Zeilen lass erst mal weg:
ADCA.CTRLA |= ADC_CH0START_bm;
while ( ADCA.CTRLA & ADC_CH0START_bm );

Du hast ja FreeRunningMode gewählt, also brauchst du die ADC Wandlung nicht extra anstossen. Das Bit ADC_CH0START_bm im Register ADCA.CTRLA ist das Startbit für SingleConversion vom Channel0, das brauchst du nicht setzen, es eignet sich auch nicht, um festzustellen, ob die Wandlung beendet ist, dazu dienst das IF Bit im Register ADC0.CH0.INTFLAGS.

Also bitte nicht alles vermischen. Entweder SingleConversion oder FreeRunning und immer ADC0.CH0.INTFLAGS prüfen.

Das mit der Debuggermeldung (watch-window) ist wahrscheinlich ein anderes Problem und hat mit dem ADC nichts zu tun.

Dirk
 
Hallo Dirk,

Es ist aber noch der FreeRunningMode gewählt: ADCA.CTRLB = 0x08;
Sorry, das hab ich übersehen.

Im CTRLA Register wird ADC_CH0START_bm beim Start der Conversion zurückgesetzt, nicht beim Ende, wenn das Ergebnis gültig ist. Man muss also das IF Bit im Register ADC0.CH0.INTFLAGS überprüfen und manuell zurücksetzen (siehe meinen Beitrag vor deinem).
In dem Fall ja. Besser ist das auch im SingleConversation Mode, da erst dann der Wert übernommen wurde.

Michael

PS: Ups, da waren wir ja fast gleichzeitig
 
OK den Fehler mit Location not valid habe ich nun behoben. Indem ich Ohne Optimierung debugge.
Project -> Configuration Options -> General unter 'Optimization' von s auf 0 stellen.

Nun funktioniert das Programm, ABER jetzt kommen falsche Werte :S. Wenn ich ihm 0,2 Volt rein schicke erwarte ich einen Wert von zirka 800 aber da kommt irgendein beliebeger Wert der zwischen 2200 und 3000 variiert?

Ein großes Dankeschön zuerst.
 
Code:
#include <avr/io.h>     
	 
	
int main(){	
		
	uint16_t temp=0;	
	uint16_t mittel=0;
	uint16_t summe=0;
	//uint16_t a[10];

	uint16_t i=0;

	ADCA.CTRLA = 0x01; 	// enable adc 
	ADCA.CTRLB = 0x08; //ADC_RESOLUTION_12BIT_gc; 		// 12 bit conversion 
	ADCA.REFCTRL = 0x00; // internal 1.0V Reference //ADC_REFSEL_INT1V_gc | 0x02; 	// internal 1V bandgap reference 
	//ADCA.PRESCALER = ADC_PRESCALER_DIV4_gc; 	// peripheral clk/8 (2MHz/4=500kHz) 
	ADCA.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc; 	// single ended 
	ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN2_gc; 	// PORTA:2	

	for(i=0; i<10; i++){

		while(!ADCA.CH0.INTFLAGS) { };
		
		temp = ADCA_CH0RES;
		summe=summe+temp;
		//temp=a[i];
		ADCA.CH0.INTFLAGS = ADC_CH_CHIF_bm; // IF wieder löschen
		
	}

	mittel=summe/10;

    return 0;
}

Es "funktioniert" aber auch ohne die zwei Zeilen mit den Interrupt-Flags. Es nimmt genauso die falschen Werte auf.
 
Lt. AppNote soll man nach dem enable eine Conversation abwarten - bei uncalibriertem Start.

Probier mal das:
Code:
#include <avr/io.h> 

int main()
{ 

	//int schleife=1; 
	uint16_t temp=0; 
	uint16_t mittel=0;
	uint16_t summe=0;
	//uint16_t a[10];

	uint16_t i=0;

	
	ADCA.CTRLB = 0x08; //ADC_RESOLUTION_12BIT_gc; 
	ADCA.REFCTRL = 0x00; // internal 1.0V Reference 
	ADCA.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc; 
	// single ended 
	ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN2_gc; // PORTA:2

	ADCA.CTRLA = 0x01; // enable adc 
	// eine Conversationszeit abwarten (24ADC-Clocks) - hier kann auch eine feste Zeit gewartet werden
	while(!ADCA.CH0.INTFLAGS) { };
	// IF wieder löschen
	ADCA.CH0.INTFLAGS = ADC_CH_CHIF_bm; 
	// dummy lesen
	temp = ADCA_CH0RES;

	for(i=0; i<10; i++)
	{
		while(!ADCA.CH0.INTFLAGS) { };
		// IF wieder löschen
		ADCA.CH0.INTFLAGS = ADC_CH_CHIF_bm; 

		// Wert entnehmen
		temp = ADCA_CH0RES;
		summe=summe+temp;
		//temp=a[i];

	}
	mittel=summe/10;

	return 0;
}

Michael
 
Status
Für weitere Antworten geschlossen.

Ü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)