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
unsignedintsin[40];
4
unsignedinti=0;
5
6
7
#pragma vector = TIMERA0_VECTOR
8
__interruptvoidTIMERA0_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
voidmain(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
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
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.
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
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.
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
unsignedintsin[160];
4
unsignedinti=0;
5
6
#pragma vector = ADC10_VECTOR
7
__interruptvoidADC10_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
voidmain(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.
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.