Forum: Mikrocontroller und Digitale Elektronik MSP430F1612 ADC12 Problem


von Mathias U. (munter)


Lesenswert?

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

von Christian R. (supachris)


Lesenswert?

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.

von Mathias U. (munter)


Lesenswert?

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

von Christian R. (supachris)


Lesenswert?

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.

von Mathias U. (munter)


Lesenswert?

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

von Christian R. (supachris)


Lesenswert?

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.

von Mathias U. (munter)


Lesenswert?

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.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.