Archiv verlassen und diese Seite im Standarddesign anzeigen : Abspeichern von Messdaten ist bestimmten Zeitabständen
helipaddi
02.03.2010, 07:28
Guten Morgen,
vielleicht könnt ihr mir bei diesem kleinem Problem helfen! Ich muss Messdaten, welche in der Hauptschleife erstellt werden, in definierten Zeitabständen auf eine Sd Karte speichern. Dazu benutze ich einen Timer der mit 25hz läuft.
Eigentlich sollten dann nach 2 min 3000 Einträge auf der Karte gespeichert sein. Dies stimmt aber leider nicht...
Wisst ihr wo das Problem sein könnte?
Danke schonmal für eure Hilfe.
Gruß,
Patrick
Sorry aber mit so wenigen Infos und ohne Code zu posten wird dir hier wohl kaum jemand helfen können.
oberallgeier
02.03.2010, 08:56
... Messdaten ... auf eine Sd Karte speichern ... Timer der mit 25hz ... wo das Problem sein könnte ...KÖNNTE: Vermutlich speicherst Du in der ISR *baaa* oder 25 x Abspeichern dauert länger als 1 sec, oder Speichertiming stört Karte, oder oder oder. Aber natürlich hat maw_hn recht: warum sollen wir viel schreiben, wenn Du zu faul bist, eine ausführliche Fehlerbeschreibung zu geben? Siehe Forumregel Nr 5 - weißt Du was in den Forumregeln steht?
Da meine Glaskugel in Reparatur ist, schließe ich mich maw_hn an:
Mehr Infos bitte!
- bitte Quellcode der main und der Timer-ISR posten.
- Hast Du schon mal nachgemessen, ob der Timer wirklich mit 25Hz läuft?
- Wieviele Werte werden denn auf der SD-Karte gespeichert?
- Werden vielleicht schon gespeicherte Werte durch nachfolgende wieder überschrieben?
Gruß,
askazo
helipaddi
02.03.2010, 09:31
Hab den Quellcode leider gerade nicht hier. Werde ihn heute Abend aber hochladen. Im Prinzip passiert aber auch nicht viel. In der Hauptschleife werden 4 16bit Integer eingelesen welche als PWM in den MC kommen. Im Interrupt werden diese dann mit Hilfe von itoa auf die Karte geschrieben. Zusätzlich wird auf dem Display noch angezeigt wie viele Zeilen schon geschrieben wurde. Daher weis ich auch, dass der Timer viel zu langsam läuft. Den Timervorlade Wert setze ich am Anfang der ISR Routine.
- Hast Du schon mal nachgemessen, ob der Timer wirklich mit 25Hz läuft?
Werde ich heute Abend mal machen! Kann mir aber nicht vorstellen, dass er falsch läuft, da ich schon den internen RC und einen externen Quarz benutzt habe.
[...]Daher weis ich auch, dass der Timer viel zu langsam läuft. [...]
[...] Kann mir aber nicht vorstellen, dass er falsch läuft, [...]
:-s
Irgendwie widersprichst Du Dir gerade selber....
helipaddi
02.03.2010, 11:15
](*,)
Anders ausgedrückt:
Der Avr hat auf jeden Fall den richtigen Takt. Vorteiler und Vorlade Wert sind mit Hilfe von rnAvr hier aus der Wiki generiert.
Trotzdem werden die Einträge nicht mit der richtigen Frequenz erstellt...
helipaddi
02.03.2010, 19:40
Hier jetzt mal die relevanten Codeauschnitte:
ISR(TIMER1_OVF_vect)
{
TCNT1 = 25536;
rcFunktion1 = (rcChannel1-Stick_min-Stick_diff);
rcFunktion2 = (rcChannel2-Stick_min-Stick_diff);
rcFunktion3 = (rcChannel3-Stick_min-Stick_diff);
rcFunktion4 = (rcChannel4-Stick_min-Stick_diff);
//Kanäle auf SD schreiben
ffwrites(itoa(rcChannel1, buffer1, 10));
ffwrite(':');
ffwrites(itoa(rcChannel2, buffer2, 10));
ffwrite(':');
ffwrites(itoa(rcChannel3, buffer3, 10));
ffwrite(':');
ffwrites(itoa(rcChannel4, buffer4, 10));
ffwrite(0x0D);
ffwrite(0x0A);
while (1)
{
rcChannel1 = pwmIn(&PIND, PD6);
rcChannel2 = pwmIn(&PIND, PD5);
rcChannel3 = pwmIn(&PIND, PD4);
rcChannel4 = pwmIn(&PIND, PD3);
}
TCCR1B = (1<<CS11);
Der Avr läuft mit 16mHz.
Wenn ich richtig gerechnet habe, wird Deine ISR alle 20ms aufgerufen, was einer Frequenz von 50Hz entspricht. ( (65536 - 25536) * 62,5ns * 8 = 20ms)
Du machst übrigens ziemlich viele Funktionsaufrufe in der ISR. Ich weiß nicht, wieviel Takte so ein itoa oder ffwrites benötigt, aber da könnte schon einiges zusammenkommen. Du solltest auf jeden Fall mal prüfen, ob Du die ISR überhaupt schnell genug abarbeiten kannst.
helipaddi
03.03.2010, 11:49
Ups, hatte den Timer bewusst auf 50hz eingestellt, um zu testen wie hoch die Abweichung ist.
Habe mal ungefähr gezählt wie viele Takte ich benötige. Sollte eigentlich in der Zeit kein Problem sein... Ausserdem ist die Ungenauigkeit auch bei z.B. 10hz vorhanden.
Habe den Timer jetzt wieder auf 50hz eingestellt. Eigentlich sollte dann nach einer Minute der Counter bei 3000 sein, er kommt aber nur bis 1350. Bei 10hz oder 25hz das gleiche. :-k
oberallgeier
03.03.2010, 12:57
... hatte den Timer bewusst auf 50hz eingestellt, um zu testen wie hoch die Abweichung ist ...Welche Abweichung? Klingt irgendwie unlogisch und verdächtig - ich bring das Auto zum Schleudern und wunder mich nachher, dass es nicht geradeaus fährt.
... Vermutlich speicherst Du in der ISR *baaa* ...Meine ursprüngliche Vermutung ist also richtig.
Vorschlag: Zu Beginn der ISR - VOR der Abspeichergeschichte - einen Port einschalten (dazu gibts bei mir IMMER eine TestLED) und vor dem RETI diesen Port ausschalten. Oskar dranhalten und anschauen, wie lange die ISR dauert. Damit habe ich sehr viele ISR auf die Laufzeit überprüft - auch wenn der Controller vor- und nachher noch etliche organisatorische Dinge einfügt (Register retten und so).
helipaddi
03.03.2010, 14:29
Den Timer mal mit'm Oszi messen ist eine super Idee. Das werde ich gleich mal machen!
Besserwessi
03.03.2010, 18:48
Das Schreiben auf die SD-karte und das LCD Display könnte schon etwas zu lange dauern, zumindest bei 50 Hz. Wenn man die Rate reduziert sollte es dann aber irgendwann funktionieren. Idealerweise schreibe man nicht jeden Datensatz aufs LCD, denn schneller als etwa 3-5 Hz kann man nicht ablesen. Auch das schreiben aufs LCD sollte man eher ins Hauptprogramm verlegen, oder aufgeteilt in kleine Häppchen in eine andere ISR.
Das Schreiben auf die SD Karte sollte wenn möglich außerhalb der ISR ablaufen, denn das kann im ungünstigen Fall lange dauern. Es ist auch nicht klar wie die Routinen geschreiben sind. Je nach Aufbau, kann es Probleme in der ISR oder außerhalb geben.
Kleiner Tipp wie man solche Probleme auch ohne Oszi erkennen kann:
bool bNewData = false;
uint8_t ErrCnt = 0;
void ISR()
{
if (!bNewData)
bNewData = true;
else
ErrCnt++;
}
void main()
{
while(1)
{
if (bNewData)
{
// Hier Daten abholen und auf SD-Karte speichern
...
// Dann Flag zurücksetzen
bNewData = false;
}
}
}Bei diesem Code wird ErrCnt um 1 inkrementiert falls ein Interrupt ausgelöst wird, bevor die Datenverarbeitung abgeschlossen ist.
Auf dem Display könntest du dann z.B. ausgeben lassen wie viele Interrupts pro Sekunde du "verpasst" weil das Speichern zu lange dauert. Ist der Wert größer als 0, könnte ein Ringpuffer (FIFO) eventuell Abhilfe schaffen.
helipaddi
04.03.2010, 19:17
Erstmal vielen Dank für eure Tipps! Werde es mal austesten und dann berichten.
Meint ihr es ist sinnvoll, statt 9 mal die Funktion zum schreiben auf die SD aufzurufen erst alles zu einen String zusammen zu fassen und dann komplett auf die Karte zu schreiben? Komme leider aus der C# Welt und da macht man sich nicht so viele Gedanken über die Performance...
EDIT: Benutze übrigends diese SD Lib:
http://www.mikrocontroller.net/articles/AVR_FAT32
Meint ihr es ist sinnvoll, statt 9 mal die Funktion zum schreiben auf die SD aufzurufen erst alles zu einen String zusammen zu fassen und dann komplett auf die Karte zu schreiben? Komme leider aus der C# Welt und da macht man sich nicht so viele Gedanken über die Performance...Das kann durchaus sinnvoll sein, viele Speichermedien sind beim Schreiben von großen Datenblöcken am Stück schneller. Wie das bei SD-Karten ist kann ich dir allerdings nicht sagen, da ich selbst bisher noch keine verwendet habe.
Der von mir angesprochene Ringpuffer kann dir bei sowas übrigens auch helfen:
void ISR()
{
// Daten abholen und in Ringpuffer speichern
}
void main()
{
while(1)
{
if (Ringpuffer Füllstand > 0)
{
if ((Ringpuffer Füllstand > x) || (mehr als y Sekunden seit letztem Speichern))
{
Gesamten Inhalt des Ringpuffers auf SD-Karte schreiben
}
}
}
}Die ISR muss nur die Werte auslesen und im Puffer speichern, was natürlich möglichst schnell erfolgen sollte (wie werden die Werte eingelesen?). Und die Hauptschleife entleert den Puffer in regelmässigen Abständen, oder sobald er voll genug ist, auf die SD-Karte.
Alternativ zu dieser Implementierung kann man es auch wieder so machen wie in meinem ersten Beispiel, also in der ISR nur ein Flag setzen. In diesem Fall hätte man in der Hauptschleife einen Teil der mit der ISR synchronisiert ist und in dem die Daten abgeholt werden, und einen Teil der asynchron nebenher läuft und die Daten bei Gelegenheit auf die SD-Karte schreibt.
edit:
das schaut dann etwa so aus
void ISR()
{
if (!bNewData)
bNewData = true;
else
ErrCnt++;
}
void main()
{
while(1)
{
if (bNewData) // ISR synchron
{
// Daten abholen und in Ringpuffer speichern
bNewData = false;
}
if (Ringpuffer Füllstand > 0) // asynchron
{
if ((Ringpuffer Füllstand > x) || (mehr als y Sekunden seit letztem Speichern))
{
// Gesamten Inhalt des Ringpuffers auf SD-Karte schreiben
}
}
}
}
helipaddi
04.03.2010, 21:01
wie werden die Werte eingelesen?
Die Werte kommen als PWM mit einer Frequenz von ca. 50hz in den MC. Ist übrigens ein RC Servo Signal. Da die Funktion zum messen daher eventuell 22ms braucht (20ms bis das HIGH kommt und 2ms bis wieder LOW kommt) habe ich diese ausgelagert.
Die Werte werden also in main() gemessen?
Na das ist doch optimal, denn dann läuft der Teil ja ohnehin schon asynchron nebenher. Wenn man das dann mit dem Speichern genauso macht, sollte man die Daten auch irgendwie auf die SD-Karte geschaufelt kriegen, ohne Interrupts zu verlieren.
helipaddi
05.03.2010, 08:08
Die Werte werden also in main() gemessen?
Na das ist doch optimal, denn dann läuft der Teil ja ohnehin schon asynchron nebenher. Wenn man das dann mit dem Speichern genauso macht, sollte man die Daten auch irgendwie auf die SD-Karte geschaufelt kriegen, ohne Interrupts zu verlieren.
Genau, sollte funktionieren :-) Bin gerade mal deine Vorschlaege am einbauen!
Die Herausforderung beim Speichern ist eigentlich, dass die einzelnen Datensätze genau mit 25hz auf die Karte müssen. Diese werden nämlich später mit Hilfe von FFMPEG zu einer Videodatei, welche mit 25hz abgespielt wird, zusammen gesetzt. Und da sollte alles synchron sein.
Aber mit einem Timer der genau läuft sollte dies ja kein Problem sein ;-)
Besserwessi
05.03.2010, 08:46
Es sollte nicht so wichtig sein, wann die Daten geschreiben werden, wichtig ist vielmehr, wann die Daten gemesser werden, und das genau die Richtige Zahl an Daten geschreiben wird, also nichts ausgelassen wird.
Es wäre besser das schreiben auf die Karte ins Hauptprogramm zu verlegen, und die Messung in den Interrupt. Die Messung sollte dann aber nicht durchgängig Warten, sondern nur bei Flanken je einen kurzen Interrupt auslösen.
helipaddi
05.03.2010, 08:53
wichtig ist vielmehr, wann die Daten gemesser werden, und das genau die Richtige Zahl an Daten geschreiben wird, also nichts ausgelassen wird.
Wenn der Messzeitpunkt mal ein bisschen ungenau ist, ist das kein Problem! Ausgelassen werden sollten natuerlich keine Daten.
Besserwessi
05.03.2010, 09:29
Das Schreiben auf die SD karte in der ISR ist ein echtes Problem. Gelegentlich muß intern relativ viel passieren. Da kann es schon mal zusammenkommn, dass ein DatenSektor geschrieben werden muß (in der Karte), dazu noch einen Sektor der FAT schreiben und einen anderen Lesen. Das kann also im ungünstigen Fall wirklich relativ lange dauern, auch wenn es meistens relativ flott geht.
Deshalb sollte man das schreiben wirklich besser so machen, das es auch unterbrochen werden kann, also ins Hauptprogramm.
helipaddi
05.03.2010, 09:39
Daher wollte ich es ja so machen wie von Felix G vorgeschlagen. Also im ISR nur ein Flag setzten und dann in der Hauptschleife abarbeiten lassen.
Das bedeutet die Messung erfolgt in main() nebenher, ebenso das Speichern auf der SD-Karte, und bei jedem Interrupt werden die aktuellen Daten in einen Puffer geschrieben (das geht sehr schnell, kann also auch direkt in der ISR erfolgen)
Ich wage jetzt mal eine Prophezeiung wie das Ergebnis aussehen könnte:
(falls der Puffer in der ISR gefüllt wird)
- Du wirst keine Interrupts verpassen
- Du wirst am Ende genau so viele Daten auf der SD-Karte haben wie du möchtest
- Die Daten werden "ruckeln"
Das Problem ist nämlich, daß während dem Speichern keine Messungen durchgeführt werden können, da main() "blockiert" ist (durch die Speicherfunktion). Lösen kann man dieses Problem auf mehrere Arten:
- Messen und im Puffer ablegen erfolgt direkt in der ISR, das Speichern auf der SD-Karte asynchron in main(). Problem: lange Interrupts, und selbst wenn keiner verpasst wird, bleibt in main() kaum noch Rechenzeit übrig um die Daten zu speichern
- Interruptbasierte Messung (möglich, falls es nur eine PWM ist, oder die steigenden Flanken aller PWMs synchron sind). In diesem Fall braucht man die PWM an einem Interrupt-fähigen Pin. Bei einer steigenden Flanke wird ein Timer gestartet, bei einer fallenden Flanke wird der Timer wieder ausgelesen. Das ganze erfolgt komplett unabhängig von main(). Dann könnte man in der 25Hz ISR den jeweils aktuellen Messwert im Puffer ablegen, und den ganzen Kram asynchron aus main() heraus abspeichern.
helipaddi
05.03.2010, 11:45
Das bedeutet die Messung erfolgt in main() nebenher, ebenso das Speichern auf der SD-Karte, und bei jedem Interrupt werden die aktuellen Daten in einen Puffer geschrieben (das geht sehr schnell, kann also auch direkt in der ISR erfolgen)
Werde es so mal umsetzen, kommt mir als beste Lösung vor! Danke für die Ratschläge.
Ich denke das Ruckeln ist zu vertreten, da sich die Messwerte auch nicht so schnell ändern.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.