Hallo!
Ich habe mir eine Schaltung gebaut, welche einen FT232RL verwendet, um
Daten vom Mikrocontroller an den PC zu senden. Dabei wird eine
Geschwindigkeit von 1.000.000Bit/s (etwas überdimensioniert, aber für
spätere Erweiterungen ggf. nötig) verwendet und c.a. 15.000 Byte pro
Sekunden versendet.
Auf der PC-Seite soll nun ein Programm diese Daten eine Sekunde lang
aufzeichnen und speichern. Dafür habe ich mir folgende (einfache)
Programmierung überlegt, um die Daten zu speichern:
//...Werte die Empfangsdaten ab dieser Stelle aus, um die Übersichtlichkeit zu bewahren habe ich mir das mal geschenkt...
16
}
Der Timer ist so eingestellt, dass er eine Sekunde abzählt. Die
Einstellungen des SerialPorts sind natürlich passend zum FT232RL. Als
Encoding verwende ich:
1
serialPort1.Encoding=Encoding.GetEncoding(28591);
um 8 bit Encoding zu bekommen.
Obwohl die serialPort1_DataReceived-Funktion recht einfach gehalten ist,
fehlen Daten in dem Stringbuilder. Dabei ist der Punkt, wann die Daten
fehlen, von der Größe des Eingangspuffers abhängig. Ich habe den
Eindruck, dass die Funktion aufgerufen wird, während sie selbst noch in
der Bearbeitung ist (wie bei Interrupts auf uCs). Dabei würde ich von
meinem Rechner (mit einer vielfach größeren Taktrate als ein uC)
erwarten, dass er die Funktion rechtzeitig abarbeitet.
Hat vielleicht einer von euch eine Idee, warum es nicht funktioniert und
wie das Problem gelöst werden kann? Vielen Dank!
Was ich hier bei einem Projekt gesehen hatte (Controller C8051F585 +
FT232R, Baudrate 1.5 M) war, dass einige Parameter zusätzlich gesetzt
werden mussten damit es stabil läuft (allerdings über die FTD2XX.dll):
1
// read timeout 1000 ms, write timeout 500 ms
2
FT_SetTimeouts(handle,1000,500);
3
// flush receive buffer timeout 2 ms
4
FT_SetLatencyTimer(handle,2);
5
// transfer size for in/out transfers 256 bytes
6
FT_SetUSBParameters(handle,256,256);
Was man u.U. noch testen kann ist: Statt wie üblich ein Stopbit, zwei
Stopbits nehmen...
if (timer2.Enabled)
{
Empfangsdaten.Append(serialPort1.ReadExisting());
}
das darfst du nicht machen. du musst immer die Daten abrufen. Wenn du
sie nicht brauchst musst du sie nach den abrufen wegschmeissen.
> Als Encoding verwende ich:> serialPort1.Encoding = Encoding.GetEncoding(28591);> um 8 bit Encoding zu bekommen.
Geht es überhaupt um Strings oder geht es um Daten? Wenn es daten sind,
dann verwende auch bitte keine String funktionen. (Read oder ReadByte).
@Arc Net: Die dll wäre durchaus auch eine interessante Lösung. Ich würde
allerdings erstmal versuchen, ohne dll auszukommen und über bekannte
Funktionen zu arbeiten. Aber falls ich doch die dll verwenden werde, so
sind deine Hinweise schonmal sehr sinnvoll!
@Peter II: Ich möchte alle Daten verwenden. Ich war davon ausgegangen,
dass sie durch das Abrufen auch automatisch gelöscht werden. Ist dies
nicht so?
Es geht tatsächlich um Daten. Ich hatte mir von ReadExisiting erhofft,
dass dadurch tatsächlich alles gelesen wird. Bei ReadByte hatte ich die
Befürchtung, dass es zu komplex (Rechenzeit) wird.
Martin S. schrieb:> @Peter II: Ich möchte alle Daten verwenden. Ich war davon ausgegangen,> dass sie durch das Abrufen auch automatisch gelöscht werden. Ist dies> nicht so?
erst durch serialPort1.ReadExisting(); wird gelöscht. das rufst du aber
nicht immer auf.
> Es geht tatsächlich um Daten. Ich hatte mir von ReadExisiting erhofft,> dass dadurch tatsächlich alles gelesen wird. Bei ReadByte hatte ich die> Befürchtung, dass es zu komplex (Rechenzeit) wird.
andersrum. Die Stringfunktionen machen eine Zeichsatzkonvertierung und
sind damit langsamer.
Das SerialPortExisting wird im Grunde genommen während 1s regelmäßig
aufgerufen, was danach am Port passiert ist mir erstmal egal. Ich habe
nun einen Test gemacht mit ReadByte, und ich habe den Eindruck, noch
weniger Daten zu bekommen. Auf jeden Fall findet der 1. Datenverlusst an
der Stelle statt, wo er auch bei dem String stattfindet. Es kommen
danach nochmal die gleiche Menge Daten wie vorher, und das war es dann.
Martin S. schrieb:> Ich habe nun einen Test gemacht mit ReadByte, und ich habe den Eindruck,> noch weniger Daten zu bekommen.
zeigt doch mal bitte den code.
Martin S. schrieb:> Es sieht jetzt so aus:
müsste eigentlich passen, viele vergessen alle Daten abzurufen.
Kommen denn die Daten in einem anderen Programm vollständig an? Nicht
das das Problem woanders liegt. Letzen war hier auch jemand der einen
Defekten USB/Com adapter hatte wo Zeichen weggekommen sind.
Ich habe einen Test mit dem Terminal-Programm "HTerm" gemacht. Meines
Erachtens fehlern hier keine Daten. Wie oben gesagt, ist der Punkt, wann
die Daten in meinem eigenen Programm fehlen, von der Größe des Puffers
abhängig, d.h. der Schnitt kann somit ja auch nicht durch die Elektronik
verursacht sein (weil er dann ja Pufferunabhängig wäre).
Martin S. schrieb:> Ich habe einen Test mit dem Terminal-Programm "HTerm" gemacht. Meines> Erachtens fehlern hier keine Daten. Wie oben gesagt, ist der Punkt, wann> die Daten in meinem eigenen Programm fehlen, von der Größe des Puffers> abhängig, d.h. der Schnitt kann somit ja auch nicht durch die Elektronik> verursacht sein (weil er dann ja Pufferunabhängig wäre).
Schon ausprobiert was passiert, wenn die o.g. Einstellungen über den
Gerätemanager gemacht werden (Anschlusseinstellungen -> Erweitert)?
Also eine Änderung der sogenannten "BM-Einstellung" (was ist das??)
verschiebt die Fehlstelle etwas, aber löst das Problem nicht. Auch die
Verwendung von Read anstelle von ReadByte bringt keinen Vorteil.
Hallo,
strings sollte man grundsätzlich vermeiden, wenn man nicht ganz genau
weiss, was der Compiler draus macht. Basic z.B. arbeitet so, dass beim
Anhängen eines Zeichens an einen vorhandenen String für einen neuen
String Speicher reserviert wird und der bisherige String plus das
zusätzliche Zeichen dorthin kopiert wird (das ist glaube ich sogar eine
der wenigen Sachen, die Bill Gates miterfunden hat). Klar dass das nicht
so schnell geht.
Ich misstraue daher grundsätzlich Funktion wie append bei strings und
schreibe lieber selber eine Bufferverwaltung mit einem Pointer, die ist
bei jeder Grösse und Füllgrad gleich schnell.
Gruss Reinhard
Hallo,
strings sollte man grundsätzlich vermeiden, wenn man nicht ganz genau
weiss, was der Compiler draus macht. Basic z.B. arbeitet so, dass beim
Anhängen eines Zeichens an einen vorhandenen String für einen neuen
String Speicher reserviert wird und der bisherige String plus das
zusätzliche Zeichen dorthin kopiert wird (das ist glaube ich sogar eine
der wenigen Sachen, die Bill Gates miterfunden hat). Klar dass das nicht
so schnell geht.
Ich misstraue daher grundsätzlich Funktionen wie append bei strings und
schreibe lieber selber eine Bufferverwaltung mit einem Pointer, die ist
bei jeder Grösse und Füllgrad gleich schnell.
Gruss Reinhard
@ Reinhard Kern:
öhm Stringveraltung unter basic mag ja selber geschrieben gut sein ....
nunja c# kennt nicht mal mehr pointer
aber du hast recht, dass eine liste, in welcher die bytes erstmal
abgespeichert werden, sinnvoller ist
dann könnte man per debugger auch nachsehen, ob dort alles angekommen
ist
A.G. schrieb:> öhm Stringveraltung unter basic mag ja selber geschrieben gut sein ....> nunja c# kennt nicht mal mehr pointer
Auf die Gefahr hin, dass du mich für einen ausgestorbenen Dinosaurier
hältst, solche Bufferverwaltungen habe ich meistens in Assembler
geschrieben, als Bestandteil des ohnehin nötigen Gerätetreibers,
allerdings waren das meistens Mikroprozessoren und Embedded Systeme. Ich
habe das zunächst auch ganz allgemein gemeint. Für einen PC geht das
nicht so ohne weiteres, aber es gibt ja Arrays usw. je nach Sprache,
d.h. einen Zugriff auf Buffer[i] gibt es auch ohne Pointertyp.
Allerdings richtet ja auch der Windowstreiber einen Buffer wählbarer
Länge ein, warum nicht den benutzen? Dann kann eigentlich nichts
verlorengehen.
Gruss Reinhard
Aus irgendeinem Grunde geht es jetzt recht gut. Ich hatte gestern noch
Versuche mit der FTDI-DLL vom Hersteller gemacht (und es ging recht gut
damit), allerdings geht es komischerweise jetzt auch in der
Ursprungsversion. Warum auch immer, vielleicht brauchte ja die serielle
Schnittstelle nach den ganzen Parameteränderungen etwas Ruhe über
Nacht^^.
Wie auch immer, es klappt nun auch sehr schön über die Eigenschaftsseite
von Arc Net sehr kleine Datenmengen zu bekommen. Leider kann ich in c#
keine passende Einstellmöglichkeit finden, die das Einstellen im
Eigenschaftsfenster der Seriellen Schnitstelle ersetzt. Es ist
interessanterweise nicht ReadBufferSize, oder die Wahl in der
Eigenschaftsseite hat höhere Priorität.
Unterschiede der aktuellen Variante zu den oberen sind auf jeden Fall,
dass ich den Port erst ganz kurzfristig vor dem Benutzen öffne, und dass
ich unmittelbar davor nochmal die Eigenschaftswerte setze (die
eigentlich schon vorher für die serielle Schnittstelle im
Eigenschaftsfenster gesetzt wurden). Ebenfalls wird der Port so schnell
wie möglich wieder geschlossen.
Vielen Dank nochmal für die vielen Hinweise!
Nochmal ein kleiner Nachtrag: Es kamen doch nochmal dann und wann
Fehler. Diese konnte ich aber loswerden, indem ich zu Beginn der Messung
"ReadExisting" ausgeführte habe (ohne die Daten weiter zu benutzen).
Dies ist sowieso sinnvoll, um sicherzustellen, dass tatsächlich keine
Daten empfangen werden, die vor dem Startzeitpunkt gesendet wurden und
bereits im Buffer sein könnten.