Forum: Compiler & IDEs MSP430 per ADC Sinusspannung auswerten


von Benjamin H. (faza)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

ich sitze gerade an einem kleinen Projekt.

Ich möchte mit einem MSP430 per ADC Sinuswerte in einem Array speichern.
Den MSP430 habe ich zusammen mit einem Funktionsgenerator verbunden.

An dem Funktionsgenerator habe ich als Beispiel, eine Sinusfunktion von 
20Hz einen Peak-to-Peak Wert von 2,5V und ein Offset von 1,25V 
eingestellt.

Mein Ziel ist es, per ADC 40 Mal abzutasten.

Aus dem Grund bin ich wie folgt hergegangen:
Da ich 40 Mal innerhalb einer Periode abtasten möchte, muss der ADC alle 
1,25ms abtasten.

Den DCO habe ich auf 150 kHz runtergeregelt und nochmal die SMCLK mit 
dem Divider durch 8 geteilt. So das der Timer nun eine Frequenz von 
18750 Hz beträgt.

Da ich alle 1,25ms abtasten möchte, bis sich ein Timer-Interrupt 
auslöst, habe ich den TACCR0 mit 23 initialisiert.


Leider bekomme ich aber dennoch keine sauberen Werte von den Frequenz.


Im Anhang sind die Werte vom Array zu sehen.

Hier das Programm:
--------------------------------
1
#include "msp430g2231.h"
2
3
unsigned int sin[40];
4
unsigned int i=0;
5
6
7
#pragma vector = TIMERA0_VECTOR
8
__interrupt void TIMERA0_sin (void)
9
{
10
  P1OUT ^= BIT0;
11
   
12
  
13
  if (i==39)
14
  {
15
    i = 0;
16
  }
17
  
18
  else
19
  {
20
    sin[i] = ADC10MEM;
21
    i++;
22
  } 
23
    
24
    TA0CCTL0&=~CCIFG;
25
}
26
27
28
void main( void )
29
{
30
  
31
  WDTCTL = WDTPW + WDTHOLD;     // Stop watchdog timer to prevent time out reset
32
  P1DIR |= BIT0 + BIT6;
33
  P1OUT &= ~BIT0 + BIT6;
34
  
35
  P1SEL |= BIT4;        // P1.4 als A/D-Eingang
36
37
  
38
  
39
  //------- Timer einstellungen ---------
40
  BCSCTL1 = RSEL2;
41
  DCOCTL = DCO0 + DCO1; // Kalibriere DCO auf 0,15 MHz
42
43
  TACTL |= TACLR;       // lösche alle Einstellungen in diesem Register
44
  TACTL |= TASSEL_2 + MC_1 + ID_3;     // Wähle SMCLK und UP-Mode
45
  TA0CCTL0 = CCIE;      // Interrupt-Enable Cap/Comp
46
  TACCR0 = 46;          // Initialisierung
47
  
48
  
49
 
50
  //------- ADC10 einstellungen ---------
51
  ADC10CTL0 &= ~ENC;    // ADC10 deaktivieren, ab jetzt darf eingestellt werden
52
53
  ADC10CTL1 |= INCH_4;  // ADC Eingang BIT4
54
  ADC10CTL1 |= ADC10SSEL_0 + ADC10SSEL_1;   // SMCLK auswählen
55
  ADC10CTL1 |= CONSEQ_2;        // einmalig
56
  
57
  ADC10CTL0 |= ADC10ON;         // Peripherie global einschalten
58
  ADC10CTL0 |= REFON + REF2_5V; // internen Generator für Referenz einschalten
59
  ADC10CTL0 |= MSC;             // Multisample einschalten  
60
  
61
  __bis_SR_register(GIE);       // Interrupts global aktivieren
62
  
63
  ADC10CTL0 |= ENC;             // ADC10 starten
64
  ADC10CTL0 |= ADC10SC;         // Konvertierung starten
65
}
--------------------------------

Hoffe ihr könnt mir weiterhelfen und für jede Hilfe bin ich dankbar.

--

Bitte Quelltext in [ c ] [ /c ] - Tags einschließen.
-rufus

: Bearbeitet durch User
von few words (Gast)


Lesenswert?

Also, für den A/D Wandler brauchst du eine ruhige und entkoppelt 
Versorgung. Jedes gezappele geht auf die Referenz und verfälscht den 
Messwert.

Wofür nimmst du den Timer? Der A/D Wandler hat einen eigenen Interrupt. 
Nutze die ISR vom A/D Wandler, dann gibt es keine Probleme mit dem 
Zugriff auf die Regiseter.

von Benjamin H. (faza)


Angehängte Dateien:

Lesenswert?

few words schrieb:
> Also, für den A/D Wandler brauchst du eine ruhige und entkoppelt
> Versorgung. Jedes gezappele geht auf die Referenz und verfälscht den
> Messwert.
>
> Wofür nimmst du den Timer? Der A/D Wandler hat einen eigenen Interrupt.
> Nutze die ISR vom A/D Wandler, dann gibt es keine Probleme mit dem
> Zugriff auf die Regiseter.


Vielen Dank für deine Antwort.

Verstehe ich das richtig das wenn ich den DCO runtertakte, der Timer vom 
A/D ebenfalls langsamer läuft und er deshalb solche Ergebnise liefert?

Ich habe nun, den Takt wieder auf 1MHz gelassen und die SMCLK von dem 
A/D Programmteil auskommentiert.

Ausserdem habe ich auch den Wert in TACCR0 auf 2500 hochgesetzt.

Ist denn meine Rechnung für die Initialisierung für den TACCR0 richtig?
Wenn ich für eine Periode 40 Abtastungen machen möchte komme ich ja wie 
oben beschrieben auf, 1,25ms.

Wenn der Takt vom DCO nun 1MHz beträgt, muss ich doch

1*10^6 x 1,25*10^-3   rechnen, richtig?

Wobei ich dann auf den Wert von 1250 komme.

Ich habe nun bewusst den doppelten Wert für den TACCR0 genommen, weil 
ich aus einem anderen Programm gesehen habe, um die LED am MSP430 eine 
Sekunde lang anbleibt und dann eine Sekunde aus, muss ich den Wert 
verdoppeln.

Ich verstehe ebenfalls nciht, wieso er mir nciht in den 40 Abtastungen 
eine Periode anzeigt, sondern mehrere.


Hoffe das es richtig war, den Timer im ADC Block auszukommentieren.
1
 
2
(....)
3
4
  //------- ADC10 einstellungen ---------
5
  ADC10CTL0 &= ~ENC;    // ADC10 deaktivieren, ab jetzt darf eingestellt werden
6
7
  ADC10CTL1 |= INCH_4;  // ADC Eingang BIT4
8
 // ADC10CTL1 |= ADC10SSEL_0 + ADC10SSEL_1;   // SMCLK auswählen
9
  ADC10CTL1 |= CONSEQ_2;        // einmalig
10
  
11
  ADC10CTL0 |= ADC10ON;         // Peripherie global einschalten
12
  ADC10CTL0 |= REFON + REF2_5V; // internen Generator für Referenz einschalten
13
  ADC10CTL0 |= MSC;             // Multisample einschalten  
14
  
15
  __bis_SR_register(GIE);       // Interrupts global aktivieren
16
  
17
  ADC10CTL0 |= ENC;             // ADC10 starten
18
  ADC10CTL0 |= ADC10SC;         // Konvertierung starten
19
}

: Bearbeitet durch User
von few words (Gast)


Lesenswert?

Nein, das hast du falsch verstanden. Der A/D Wandler hat einen eigenen 
Interrupt und meldete sich, wenn er fertig gewandelt hat. Du kannst den 
Interrupt ganz ohne Timer nutzen.

Wenn du unbedingt die Timer ISR verwenden willst, musst du in der ISR 
den A/D Wandler immer nur für eine Messung starten. Der A/D Wandler darf 
dann nicht frei laufen.

von Benjamin H. (faza)


Angehängte Dateien:

Lesenswert?

few words schrieb:
> Nein, das hast du falsch verstanden. Der A/D Wandler hat einen eigenen
> Interrupt und meldete sich, wenn er fertig gewandelt hat. Du kannst den
> Interrupt ganz ohne Timer nutzen.
>
> Wenn du unbedingt die Timer ISR verwenden willst, musst du in der ISR
> den A/D Wandler immer nur für eine Messung starten. Der A/D Wandler darf
> dann nicht frei laufen.


Danke für die Beschreibung.

Ich habe das jetzt dementsprechend geändert.

1
#include "msp430g2553.h"
2
3
unsigned int sin[160];
4
unsigned int i=0;
5
6
#pragma vector = ADC10_VECTOR 
7
__interrupt void ADC10_sin (void)
8
{
9
  
10
  if (i==159)
11
  {
12
    i = 0;
13
  }
14
  
15
  else
16
  {
17
    sin[i] = ADC10MEM;
18
    i++;
19
  } 
20
  
21
  
22
  ADC10CTL0 &= ~ADC10IFG;       // clear interrupt flag
23
  
24
}
25
26
27
void main( void )
28
{
29
  WDTCTL = WDTPW + WDTHOLD;     // Stop watchdog timer to prevent time out reset
30
31
32
//------- ADC10 einstellungen ---------
33
  ADC10CTL0 &= ~ENC;            // ADC10 deaktivieren, ab jetzt darf eingestellt werden
34
35
  ADC10CTL1 |= INCH_4;          // ADC Eingang BIT4
36
  ADC10CTL1 |= ADC10SSEL_0;     // ADC10OC auswählen
37
  ADC10CTL1 |= CONSEQ_2;        // Repeat single channel
38
  ADC10CTL1 |= ADC10DIV_4;      // Clock um 5 teilen
39
  
40
  ADC10CTL0 |= ADC10ON;         // Peripherie global einschalten
41
  ADC10CTL0 |= REFON + REF2_5V + SREF_1; // internen Generator für Referenz einschalten
42
  ADC10CTL0 |= MSC;             // A/D Wandlung zum schnellstmöglichen Zeitpunkt automatisch 
43
  ADC10CTL0 |= ADC10SHT_2;      // Sample and Hold auf 16
44
  
45
  ADC10CTL0 |= ADC10IE;         // ADC10 interrupt starten
46
  
47
  ADC10AE0  |= BIT4;             // ADC input enable P1.4
48
  
49
  __bis_SR_register(GIE);       // Interrupts global aktivieren
50
  
51
  
52
  ADC10CTL0 |= ENC;             // ADC10 starten
53
  ADC10CTL0 |= ADC10SC;         // Konvertierung starten
54
 
55
}


Ich habe nun wieder ein paar Fragen, bezüglich des Signals.

Im ersten Bild, sieht man den aufgezeichneten Verlauf der Sinuskurve.
Leider bekomme ich noch keine sauberen Werte. Ich habe den anschein, 
dass am ADC noch einiges eingestellt werden muss.

Denn mein vorläufiges Ziel ist es, das Programm so zu schreiben, dass er 
beliebige Frequenzen von 100 Hz - 20 kHz aufzunehmen und er immer sauber 
aufzeichnet.


Im zweiten Bild sieht man willkürliche Werte. Und die irritieren mich 
auch sehr. Obwohl ich den MSP430 an den Frequenzgenerator noch nicht 
angeschlossen habe, zeichnet der ADC10 Werte auf, die ich mir nicht 
erklären kann.


Hoffe ihr kennt die Antwort auf beide Fragen.

von Eric B. (beric)


Lesenswert?

Benjamin Hase schrieb:
> Im zweiten Bild sieht man willkürliche Werte. Und die irritieren mich
> auch sehr. Obwohl ich den MSP430 an den Frequenzgenerator noch nicht
> angeschlossen habe, zeichnet der ADC10 Werte auf, die ich mir nicht
> erklären kann.

Dem ADC ist es egal ob ein Funktionsgenerator angeschlossen ist oder 
nicht. Der misst einfach was an den Pin liegt. Wenn der Pin, wie ich 
vermute, frei in der Luft schwebt (also nicht mit Pull-up oder Pull-down 
irgendwo hin gezogen wird), dann misst der ADC Mist.

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.