Hallo, ich weiss, dass es zu dem Thema ADC hier ne Menge Beiträge gibt,
aber deren Inhalt hat mich leider nicht weitergebracht.
Kurz zur Hardware & Software:
MSP430F1612
IAR Emb. Workbench 3.21A
Sprache: C
Jetz mein Problem:
Ich habe ein Beispiel zum ADC12 von TI genommen, ausprobiert und es geht
soweit ganz gut. Ich kann jatzt die angelegte Spannung an einem Pin
erfassen, wandeln und weiterverarbeiten.
Im Beispiel (fet140_adc12_02.c) wird der ADC A0 genommen...also P6.0.
Schön und gut, aber wenn ich versuche, den A1, also P6.1 zu nehmen, dann
geht es nicht.
Ich habe an A0 eine Spannung dran, und an A1 eine andere Spannung.
Jetzt dachte ich, dass wenn ich P6SEL |= 0x02 mache, dann wird
automatisch der Kanal gewählt, für den am Port die Zweitfunktion (ADC)
aktiviert ist.
Aber er nimmt trotzdem den A0.
Hier erstmal kurz der Code
1 | void main()
| 2 | {
| 3 | WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer
| 4 | P6SEL |= 0x03; // Enable A/D channel A0 und A1; P6.0 & P6.1
| 5 | ADC12CTL0 = ADC12ON+SHT0_2+REFON+REF2_5V; // ADC12ON --> schaltet ad-wandler ein
| 6 | // SHT0_2 --> clocks für sample-time
| 7 | // REFON --> interne referenz an
| 8 | // REF2_5 --> referenz auf 2.5V
| 9 | ADC12CTL1 = SHP; // Use sampling timer
| 10 | ADC12MCTL0 = SREF_1; // Vr+=Vref+
| 11 |
| 12 | wait(3600); // wartezeit, damit referenzspannung steht...
| 13 |
| 14 | ADC12CTL0 |= ENC; // Enable conversions
| 15 |
| 16 | for(;;)
| 17 | {
| 18 | // ersten kanal einlesen...
| 19 | ADC12CTL0 |= ADC12SC; // ADC12 starten
| 20 | while ((ADC12IFG & BIT0)==0); // solange, wie interruptflag (IFG) nicht
| 21 | // gesetzt wurde...wandle
| 22 | adcwert = ADC12MEM0;
| 23 | adcwert_mV = (float) (((float)ADC12MEM0 / 4096.0) * 2500.0); // Wert in mV
| 24 |
| 25 | // zweiten kanal einlesen
| 26 | // --> hier muss noch der kanal umgeschalten werden...aber wie??
| 27 | ADC12CTL0 |= ADC12SC; // ADC12 starten
| 28 | while ((ADC12IFG & BIT0)==0); // solange, wie interruptflag (IFG) nicht
| 29 | // gesetzt wurde...wandle
| 30 | adcwert1 = ADC12MEM0;
| 31 | adcwert_mV1 = (float) (((float)ADC12MEM0 / 4096.0) * 2500.0); // Wert in mV
| 32 |
| 33 | _NOP();
| 34 | }
| 35 | } // ende main
|
Wenn ich jetzt statt
ADC12MCTL0 = SREF_1;
ADC12MCTL0 = SREF_1 + INCH_1;
mache, dann nimmt er nur A1.
Was ich aber dann eigentlich machen möchte, ist dass ich erst A0 wandle,
und dann danach A1.
Ich möchte single conversion machen. Ich weiß, dass es sicher auch mit
einer Sequenz geht, aber das möchte ich erstmal nicht machen.
Das Wandlungsergebnis landet ja immer in MEM0. Kann ja auch...
Er soll nur nach dem Wandeln den A0 auf A1 umschalten. Das muss doch
gehen, oder?
Wie stell ich das am besten an? Hat einer einen entscheidenden Tipp?
Oder WAS muss ich genau machen, damit er mir NUR nen A1 wandelt? Die
Sache mit P6SEL |= 0x02; geht ja irgendwie nicht...
Danke
mathias
Nimm den Sequenzer, im Single Sequence Modus.
1 | while ((ADC12IFG & BIT0)==0); // solange, wie interruptflag (IFG) nicht
|
musst du BIT0 auf BIT1 ändern, wenn du nach der Wandlung von Channel 1
statt 0 die Daten haben willst.
Das geht aber nur, wenn du eine einmalige Sequenz startest, und beim
Init folgendes machst:
1 | ADC12MCTL0 = SREF_1 + INCH_0;
| 2 | ADC12MCTL1 = SREF_1 + INCH_1 + EOS;
|
Dann Startet der Sequenzer die Messung bei Channel 0, Ergebnis geht in
ADC12MEM0, dann wandelt er Channel 1, Ergenis in ADC12MEM1, da dort dann
das EOS (End of Sequence) Bit gesetzt ist, hält er an, und startet erst
wieder, wenn du das SC bit setzt.
Danke Dir erstmal, aber das ist die Sache mit der Sequenz, die ich
erstmal nicht machen wollte...
Es muss doch auch möglich sein, die Wandlung einzeln zu machen...
Also quasi:
ADC12 starten --> A0 wandeln --> wegen mir ADC12 stoppen... --> ADC12
neu konfigurieren --> ADC12 starten --> A1 wandeln... --> zurück zum
Anfang...
Naja, ich werde morgen doch mal die Sache mit der Sequenz
versuchen..AUSSER, es hat jemand doch noch nen Tipp für mich, wie ich es
ohne hinbekomme...
(ob die Sache jetzt Sinn macht, sei erstmal dahingestellt ;-) )
danke
mathias
Na gut, so von hinten durch die Brust ins Auge geht natürlich auch.
Musst dann immer das ADC12MCTL0 anpassen, das Ergebnis landet immer in
ADC12MEM0 dann.
Und immer wenn du das SC Bit setzt, wird wieder ein Wert gewandelt.
Die Frage für mich ist, WIE ich das am besten mache? Ich hab schon
soviele Sachen rumprobiert...mit den ADC12MCTLx - Regsitern...bin noch
auf keinen grünen Zweig gekommen...
Das das Ergebnis immer in ADC12MEM0 landet ist mir klar. Kann ja auch...
Aber an welcher Stelle muss ich denn WIE das ADC12MCTL0 anpassen?
Es hat irgendwas mit INCH_0 oder INCH_1 zu tun, aber was und wie?
danke
Ich kanns momentan nicht testen, aber es müsste so gehn:
1 | ADC12MCTL0 = INCH_0 + SREF_1; // P6.0
| 2 | ADC12CTL0 |= ADC12SC; // ADC12 starten
| 3 |
| 4 | while ((ADC12IFG & BIT0)==0); // Warte auf Wandlungsende
| 5 | adcwert = ADC12MEM0; // Wandlungsergebnis
| 6 |
| 7 | //Auswertung
| 8 |
| 9 | ADC12MCTL0 = INCH_1 + SREF_1; // P6.1
| 10 | ADC12CTL0 |= ADC12SC; // ADC12 starten
| 11 | while ((ADC12IFG & BIT0)==0); // Warte auf Wandlungsende
| 12 | adcwert1 = ADC12MEM0; // Wandlungsergebnis
|
Die INCH-Bits geben an, welcher Kanal gesampelt werden soll (P6.0 bis 7,
Temp, VCC/2, Ref-Spannung....)
Jedes ADC12-Memory Register kann jeden Kanal sampeln.
Eventuell musst du das ENC Bit nach der Wandlung vor dem Umschalten des
Kanals zurücksetzen.
Ich danke Dir Christian!
Ich dächte, ich hätte es gestern Abend schon mal so gehabt, aber
wahrscheinlich hat da ne Kleinigkeit gefehlt!
Hier nochmal mein jetziger Code, der so funktioniert, wie ich es
wollte... 1 | void main()
| 2 | {
| 3 | WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer
| 4 | P6SEL |= 0x03; // Enable A/D channel A0 und A1; P6.0 & P6.1
| 5 | ADC12CTL0 = ADC12ON+SHT0_2+REFON+REF2_5V; // ADC12ON --> schaltet ad-wandler ein
| 6 | // SHT0_2 --> clocks für sample-time
| 7 | // REFON --> interne referenz an
| 8 | // REF2_5 --> referenz auf 2.5V
| 9 | ADC12CTL1 = SHP; // Use sampling timer
| 10 | wait(3600); // wartezeit, damit referenzspannung steht...
| 11 |
| 12 | for(;;)
| 13 | {
| 14 | // kanal 1 wandeln
| 15 | ADC12MCTL0 = INCH_0 + SREF_1; // P6.0
| 16 | ADC12CTL0 |= ENC + ADC12SC; // ADC12 starten
| 17 |
| 18 | while ((ADC12IFG & BIT0)==0); // warte auf wandlungsende
| 19 | adcwert = ADC12MEM0; // wandlerwerte in adcwert
| 20 | adcwert_mV = (float) (((float)ADC12MEM0 / 4096.0) * 2500.0); // wert in mV
| 21 |
| 22 | ADC12CTL0 &= ~ENC; // ADC12 stoppen
| 23 |
| 24 | // kanal 2 wandeln
| 25 | ADC12MCTL0 = INCH_1 + SREF_1; // P6.1
| 26 | ADC12CTL0 |= ENC + ADC12SC; // ADC12 starten
| 27 |
| 28 | while ((ADC12IFG & BIT0)==0); // warte auf wandlungsende
| 29 | adcwert1 = ADC12MEM0; // wandlerwerte in adcwert1
| 30 | adcwert_mV1 = (float) (((float)ADC12MEM0 / 4096.0) * 2500.0); // wert in mV
| 31 |
| 32 | ADC12CTL0 &= ~ENC; // ADC12 stoppen
| 33 |
| 34 | _NOP();
| 35 | }
| 36 | } // ende main
|
Erst wird der erste Kanal gewandelt, dann der ADC12 abgeschalten.
Dann wird der zweite Kanal gewandelt und danach wieder der ADC12
abgeschalten. Das ganze in einer Endlosschleife.
Wie gesagt, über den Sinn DIESER Methode lässt sich sicher streiten! ;-)
mathias
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|