MSP430F2013 Weiß jemand wie das mit dem Digital Filter Output und dem Oversampling geht? Die Werte bei einer Gleichspannung springen bei mir sehr. Ich triggere den ADC von aussen (200x/sec), und übernehme die Werte in einen anderen µP. // .... SD16CTL = SD16REFON + SD16SSEL_1; // 1.2V ref, SMCLK SD16INCTL0 = SD16INCH_1; // A1+/- SD16CCTL0 = SD16SNGL + SD16UNI + SD16IE ; // Single conv, //interrupt,unipolar SD16AE = SD16AE2; // P1.2 A1+; P1.3 A1- = VSS =>Löt 4 / 5 //.............. Könnte ich pro Aufruf mehrere Messungen machen lassen, und dann den Mittelwert abfragen/versenden? Oder muß ich das von Hand programmieren? Vielen Dank im Vorraus Dirk
Hallo, kann mir einer sagen was hier falsch ist bei der addition? bzw. wie das richtig in C geschrieben wird. //..................... if (OVS==1) { Wert4 = SD16MEM0; Wert = Wert1 + Wert2 + Wert3 + Wert4; Wert=Wert/4; Wert_Senden (); OVS=0; } //..................... auch.. Wert=Wert1 Wert+=Wert2 usw. gibt eine Wahrnung Vielen Dank Dirk
Hallo Rufus, die Meldung(!) lautet: [Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement Wert = Wert1 + Wert2 + Wert3 + Wert4; auch bei Wert+=Wert2; Also wie addiert mann/frau in 'C' für den MSP430F2013 Dirk
Ich nehme an, du willst einen gleitenden Mittelwert realisieren, oder? Da brauchst du eine Art Ringpuffer, der bei jedem Sample mit einem neuen Wert gefüllt wird. Nach dem neuen Wert musst du die letzten x Werte aufsummieren und wieder teilen. Für Werte 2^x geht das besonders gut, dann hast du schnelle Bitschiebe-Operationen. Das sieht dann bei mir folgendermaßen in der ADC12 ISR aus:
1 | SamplePointer = SampleCount & ModeMedianSampleMask; //ganz billiger Ringpuffer ;-) |
2 | // -> Index wird mit der Anzahl der Mittelwert-Samples -1 markiert
|
3 | // z.B. Anzahl 8 -> unterste 3 Bits werden 1 gesetzt,
|
4 | // -> Index läuft immer nur von 0 bis 7 durch
|
5 | |
6 | |
7 | ADCData0[SamplePointer] = ADC12MEM0; //Werte in die Puffer |
8 | ADCData1[SamplePointer] = ADC12MEM1; |
9 | ADCData2[SamplePointer] = ADC12MEM2; |
10 | ADCData3[SamplePointer] = ADC12MEM3; |
11 | |
12 | unsigned char i; |
13 | unsigned char j; |
14 | |
15 | |
16 | i = ModeMedianSampleCount; |
17 | j = (SamplePointer -i) & ModeMedianSampleMask; |
18 | |
19 | MedianValue0 = ADCData0[j]; //Neue Startwerte in Mittelwert |
20 | MedianValue1 = ADCData1[j]; |
21 | MedianValue2 = ADCData2[j]; |
22 | MedianValue3 = ADCData3[j]; |
23 | |
24 | i--; |
25 | |
26 | while(i) //restliche n-1 Werte aufsummieren |
27 | {
|
28 | j = (SamplePointer -i) & ModeMedianSampleMask; //Position im "Ringpuffer" neu berechnen |
29 | MedianValue0 += ADCData0[j]; |
30 | MedianValue1 += ADCData1[j]; |
31 | MedianValue2 += ADCData2[j]; |
32 | MedianValue3 += ADCData3[j]; |
33 | i--; |
34 | }
|
35 | |
36 | |
37 | MedianValue0 = MedianValue0 >> ModeMedianSampleBitShift; //Ales nochma rumschieben.... |
38 | MedianValue1 = MedianValue1 >> ModeMedianSampleBitShift; |
39 | MedianValue2 = MedianValue2 >> ModeMedianSampleBitShift; |
40 | MedianValue3 = MedianValue3 >> ModeMedianSampleBitShift; |
41 | |
42 | |
43 | ADC12IFG = 0x00; // Flags löschen |
44 | ADC12CTL0 |= ADC12SC; // schon mal Start conversion....kann ja nich schaden, spart zeit am Ende. |
Die nötigen Werte werden vor dem Sampling-Start irgendwoanders folgendermaßen initialisiert, um zeit zu sparen:
1 | if(samples == 2)ModeMedianSampleBitShift = 0; |
2 | if(samples == 4)ModeMedianSampleBitShift = 1; |
3 | if(samples == 8)ModeMedianSampleBitShift = 2; |
4 | if(samples == 16)ModeMedianSampleBitShift = 3; |
5 | |
6 | ModeMedianSampleMask = ModeMedianSampleCount - 1; |
Geht natürlich in der einfachen Form nur für 1,2,4,8 oder 16 Mittelungen, dann ist der 16 Bit Wertebereich für die ADC12 Summen-Werte erschöpft.
Hallo Christian R., ergentlich wollte ich bei jedem triggern 4x hintereinander messen und aus den 4 Messungen dann den Mittelwert bilden. Den Code habe ich schon geschrieben, aber die Zeilen mit der Addition will er einfach nicht haben. Danke für das Beispiel Dirk
Hallo, habe die Vars verändert volatile unsigned long ADC_Wert; =>> long ADC_Wert; nun kommt keine Meldung mehr. Danke, einfach zuwenig 'C' Dirk
Na, jetzt hast Dus durch probieren rausbekommen - aber weißt Du auch, was Du gemacht hast und warum volatile diese Warnung erzeugt?
Hallo Uhu Uhuhu, nein habe die Sache bisher nicht weiter verfolgt, bin an den Vorbereitungen für die Digitalen Filtern dran. Leider habe ich nur ein Multimeter, und muß deshalb alles schichtweise aufbauen und auch verbessern(4fach messen je Wert). Meine Soundkarte(Uralt) gibt was sinusartige ab 7Hz aus, ab ca. 15Hz kann ich es gebrauchen. Das Bild zeigt einen 25Hz Sinus (teilweise, noch schlechte Fototechnik)) - von der Soundkarte - über den ADC vom MSP430F2013 ( 4fach gemessen Mittelwert ) - zu einem zweiten µP (Propeller) (Quarz, triggern ++) - über RS232 zum PC - über VB6 auf den Monitor Aber wenn Du möchtest, Warum? Dirk
Hallo Uhu Uhuhu, habe nochmal über Deine 'Frage' nachgedacht. Die Frage die Du gestellt hast hilft mir nicht weiter! Es ist keinerlei Tip/Hinweis vorhanden. z.B PDF, Stichworte, usw. All_so hast DU die Frage für DICH gestellt, und möchtest mich als Bühne benutzen. Du liest mindestens einen Teil des Hin und Hers, verschenkst all_so doch schon eine Menge Zeit. Aber warum, dann keinen kleinen Tip? Einen moralischen Zeigefinger, oder überholte Lernmodele helfen nicht bei mir. Ich bin alt und auch noch stur. Mir soll das ganze auch freude machen, und ich erwarte von keinem das er den Code für mich schreibt. Leider sind die moderen Themen erstaunlich komplex und als Anfänger bzw. Hobby-Erfinder ist es schon ein hartes Brot, und den einen oder andern Tip, auch unverdient(unberechtigt) währe nicht nur eine schöne Geste. Ich bin schon sooooft gegen die Wand gelaufen, das ich das Lernmodel nicht mehr unterstützen möchte. Wenn DU eine Frage hast, würde ich Dir gerne weiterhelfen. Leider bin ich noch nicht Fit, und viele Unklarheiten schränken das ein, was ich schon gefunden habe. All_so, warum? Dirk
>> Die Werte bei einer Gleichspannung springen bei mir sehr.
Sag mal, wie sehr springt denn der Wert ? ich habe arge Zweifel das ne
4fach Messung das schon beseitigt.
Ich hab mir mal die Zähne dran ausgebissen. Der F2013 hat in der
Hinsicht ein paar Tücken.
Du solltest die VREF abblocken (siehe Datenblatt), die VREF muß zu
diesem Zweck auf den Ausgang geschaltet werden.
P1SEL_bit.P1SEL_3 = 1; // Referenz auf den Ausgang
Dann Errata Sheets lesen (center 1,2V temp. drift 50ppm/K), hier mußt du
einen Korrektur Wert (0xBF) schreiben.
Der ADC IN- gehört an Masse (du verwendest ja den unipolaren Modus.
Dann kannst du mit den Filtern mal experimentieren (OSR=1024 ergibt bei
mir die besten Ergebnisse).
Hardware, Layout, 16 BIT bei einer Eingangsspg. von 0 - 0,6 V, rechne
das mal aus. Wenn du dir große Mühe gibst dann holst du stabile 15 BIT
heraus (128 Mittelwerte vorraus gesetzt).
Es gibt also noch ein paar Denksportausgaben.
Hallo Joe, erstmal vielen Dank! Denksport mit Aussichten finde ich gut. Also, mit einem selbstgebauten VB6 Ozi (200Messungen/sec.) hatte ich den optischen Eindruck das sich das Springen ungefähr halbiert hat. Wahrscheinlich gibt es noch irgendwelche Störungsignale im System und es liegt noch nicht am ADC. Danke, mit den meisten Tips werde ich klarkommen, auch die Art ist fein für mich. Aber leider geht es erst am Wochenende weiter für mich. Frage: - viele Wandlungen/sec. schafft er den. Habe keine Angaben für den F2013 gefunden. (Ich bin mal auf 3000 in zwei Sec. gewessen, aber da gab es noch mehrere Fehler bei meinen Frequenzeinstellungen und im gesammten Wechselspiel) // Zur Zeit habe ich das, kann natürlich erweitert werden ........................ // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { P1IFG &= ~0x10; // P1.4 IFG cleared P1OUT |= 0x20; // Data 'H' => warten auf ADC_Wert OVS=3; // Public oversampling + 1 ADC_Wert=0; // Public SD16CCTL0 |= SD16SC; // Set bit to start conversion ADC } #pragma vector = SD16_VECTOR __interrupt void SD16ISR(void) { ADC_Wert += SD16MEM0; OVS=OVS-1; if (OVS==0) { ADC_Wert=ADC_Wert/4; // OVS +1 ADCWert_Senden (); } else { SD16CCTL0 |= SD16SC; // Set bit to start conversion ADC } }
Hallo Dirk, > All_so hast DU die Frage für DICH gestellt, > und möchtest mich als Bühne benutzen. Beileibe nicht. Ich findes es gut, daß Du das Problem selbst gelöst hast. Nicht gut finde ich, daß Du offenbar nur rumprobiert hast, ohne zu wissen, was Du tust. Was macht volatile und warum mault der Compiler [Pa082]: undefined behavior: the order of volatile accesses is undefined wenn Du Wert = Wert1 + Wert2 + Wert3 + Wert4; schreibst und die Wert<n> vom Typ volatile unsigned long sind - das ist doch die Frage, die Du Dir hier stellen müßtest. Also, hier ist die Erklärung: Volatile sagt dem Compiler, daß sich der Inhalt der Variablen zu jeder Zeit ändern kann - z.B. durch eine Interrupt-Service-Routine. Der Compiler lädt deshalb volatile-Variable vor jedem Gebrauch neu und hält sie nicht in einem Register (was den Code meistens aufbläht, deswegen sollte man volatile nur benutzen, wenn es wirklich so ist). Aber warum resultiert aus einer Addition von volatile-Variablen undefiniertes Verhalten? Ganz einfach: Per Definition werden in C Ausdrücke von links nach rechts abgearbeitet - natürlich unter Berücksichtigung der 'Vorfahrtregeln'. Bei volatile Variablen hat der Compiler die Freiheit, die Reihenfolge der Ladeoperationen anders als von links nach rechts anzuordnen und da er solche Variable nicht in einem Register halten kann - die Urkopie kann sich ja jederzeit ändern - ist Abarbeitung von links nach rechts nicht mehr garantiert. Deshalb die Warnung. Angenommen, man schreibt folgende Anweisung: Wert = Wert1 + Wert1 + Wert2 + Wert1; und Wert1 ändert sich zufällig in dem Moment, wo Wert2 dazuaddiert wird, dann kommt u.U. ein falsches Ergebnis heraus und die Ursache solcher Fehler ist sehr schwer zufinden, weil sie nur sporadisch auftreten ohne Kausalzusammenhang mit dem Code, in dem sie auftreten und sehr schnell ablaufen. Per Einzelschritt im Debugger kann man sie nicht finden.
Hallo Uhu Uhuhu, mit der 'Bühne', da sind mir die Pferde durchgegangen und noch nicht mal wegen Dir. Und das Du mir trotzdem antwortest finde ich gut. Und der Inhalt der Antwort hat es in sich. Ist mir nun klarer geworden. Die definition Veränderung kamm erst wirklich ganz am Ende und eher aus purem frust. Da hatte ich schon eine Menge Gegoogelt, wegen 'C', alle Beispiele durchsucht und konnte es nicht fassen wieso eine solche Zeile bei mir nicht laufen sollte. Die definition 'volatile unsigned' hatte ich aus einem Beispiel copiert, und hatte sowas im Kopf, das in der Einzelschrittsteuerung auch dieser Wert geprüft werden kann. (irgendwo angelesen und nicht verdaut). Das sind meine ersten Begegnungen mit 'C'und 'Spin' und µP. Das die Interrupt-Service-Routine mit dem µP-Clock gesteuert werden und somit jede Code Zeile trennen können ist mir erst jetzt bewuster geworden. Möglicherweise habe ich noch so ein duzent halbgare geschichten, die alles irgendwie zäh werden lassen. Im Simulationsbetrieb geht er nicht in die Interrupts rein obwohl ich sie von Hand auslöse. Fehlt eine Einstellung oder habe ich ein Denkfehler. Ich habe den 2013 aus dem USB-Stick rausgenommen, mit zwei Drähten verbunden. (externe Stromversorgung) - programmieren kann ich ihn - das Prog. bleibt auch drin aber ich muß immer erst den Stick wieder einstecken, damit das Program startet. Dannach kann ich ihn wieder raus ziehen und es läuft weiter bis zum Abschalten der Stromversorgung Zu beiden Geschichten habe ich noch nichts in den PDFs gefunden. Vielen Dank Uhu (Uhuhu) (muß nun arbeiten) Dirk
>> aber ich muß immer erst den Stick wieder einstecken, damit das Program >> startet. Schau dir mal die Resetbeschaltung an, hängt dein Reset (wenn nicht mit dem Stick verbunden) in der Luft ? Ich werde mir morgen (im Moment keine Zeit) deinen Thread noch mal vornehmen und die Tipps ausformulieren. Viel Erfolg bis dahin.
> Schau dir mal die Resetbeschaltung an, hängt dein Reset (wenn nicht > mit dem Stick verbunden) in der Luft ? Darauf würde ich auch tippen - ich hatte das Problem auch schon.
Hallo Joe, Hallo Uhu Uhuhu, mir war heute nicht so gut auf der Arbeit, also bin ich wieder vor der Schaltung. Muß das morgen nacharbeiten. All_so nun zum guten Teil des Tages: Lötstift 10 oder der Zweite von rechts von den 4 Stiften des USB-Steckers. Es stimmt kurzer Reset-Impuls. Bei mir muß auch die RS-Schnittstelle neu geöffnet werden. Beides zusammen wirkt. Habe zwar die RS entkoppelt, aber irgendwie haut sie noch durch. Mein anderer µP hat einen Autoreset, wenn Spannung angelegt wird. Ist schon witzig. In Endaufbau heißt es dann + Widerstand nach C nach Masse, zwischen Wiederstand und Masse, dann den Reset. (Plus >---###--x--||--> Masse | | => Reset Lötstift 10 Ich habe den Träger rausgenommen, und mit 2Ltg (Löt 10/11) zum Programmieren an den kleine Stecker des USB-Stickes gelötet(hatte keinen so kleinen Stecker). Alle andern(12) habe ich auf eine Lötleiste gelegt, von da gehe ich zum Demoboard des Propellers(- + I/Os ). Hierdurch ist mir die dop. Belegung entgangen bzw. habe auch keinen Reset erwartet. Hallo Joe, ist zwar eine sehr schöne Idee, aber bis morgen wird sich sehr viel im Prg verändert haben oder ich stehe wieder heulend auf der Matte. Vielen Dank, die Liste wird kürzer, was kann ich für euch tun? Dirk
Hallo Dirk, sei mir nicht böse, aber mit 'Was kann ich für Sie tun?' assoziiere ich immer Telekom etc. und Dienst nach Vorschrift... kotz, würg. Ich hab noch einen kleinen Nachtrag zum Thema volatile: volatile long ist auf dem MSP430 richtiggehend gemeingefährlich: Der Prozessor ist 16 bit breit, die long-Typen 32. Wenn auf ein volatile long zugegriffen werden soll, dann sind dafür zwei Maschinenbefehle notwendig. Angenommen, Du hast einen Inkremantalgeber, der zwischen -1 und 0 herumdümpelt, dann wechselt der Wert zwischen 0xffffffff und 0x00000000. Wenn es der Zufall will, daß der Wechsel der Variablen genau nach dem Zugriff auf ein Teilwort stattfindet, dann rechnet der Prozessor plötzlich nicht mit 0xffffffff oder 0x00000000, sondern mit 0xffff0000 oder 0x0000ffff - ein Wort stammt vom vorherigen Wert, eins vom aktuellen. Auf dem MSP430 muß man deshalb vor dem Zugriff auf ein volatile long die Interrupts sperren. Warum verwendest Du eigentlich für ADC_Wert ein long? Der ADC des 2013 liefert 16 Bit, da reicht ein int-Typ aus.
Hallo Uhu Uhuhu, Ich habe nach Public gesucht in den Beispielen und dann copiert. Dann bei dem 4fach Messen war es einfach, erst addieren dann teilen. Und eine Gefahr war nicht in Sicht. Leider hat sich grade die ganze Schaltung verabschiedet. Muste einiges umlöten. Habe von SD16INCH_1 nach SD16INCH_4 umgearbeitet damit ich die Ref auf P1.3 legen kann (P1SEL=0x08?). Hatte zwar mit den Fingern gute Anzeige, aber ansonst lief weder Rechteck noch Audiokarte gegen Masse. Bei dem ganzen gelöte, umprogrammieren und C an Ref legen usw. habe ich wohl einen hochgeladen Kondensator an +/- 3,3V angeschlossen. Das hat sich wohl durchgefressen bis in Spannungsstabilisierung. Der Msp ist Ok, kleiner Test nur über USB (klein, zäh und tapfer). Die Spannungsstabilisierung ist hin, den Propeller kann ich noch nicht testen. Warscheinlich muß ich jetzt am Sonntag mit zum Spaziergang durch das grüne Zeug. Wünsche euch ein schönes Wochenende Dirk
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.