www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP430F1612 ADC12 Problem


Autor: Mathias U. (munter)
Datum:

Bewertung
0 lesenswert
nicht 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
void main()
{
  WDTCTL = WDTPW+WDTHOLD;                           // Stop watchdog timer
  P6SEL |= 0x03;                                    // Enable A/D channel A0 und A1; P6.0 & P6.1
  ADC12CTL0 = ADC12ON+SHT0_2+REFON+REF2_5V;         // ADC12ON --> schaltet ad-wandler ein
                                                    // SHT0_2  --> clocks für sample-time
                                                    // REFON   --> interne referenz an
                                                    // REF2_5  --> referenz auf 2.5V
  ADC12CTL1 = SHP;                                  // Use sampling timer
  ADC12MCTL0 = SREF_1;                              // Vr+=Vref+

  wait(3600);                                       // wartezeit, damit referenzspannung steht...

  ADC12CTL0 |= ENC;                                 // Enable conversions

  for(;;)
  {  
    // ersten kanal einlesen...
    ADC12CTL0 |= ADC12SC;                           // ADC12 starten
    while ((ADC12IFG & BIT0)==0);                   // solange, wie interruptflag (IFG) nicht
                                                    // gesetzt wurde...wandle 
    adcwert = ADC12MEM0;
    adcwert_mV = (float) (((float)ADC12MEM0 / 4096.0) * 2500.0); // Wert in mV
 
  // zweiten kanal einlesen
// --> hier muss noch der kanal umgeschalten werden...aber wie??
    ADC12CTL0 |= ADC12SC;                           // ADC12 starten
    while ((ADC12IFG & BIT0)==0);                   // solange, wie interruptflag (IFG) nicht
                                                    // gesetzt wurde...wandle 
    adcwert1 = ADC12MEM0;
    adcwert_mV1 = (float) (((float)ADC12MEM0 / 4096.0) * 2500.0); // Wert in mV
  
    _NOP();   
  }
}   // 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

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nimm den Sequenzer, im Single Sequence Modus.
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:
ADC12MCTL0 = SREF_1 + INCH_0;
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.

Autor: Mathias U. (munter)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Mathias U. (munter)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kanns momentan nicht testen, aber es müsste so gehn:
ADC12MCTL0 = INCH_0 + SREF_1;                   // P6.0
ADC12CTL0 |= ADC12SC;                           // ADC12 starten

while ((ADC12IFG & BIT0)==0);                   // Warte auf Wandlungsende 
adcwert = ADC12MEM0;                            // Wandlungsergebnis

//Auswertung

ADC12MCTL0 = INCH_1 + SREF_1;                   // P6.1
ADC12CTL0 |= ADC12SC;                           // ADC12 starten
while ((ADC12IFG & BIT0)==0);                   // Warte auf Wandlungsende  
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.

Autor: Mathias U. (munter)
Datum:

Bewertung
0 lesenswert
nicht 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...
void main()
{
  WDTCTL = WDTPW+WDTHOLD;                           // Stop watchdog timer
  P6SEL |= 0x03;                                    // Enable A/D channel A0 und A1; P6.0 & P6.1
  ADC12CTL0 = ADC12ON+SHT0_2+REFON+REF2_5V;         // ADC12ON --> schaltet ad-wandler ein
                                                    // SHT0_2  --> clocks für sample-time
                                                    // REFON   --> interne referenz an
                                                    // REF2_5  --> referenz auf 2.5V
  ADC12CTL1 = SHP;                                  // Use sampling timer
  wait(3600);                                       // wartezeit, damit referenzspannung steht...

  for(;;)
  { 
    // kanal 1 wandeln
    ADC12MCTL0 = INCH_0 + SREF_1;                   // P6.0
    ADC12CTL0 |= ENC + ADC12SC;                     // ADC12 starten

    while ((ADC12IFG & BIT0)==0);                   // warte auf wandlungsende 
    adcwert = ADC12MEM0;                            // wandlerwerte in adcwert
    adcwert_mV = (float) (((float)ADC12MEM0 / 4096.0) * 2500.0); // wert in mV
    
    ADC12CTL0 &= ~ENC;                              // ADC12 stoppen

    // kanal 2 wandeln
    ADC12MCTL0 = INCH_1 + SREF_1;                   // P6.1
    ADC12CTL0 |= ENC + ADC12SC;                     // ADC12 starten
    
    while ((ADC12IFG & BIT0)==0);                   // warte auf wandlungsende  
    adcwert1 = ADC12MEM0;                           // wandlerwerte in adcwert1
    adcwert_mV1 = (float) (((float)ADC12MEM0 / 4096.0) * 2500.0); // wert in mV 
  
    ADC12CTL0 &= ~ENC;                              // ADC12 stoppen
   
    _NOP();   
  }
}   // 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.