Habe einen AVR XMEGA-A1 Xplained von Atmel vor mir liegen.
Ich programmiere in C auf meinem Linux System und flashe meinen Code
mittels der PDI Schnittstelle und avrdude auf den xmega.
Ich habe innerhalb meines Codes das USART so konfiguriert, dass der
xmega über usb die serielle Schnittstelle emuliert, so dass ich mit
putty/plink eine "Debug Ausgabe" in meinem Terminal auf Linux haben
kann:
1
plink -sercfg 9600,8,n,1 -serial /dev/ttyACM0
Der C Code den ich hier zeige schaltet durch die LEDS und druckt den
aktuellen Wert der LED-Bits im Terminal aus:
Den Code habe ich aus diesen Quellen zusammengebastelt und teilweise von
einem Kollegen übernommen:
- https://morf.lv/guide-to-xmega-usart-aka-serial-communication
-
http://www.jtronics.de/avr-projekte/xmega-tutorial/xmega-tutorial-usart.html
Nun zu meinen Fragen:
Als nächstes möchte ich mit dem integrierten Lautsprecher des Xmega
experimentieren. Leider habe ich nichts brauchbares für mich im
Datenblatt ( http://www.atmel.com/images/doc8077.pdf ) gefunden.
1.) Kann mir eine Code Beispiele geben, die Sounds aus den integrierten
Lautsprecher erzeugen? (Zum Beispiel: generiere ein einfaches Piepen.)
2.) Kann mir einer im Datenblatt zeigen, wo entsprechende Infos sind?
3.) Danach wollte ich mit dem Lichtsensor experimentieren. Wo finde ich
Code Beispiele die dieses machen? (Zum Beispiel: lies den aktuellen
Lichtwert in eine Variable und drucke es in das Terminal. Den Teil mit
drucke es in das Terminal aus habe ich ja schon, nur kann ich im
Datenblatt nicht rauslesen, wie man den Lichtsensor abfragen kann.)
Vielen Dank für das Lesen und eine Antwort.
Hmm, löse ich deine Hausaufgabe:
Nein!!
Gebe ich tipps:
Ja:
Suche dir erst mal raus wie du den Sensor anschließen willst.
Hier sind die Stichworte:
AD-Wandler
SPI
I2C
UART
Viel Spaß
Mit freundlichen Gruß
Kerler Marian
Hallo,
Ähm, bitte lies doch mal den ganzen Artikel durch. Der Sensor ist schon
auf dem Board verbaut. Hättest du dir mal das Board angeguckt. Google
und so.
Es ist keine Hausaufgabe.
Peter Parker schrieb:> 2.) Kann mir einer im Datenblatt zeigen, wo entsprechende Infos sind?
Du brauchst in diesem Fall das Schaltbild des Boards.
Wenn du dir das anschaust, siehst du, das der Lichtsensor an Port PB1
angeschlossen ist, der Temperaturfühler sitzt an PB0 und wird über Port
PB3 angeschaltet.
Du solltest jetzt also den AD Wandler B aktivieren (wieder mit Hilfe des
Datenblattes) und dann den Kanal B1 auswählen, um den Lichtsensor
abzufragen. Das Resultat der AD Wandlung sendest du z.B. wieder an die
serielle.
> 1.) Kann mir eine Code Beispiele geben, die Sounds aus den integrierten> Lautsprecher erzeugen? (Zum Beispiel: generiere ein einfaches Piepen.)
Der Lautsprecher hängt am DACB0 (Pin B2) und wird also mit dem DA
Wandler B angesprochen. Dazu schickst du ihm Wellenformen, die mit z.B.
einem Timer getriggert werden. Denke dran, vor Benutzung des
Lautsprechers die Endstufe über Port PQ3 (Audio Shutdown) anzuschalten.
An ist Pin low.
Matthias S. schrieb:> Du brauchst in diesem Fall das Schaltbild des Boards.
OK habe nun das "datasheet" geöffnet ( Seite 3/4 und 6 ,
http://www.atmel.com/images/atmel-8067-8-and-16-bit-avr-microcontrollers-atxmega64a1-atxmega128a1_datasheet.pdf
). Eines der beiden Bilder sollte ein Schaltbild darstellen, bitte
korrigiere mich wenn das nicht der Fall sein sollte.
Matthias S. schrieb:> Wenn du dir das anschaust, siehst du, das der Lichtsensor an Port PB1> angeschlossen ist, der Temperaturfühler sitzt an PB0 und wird über Port> PB3 angeschaltet.
Also, an den Rändern der Skizze mit der Überschrift "Block diagram and
pinout" sehe ich in der Tat deine Bezeichnungen "PB0" und "PB1" und auch
"PB3". Aber ich verstehe nicht, woher du daraus lesen kannst, dass es
sich hier um den Lichtsensor/Temperaturfühler handelt.
Matthias S. schrieb:> Du solltest jetzt also den AD Wandler B aktivieren (wieder mit Hilfe des> Datenblattes) und dann den Kanal B1 auswählen, um den Lichtsensor> abzufragen. Das Resultat der AD Wandlung sendest du z.B. wieder an die> serielle.
Ok, Wenn ich dein "AD Wandler B" in das Englische übersetze, dann müsste
ich wohl irgendwas im Datasheet suchen wie "Analog-Digital-Converter-B"
oder abgekürzt "ADCB". Das finde ich auch auf Seite 62 in der Tabelle
"Peripheral Module Address Map", die aber für nähere Informationen bzlg.
"ADCB" auf dieses Dokument verweist:
http://www.atmel.com/images/doc8077.pdf . Auf Seite 284 des letzteren
Dokuments meine ich den schematischen Aufbau einer "ADC" (hier ohne B)
zu sehen. (Bitte korrigiere mich wenn es nicht stimmt.)
Des Weiteren kann ich in der source Datei von AVR "iox128a1.h" einige
Konstanten finden, die mit dem "ADCB" in Verbindung stehen:
1
...
2
/* ADCB - Analog to Digital Converter B */
3
...
4
#define ADCB_CTRLB _SFR_MEM8(0x0241)
5
...
6
#define ADCB_CH1_CTRL _SFR_MEM8(0x0268)
7
#define ADCB_CH1_MUXCTRL _SFR_MEM8(0x0269)
8
#define ADCB_CH1_INTCTRL _SFR_MEM8(0x026A)
9
#define ADCB_CH1_INTFLAGS _SFR_MEM8(0x026B)
10
#define ADCB_CH1_RES _SFR_MEM16(0x026C)
11
...
Wenn ich nun tiefer in dem Text (
http://www.atmel.com/images/doc8077.pdf , Seite 297, "CTRLB – ADC
Control register B") stöbere, finde ich heraus, dass ich eine bestimmte
Bitfolge setzen muss, um den "AD Wandler B zu aktivieren". Stimmt das?
Falls es stimmt, würde ich diesen Code vorschlagen:
1
voidmain(){
2
while(1){
3
/*aktiviere den ADCB mit "unsigned, Freerun und 8-bit Genaugkeit"*/
4
ADCB_CTRLB=0b00001100;
5
/*
6
-nun müsste ich den "Kanal B1" (also die Temperatur) ausdrucken können
7
*/
8
printf("Die Temperatur ist: %u\n",ADCB_CH1_RES);
9
}
10
}
Bestimmt denke ich viel zu einfach. Was fehlt hier noch?
(Ich lasse das Gedöns mit dem Lautsprecher erstmal weg...)
Der ADC läuft nun von alleine im Hintergrund und liefert in seinen
Ergebnisregistern die Werte für Kanal 0 bis Kanal 2. Nummer 3 lassen wir
aus, weil da der Portpin PB3 zur Aktivierung des NTC ist, den du auf Low
setzen musst, damit der NTC vernünftige Werte liefert. Lesen des ADC ist
einfach:
Vielen Dank für deine Antwort erstmal Matthias.
Matthias S. schrieb:> Im Zip ist der Schaltplan für das Board als PDF. Ein wenig> unübersichtlich, aber vollständig.
Ok, auf der Schaltskizze sehe ich die englische Bezeichnung:
-"Phototransistor, Lightsensor": Das Board hat also einen Lichtsensor.
-"NTC TEMP": Das soll "Temperatursensor" bedeuten? Warum heisst es nicht
"Temperature sensor"?
Wenn ich nun die Linie verfolge steht am Ende "Lightsensor - 6" -->
"PB1(ACB1/ADCB1)".
Kannst du mir erklären, welche Schlussfolgerungen ich aus dieser
Feststellung ziehen kann?
Ich probiere nun erstmal selbst zu Schlussfolgerungen zu kommen, in dem
ich die AVR-Header-Datei für den Chip durchsuche:
-Wenn ich nach "PB1" in der AVR-Header Datei "iox128a1.h" suche, finde
ich nichts.
-Wenn ich nach "ACB1" in der AVR-Header Datei suche, finde ich wieder
nichts.
-Wenn ich nach "ADCB1" in der AVR-Header Datei suche, finde ich wieder
nichts.
Ok jetzt kann ich aber vielleicht von "ADCB1" auf "ADCB" kommen und nach
"ADCB" in der Header-Datei suchen (analog für "ACB1" -> "ACB"):
-Suche nach "ADCB":
Habe ich ja Dank deiner Ausführungen im vorherigen Post schon eine
Stelle in der AVR-Header-Datei gefunden, die meines Erachtens nach
wichtig sein könnte bei der Programmierung mit C. Dann habe ich aber
auch noch diese Zeile gefunden:
1
#define ADCB (*(ADC_t *) 0x0240) /* Analog to Digital Converter B */
2
/*
3
Hieraus schliesse ich, dass es eine Konstante mit dem Namen "ADCB" gibt vom Typ "ADC_t", der Typ "ADC_t" wiederum ist ein gewöhnliches C-Struct namens "ADC_struct".
4
*/
Wenn ich mir jetzt das gewöhnliche C-Struct "ADC_struct" anschaue sehe
ich folgenden Code:
1
/* Analog-to-Digital Converter */
2
typedefstructADC_struct
3
{
4
register8_tCTRLA;/* Control Register A */
5
register8_tCTRLB;/* Control Register B */
6
register8_tREFCTRL;/* Reference Control */
7
register8_tEVCTRL;/* Event Control */
8
register8_tPRESCALER;/* Clock Prescaler */
9
register8_treserved_0x05;
10
register8_tINTFLAGS;/* Interrupt Flags */
11
register8_treserved_0x07;
12
register8_treserved_0x08;
13
register8_treserved_0x09;
14
register8_treserved_0x0A;
15
register8_treserved_0x0B;
16
_WORDREGISTER(CAL);/* Calibration Value */
17
register8_treserved_0x0E;
18
register8_treserved_0x0F;
19
_WORDREGISTER(CH0RES);/* Channel 0 Result */
20
_WORDREGISTER(CH1RES);/* Channel 1 Result */
21
_WORDREGISTER(CH2RES);/* Channel 2 Result */
22
_WORDREGISTER(CH3RES);/* Channel 3 Result */
23
_WORDREGISTER(CMP);/* Compare Value */
24
register8_treserved_0x1A;
25
register8_treserved_0x1B;
26
register8_treserved_0x1C;
27
register8_treserved_0x1D;
28
register8_treserved_0x1E;
29
register8_treserved_0x1F;
30
ADC_CH_tCH0;/* ADC Channel 0 */
31
ADC_CH_tCH1;/* ADC Channel 1 */
32
ADC_CH_tCH2;/* ADC Channel 2 */
33
ADC_CH_tCH3;/* ADC Channel 3 */
34
}ADC_t;
-Suche nach "ACB":
1
#define ACB (*(AC_t *) 0x0390) /* Analog Comparator B */
2
/*
3
Hieraus schliesse ich, dass es eine Konstante mit dem Namen "ACB" gibt vom Typ "AC_t", der Typ "AC_t" wiederum ist ein gewöhnliches C-Struct namens "AC_struct".
4
*/
Wenn ich mir jetzt das gewöhnliche C-Struct "AC_struct" anschaue sehe
ich folgenden Code:
1
/* Analog Comparator */
2
typedefstructAC_struct
3
{
4
register8_tAC0CTRL;/* Comparator 0 Control */
5
register8_tAC1CTRL;/* Comparator 1 Control */
6
register8_tAC0MUXCTRL;/* Comparator 0 MUX Control */
7
register8_tAC1MUXCTRL;/* Comparator 1 MUX Control */
8
register8_tCTRLA;/* Control Register A */
9
register8_tCTRLB;/* Control Register B */
10
register8_tWINCTRL;/* Window Mode Control */
11
register8_tSTATUS;/* Status */
12
}AC_t;
Matthias S. schrieb:> Leider habe> ich kein Programmstück für eine einzigen Kanal, sondern immer nur sweeps> für mehrere:
Meinst du damit, dass der Chip es einfach nicht unterstüzt oder, dass du
einfach keinen anderen Code hast im Moment?
Habe nun mit deinen Tipps (etwas abgeänderter Code, finde die Konstanten
Definition "ADC" nicht so toll) den Lichtsensor mit folgendem Code zum
Ausgabe mit printf gebracht:
ADCB.CTRLB=0b00001100;/* ==> CONVMODE FREERUN RESOLUTION des ADCB einstellen.*/
67
ADCB.PRESCALER=ADC_PRESCALER_DIV8_gc;/* ==> Frage: Was bringt diese Zeile?*/
68
ADCB.REFCTRL=(0x01<<4);/* ==> Frage: Was bringt diese Zeile?*/
69
ADCB.EVCTRL=ADC_SWEEP_012_gc;/* ==> Frage: Was bedeutet "Channel Sweep" überhaupt?*/
70
ADCB.CALL=ReadCalibrationByte(offsetof(NVM_PROD_SIGNATURES_t,ADCBCAL0));/* Hier holt man irgendwelche Kalibrationswerte... */
71
ADCB.CALH=ReadCalibrationByte(offsetof(NVM_PROD_SIGNATURES_t,ADCBCAL1));/* Hier holt man irgendwelche Kalibrationswerte... */
72
ADCB.CH1.CTRL=ADC_CH_INPUTMODE_SINGLEENDED_gc;/* Was bedeutet "Single-ended input, no gain" ? */
73
ADCB.CH1.MUXCTRL=ADC_CH_MUXPOS_PIN1_gc;/* Wählt den Pin nummer 1 aus. Ist hier die Bezeichnung "PB1" gemeint?*/
74
}
75
76
intmain(void){
77
setUpSerial();
78
setupLightSensor();
79
80
while(1){
81
printf("ADCB.CH1RES: %u\n",ADCB.CH1RES);
82
_delay_ms(500);
83
}
84
85
USART_Rx_Disable(&USART);
86
USART_Tx_Disable(&USART);
87
}
Habe nun, aber weitere Fragen und zwar zu den Dingen, die in der Methode
"setupLightSensor()" passieren:
- Was bringt diese Zeile?:
1
ADCB.PRESCALER=ADC_PRESCALER_DIV8_gc;
Eigene Recherche:
- Im Dokument ( http://www.atmel.com/images/doc8077.pdf , Seite 290
) ist eine Skizze aufgemalt und Text bezüglich des "ADC" und seines
"Prescalers". Habe auch auf Wikipedia gelesen wozu ein Prescaler gut
sein soll, aber der Text setzt doch auch viel Vorwissen voraus. Kann man
Prescaler auch für Idioten erklären oder ist das zu komplex?
- Was bringt diese Zeile?:
1
ADCB.REFCTRL=(0x01<<4)
- Im vorher genannten Dokument auf Seite 298 steht, dass dadurch
"VCC/1.6" asugewählt wird. Was bedeutet das (bitte eine Erklärung für
Idioten)?
- Was bedeutet "Channel Sweep" überhaupt?
- Was bedeutet "Single-ended input, no gain" ?
- Wie kann ich diesen Code schreiben, so dass er "Interrupt gesteuert"
ausgeführt wird?
Peter Parker schrieb:> Wenn ich mir jetzt das gewöhnliche C-Struct "AC_struct" anschaue
Das ist der Analog Comparator, eine andere Peripherie als der ADC. Der
XMega hat viel Peripherie.
>> Leider habe>> ich kein Programmstück für eine einzigen Kanal, sondern immer nur sweeps>> für mehrere:>> Meinst du damit, dass der Chip es einfach nicht unterstüzt oder, dass du> einfach keinen anderen Code hast im Moment?
Ich habe nie Verwendung für nur einen Kanal gehabt und deswegen das
praktische Feature des ADC genutzt, mehrere Kanäle selbstständig zu
wandeln.
> - Was bringt diese Zeile?:ADCB.PRESCALER = ADC_PRESCALER_DIV8_gc;
Der Prescaler erzeugt den Arbeitstakt für den ADC und sollte so gewählt
werden, das die maximale Taktfrequenz des ADC nicht überschritten wird.
Wie hoch er ist, hängt davon ab, wie hoch der CPU Takt ist. Der ADC Takt
sollte für gute 12-bit Ergebnisse nicht höher als (1/3,5 µs) = 285 kHz
sein.
Peter Parker schrieb:> - Wie kann ich diesen Code schreiben, so dass er "Interrupt gesteuert"> ausgeführt wird?
Was meinst du mit Interrupt gesteuert? Wenn du den ADC zu bestimmten
Zeiten auslösen willst, kannst du ihn z.B. vom Timer triggern. Du kannst
auch Interrupts erzeugen, wenn der ADC mit einer Wandlung fertig ist.
Im Moment läuft er, ohne Rechenzeit zu brauchen, im Hintergrund.
Peter Parker schrieb:> - Was bringt diese Zeile?:ADCB.REFCTRL = (0x01<<4) - Im vorher> genannten Dokument auf Seite 298 steht, dass dadurch> "VCC/1.6" asugewählt wird. Was bedeutet das (bitte eine Erklärung für> Idioten)?
Hmm, wie kann man das idiotisch erklären? Die Referenz bestimmt die
obere Grenze des ADC Messbereiches. Die interne Struktur des XMega
leitet bei der o.a. Einstellung eine Spannung von (3,3/1,6)=2,06 V als
Referenz an den ADC. Somit misst der ADC zwischen 0 und 2,06 V.
Lies dir bitte im Family Manual (doc8077) den Abschnitt über den ADC
durch. Das musste ich auch, bevor ich die Dinge wie Channel Sweep usw.
kapiert habe.
Peter Parker schrieb:> finde die Konstanten> Definition "ADC" nicht so toll
Geschmackssache. Mein Code war nämlich für ADCA und ich habe ihn ganz
simpel auf ADCB mit dieser Definition umgestellt. Das würde bei dir nur
mit vielfachem Umtippen gehen :-P
Matthias erstmal Danke für die Zeit, die du dir nimmst.
Matthias S. schrieb:> Lies dir bitte im Family Manual (doc8077) den Abschnitt über den ADC> durch. Das musste ich auch, bevor ich die Dinge wie Channel Sweep usw.> kapiert habe.
Habe ich das richtig verstanden?
Also ein ADC wandelt ein analoges Signal (hier eine bestimmte Spannung)
in eine Bitfolge (Digitales Signal).
Der vorliegende Mikrocontroller kann sogar den Input des analogen
Signals wählen. Was ist aber nun der Unterschied zwischen:
- /* Single-ended input, no gain */
- /* Differential input, no gain */
Was kann ich von meinem Ergebnis im Register
1
ADCB.CH1RES
Lichtsensor erwarten?
Wird die Messung dadurch besser/schlechter? Sind besser/schlechter die
falschen Begriffe?