Hallo,
ich habe ein altes DOS Programm nach Java portiert. Das Programm soll
ein ein Taktsignal von einem RDS Empfänger (1,187 kbit/s) über die
RS232 lesen und gleichzeitig einzelne Bits senden. Dazu speise ich das
Taktsignal über den Carrier Detect (Pin1, DCD) des COM Ports ein.
Aber der EventListener überprüft den COM Port scheinbar nur etwa 10 mal
pro Sekunde (auf einem Core2 E8500!) Das ist viel zu langsam.
Ich verwende die Bibliothek RXTX für Java.
Das DOS Programm auf einem 386er, welches in Turbopascal programmiert
ist, schafft das ohne Probleme!
Handelt es sich hier um ein Windows Problem (Handler, Threads...), oder
sollte ich besser C++ verwenden?
Kleiner Auszug aus dem Java Code:
1
serialPort.notifyOnCarrierDetect(true); //wenn das Bit am DCD wechselt -> event
Christian B. schrieb:> Handelt es sich hier um ein Windows Problem (Handler, Threads...), oder> sollte ich besser C++ verwenden?
Echte RS232 oder USB Wandler? Diese sind nämlich an das Datenprotokoll
von USB gebunden was nur (etwa) alle 10ms eine Datenpaket zulässt.
Christian B. schrieb:> Das DOS Programm auf einem 386er, welches in Turbopascal programmiert> ist, schafft das ohne Probleme!
Unter DOS ist man halt auch allein auf der Welt und damals war sowieso
alles besser ;)
Christian B. schrieb:> Handelt es sich hier um ein Windows Problem (Handler, Threads...), oder> sollte ich besser C++ verwenden?
ja und nein, bei Dos hattest du die CPU für dich. Jetzt hast du ein
Betriebssystem dazwischen welches die CPU aufteilt. Dir wirst es wohl
nicht schaffen mehr als 1000mal pro Sekunde etwas von einem IO-Pin
gleichmäßig einzulesen.
Wenn es überhaupt geht, dann nur wenn du einen Treiber für das System
schreibst (dann aber auch nicht mit C++ sondern mit C).
Sinnvoller ist es aber das ganze extern über einen kleinen µC zu
erledigen. Dieser kann das ganze auch mit 8Mhz ohne Probleme, er gibt
dann die Daten über Seriell an den PC (das geht dann auch mit einem USB
Adapter)
Läubi .. schrieb:> Echte RS232 oder USB Wandler? Diese sind nämlich an das Datenprotokoll> von USB gebunden was nur (etwa) alle 10ms eine Datenpaket zulässt.>> Unter DOS ist man halt auch allein auf der Welt und damals war sowieso> alles besser ;)
Es ist ein echter RS232.
Ich bin jetzt schon schockiert, dass man mit modernen Betriebssystemen
so viel schlechter fährt als damals mit DOS...
Gibt es heutzutage ein "modernes" DOS, womit man die CPU für sich allein
hat? Irgend eine schmalspur Linux Distribution o. Ä.
Christian B. schrieb:> Ich bin jetzt schon schockiert, dass man mit modernen Betriebssystemen> so viel schlechter fährt als damals mit DOS.
Du kannst auch mit einen Akkuschrauber kein Nagel reindrehen, auch wenn
er noch so modern ist. Ein PC mit seinen aktuellen Schnittstellen und
Betriebssystem ist für den Zweck ebend nicht das richtige.
Warum willst du es nicht über einen externen µC machen?
Wenn du es unbedingt am PC machen willst, kannst du dir ja ein
Logic-Analyser kaufen und dann damit die Daten auswerten.
Die uC Variante ist halt mit mehr Aufwand verbunden, als etwas Code zu
tippen. Und ich brauche 5 Stück davon. Aber 5 uCs sind natürlich
billiger, als 5 386er kaufen... ich bin gerade vom uC überzeugt worden
;)
qwertzuiopü schrieb:> wie wärs wenn du im event-listener nur einen buffer füllst und bei jedem> 10. oder 100. event eine weiterverarbeitung anstößt?
Das grundlegende Problem ist, dass ich eine Ausgabetaktrate von 1,1875
kbit/s verwirklichen muss, welche kein Standard für RS232 ist. Die
Bitdauer bis zum jeweils nächsten Bit ist 0,842 Millisekunden, aber ein
Thread.sleep() akzeptiert nur ganze Millisekunden. Oder gibt es da
andere Möglichkeiten?
Denn die Ausgabe über Setzen von Bits funktioniert schnell genug (nur
der EventListener ist zu langsam).
Christian B. schrieb:> Denn die Ausgabe über Setzen von Bits funktioniert schnell genug (nur> der EventListener ist zu langsam).
Hast du das gemessen oder glaubst du das nur?
Du kannst einfach unter Windows dein gewünschtes Zeitverhalten nicht
erreichen, eventuell mit einem (Linux)RTOS, der Empfang der Daten ist
einfach eine DLL welche in C oder C++ geschrieben ist, trotzdem bringt
dir das nix, da du nicht die ungeteilte Aufmerksamkeit des
Betriebssystems erhälts. Gerade das auslesen von Statusbits ist
sicherlich nicht dafür ausgelegt dermaßen häufige Statuswechsel zu
detektieren, eher im Gegenteil.
Christian B. schrieb:> Denn die Ausgabe über Setzen von Bits funktioniert schnell genug
definiere Schnell...
Läubi .. schrieb:> Hast du das gemessen oder glaubst du das nur?
Wenn man einen Zähler einprogrammiert, sieht man, dass etwa 20 kbit/s am
Com Port möglich sind.
Ich habs endlich geschafft. Es funktioniert, wenn man einen eigenen
Thread schreibt, der mit der Methode serialPort.isCD() in einer
Endosschleife den Zustand des DCD überwacht. Die Abtastrate beträgt etwa
20.000mal pro Sekunde, was für mein Problem mehr als ausreichend ist.
Kurzer Auszug des Thread Codes:
1
classsendextendsThread{
2
publicvoidrun(){
3
while(!isInterrupted()){
4
merken=serialPort.isCD();
5
// noch mehr Code
6
}
7
}
Der "Nachteil" ist natürlich, dass man die CPU jetzt wie gewünscht für
sich allein hat, sprich 99% Auslastung ;)
Eine Dauerlösung ist das somit nicht.
Markus schrieb:> Würdest du mal dein Programm komplett hochladen? würde mich mal> interessieren.
Gern. Hier ist die DataOut Klasse, welche den RDS Code generiert und
sendet
Christian B. schrieb:> Wenn man einen Zähler einprogrammiert
Naja vermutlich wird einfach der Comport nicht so oft abgefragt um dies
Christian B. schrieb:> sich allein hat, sprich 99% Auslastung
zu verhindern, das hat aber nix mit dem Eventlistener zu tun!
Mal ein paar Hinweise zu deinem Code:
- Klassennamen schreibt man i. A. groß und gibt ihnen sinnvolle
Namen(send ist doch etwa allgemein ;)
- Um einen neuen Thread zu starten, reicht es das Interface Runnable zu
implementieren und dem Thread im Konstruktor zu übergeben, Thread zu
erweitern nur um die run Methode zu überschreiben ist "bad practice"
- Arrays könen in Java auch folgendermaßen initialisiert werden:
1
int[]matrix={0x00001DC0,0x0000B9C0,...};
- Auch sollte man nicht alle Variablen auf Vorrat "am Anfang"
deklarieren, damit handelt man sich nur Pobleme ein
1
for(inty=0;y<16;y++){
2
inth3=0x00000000;//Hilfsregister initialisieren
3
inth2=0x00010000;
4
for(intx=0;x<16;x++){
5
inth1=data[y]&h2;//Bit ausmaskieren
6
if(h1!=0)h3=matrix[x]^h3;// ^ ist XOR
7
h2=h2<<1;//nächst groesseres Bit (Rechtsshift ist in Java unbrauchbar, wegen Vorzeichenmitnahme)
8
}
9
h3=h3^offsetwort[y%4];//Offset hinzufügen
10
code[y]=data[y]^h3;//Daten & Code & Offset
11
}
- Gleiches gilt für Membervariablen, wieso ist "reg" ein Member von
DataOut? Nicht nur das es den code unübersichtlich macht (man muss jetzt
erstmal schauen ob irgendwer anders den Member nicht doch noch
verwendet) dadurch das du diesen package private deklariert hast, darf
der Compiler den nicht mal wegoptimieren und der Zugriff auf diesen ist
langsamer.
- Eingaben sollte man am besten auch in Java prüfen ;)
Habe das mal etwas umgestellt.
Läubi .. schrieb:> das hat aber nix mit dem Eventlistener zu tun!
Stimmt, das Problem liegt dann wohl bei der Eventquelle. Scheinbar kann
der Com Port keinen Interrupt auslösen oder das wurde von der RXTX
Bibliothek nicht implementiert.
Vielen Dank für die Hinweise. Das ist mein erstes Java Programm.
Problem ist erstmal gelöst.