Forum: PC-Programmierung C#: RS485 Buskollisionen vermeiden


von Bronco (Gast)


Lesenswert?

Hallo zusammen,

ich habe einen µC, der über einen halfduplex RS485-Bus mit dem PC 
kommuniziert. Das Ende eines Telegrams wird über eine Pause von mind. 
5ms angezeigt.
Der µC sendet zyklisch alle 100ms eine kurze Nachrichte. Nun muß ich den 
PC irgendwie darauf synchronisieren, denn der PC darf seine Nachrichten 
an den µC nur in den Pausen zwischen zwei µC-Telegrammen senden, sonst 
kommt es zu Buskollisionen.

Ich wüßte nun ganz genau, wie ich das auf einem µC programmieren würde, 
da ich dort direkten Zugriff auf UART-Interrupts, Timer etc. habe.
Aber wie mache ich das unter C#? Ich bräuchte ein Event, das zügig 
kommt, wenn der PC ein Telegram vom µC empfangen hat und dann mind. 5ms 
Ruhe war.
Im Augenblick hab ich einen Thread laufen, der quasi den SerialPort 
"pollt" und über eine StopWatch das Timing mißt. Das Ganze läuft aber 
nicht sehr präzise, z.B. kann ich keine Sync-Pause von 5ms realisieren, 
sondern muß dem PC mind. 20ms geben, damit er nicht durcheinander kommt.

Hat jemand einen Tip?

von Test (Gast)


Lesenswert?

Was du "brauchst" geht schon in richtung echtzeit...da kannst du erstmal 
mit eigenen windows treibern etc anfangen. Generell ist dein ansatz hier 
ein wenig falsch...

Für sowas nimmt man entweder ein vernünftiges protokoll/bus wie zB CAN 
oder baut sich einen gateway zwischen bus und pc, der sich um den 
echtzeit teil kümmert. Alternativ kannst du zB auch die funktionsweise 
von pc und uc tauschen

von Robert L. (lrlr)


Lesenswert?

>ann ich keine Sync-Pause von 5ms realisieren,

warum nicht?

also 5ms sind ja EWIG..

schon mal nach  high-resolution timer gesucht

http://msdn.microsoft.com/en-us/library/aa964692%28v=vs.85%29.aspx

usw.

(ICH würde, wenn du schon gut µC Programmieren kannst,  aber auch ein 
gateway basteln, rs485<>UDP)

von Bernd K. (prof7bit)


Lesenswert?

Ich hab mal was ähnliches versucht, mit einem USB/RS485 Adapter auf 
FTDI-Basis, und zwar unter direkter Zuhilfenahme der Windows-API und 
Overlapped-IO und WaitForSingleObject() mit eine Timeout von nur 1ms, 
ich hab der ganzem Low-Level Mimik sogar ihren eigenen Thread spendiert 
der nur auf neue Daten von der seriellen Schnittstelle wartet, nichts 
anderes macht und sofort reagiert. Dennoch ist es mir nicht 
gelungen das zeitliche Eintreffen der empfangenen Bytes in der 
Windows-API (also das Auslösen von WaitForSingleObject) genauer als 
ungefähr 25ms (eher schlechter) mit dem tatsächlichen physikalischen 
Eintreffen auf der Leitung zu korrelieren.

Ich hab mir das dann irgendwann mit der Natur des USB-Treibers (dessen 
Pufferung von Daten, etc) erklärt, als prinzipielle Unmöglichkeit 
angesehen und meinen Timeout auf 50ms erhöht.

Vielleicht hast Du mehr Erfolg wenn Du eine "echte" serielle 
Schnittstellenkarte (als PCI-Karte) reinsteckst. Womöglich hast Du dann 
ein wesentlich straffer an die physikalische Schicht gebundenes Timing.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Bernd K. schrieb:
> Ich hab mal was ähnliches versucht

Hast Du dabei auch die Granularität des Windows-Schedulers umgestellt? 
Ohne das zu tun, bekommst Du nur Auflösungen im 10msec-Bereich.

Die Multimedia-API-Funktion timeBeginPeriod 
(http://msdn.microsoft.com/de-de/library/windows/desktop/dd757624%28v=vs.85%29.aspx) 
ermöglicht es, diese Granularität auf 1msec zu setzen.

von Bernd K. (prof7bit)


Lesenswert?

Rufus Τ. Firefly schrieb:

> Hast Du dabei auch die Granularität des Windows-Schedulers umgestellt?
> Ohne das zu tun, bekommst Du nur Auflösungen im 10msec-Bereich.
>
> Die Multimedia-API-Funktion timeBeginPeriod
> 
(http://msdn.microsoft.com/de-de/library/windows/desktop/dd757624%28v=vs.85%29.aspx)
> ermöglicht es, diese Granularität auf 1msec zu setzen.

Das muss ich noch mal ausprobieren, danke für den Tipp! Die Software 
wurde größtenteils unter Linux entwickelt (wo sie besser funktionierte) 
und erst nachträglich nach Windows portiert, d.H. mit der Windows-API 
hab ich weniger Erfahrung, also kannte ich diesen Trick noch nicht. Es 
ist mir noch nichtmal überhaupt in den Sinn gekommen überhaupt nur in 
Erwägung zu ziehen ob es dort Mechanismen geben könnte mit denen ein 
unberechtigtes Userspace-Programm eventuell einfach so an irgendwelchen 
Kernel-Timings rumschrauben darf. Muß ich mal ausprobieren ;-)

von Purzel H. (hacky)


Lesenswert?

Das Ganze ist vom Protokol her schon suboptimal. Sowas sollte man 
Master-Slave implementieren. Also der Master, dh der PC, verlang was vom 
slave, dh dem controller, mit einem timeout. Der Slave muss nun 
antworten. Ohne Aufforderung sendet der slave gar nichts.
Und sonst sollte man's bidirektional zB mit RS422 implementieren. Dort 
gibt's nichts umzuschalten.

von Bernd K. (prof7bit)


Lesenswert?

Siebzehn Für Fuenfzehn schrieb:
> Das Ganze ist vom Protokol her schon suboptimal. Sowas sollte man
> Master-Slave implementieren.

Naja, bei genau 2 Geräten ist das doch reine Definitionssache: In dem 
Fall wie oben geschildert definierst du halt kurzerhand den µC als 
Master und den PC als Slave der sich dem Timing des Masters 
unterzuordnen hat und schon passts wieder: Der Master (der µC) erwartet 
eine "Antwort" vom Slave (dem PC) entweder unmittelbar nach seinem 
Telegramm oder keine Antwort (keine Antwort ist auch eine Antwort).

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Bernd K. schrieb:
> In dem Fall wie oben geschildert definierst du halt kurzerhand den µC
> als Master und den PC als Slave der sich dem Timing des Masters
> unterzuordnen hat und schon passts wiede

Passt halt nicht wirklich, wenn man sich dessen bewusst wird, wie 
schwierig es ist, mit einem PC ein genaues Timing einzuhalten. Hier sind 
bereits auf Millisekunden spezifizierte Timeoutwerte extrem 
problematisch.

Beim Systemdesign (also der Entscheidung, wer hier Master und wer Slave 
ist) muss man das berücksichtigen; der, der eher Schwierigkeiten hat, 
ein vorgegebenes Timing einzuhalten, sollte es definieren.

Ist beim Zu-Fuß-Gehen in einer Gruppe auch so: Der langsamste gibt das 
Tempo vor.

Zwar ist ein PC nicht per se langsam, aber beim Reagieren auf externe 
Ereignisse ist er das, und zwar so deftig, daß auch ein popliger 
8-Bit-Controller, der mit nur ein paar MHz getaktet wird, hier 
problemlos das Oberwasser gewinnen kann.

von Georg (Gast)


Lesenswert?

Bronco schrieb:
> Der µC sendet zyklisch alle 100ms eine kurze Nachrichte. Nun muß ich den
> PC irgendwie darauf synchronisieren, denn der PC darf seine Nachrichten
> an den µC nur in den Pausen zwischen zwei µC-Telegrammen senden

Könntest du das noch etwas klarifizieren? Ist das was der PC sendet eine 
Antwort auf die Nachricht, oder ist das Timing nur nötig, um Kollisionen 
zu vermeiden?

Falls letzteres, würde ich bei deinem Kenntnisstand die Sache sanieren 
mit einem Prozessorchen, das die Daten vom PC zwischenspeichert und 
immer 10 ms nach einer µC-Meldung an diesen weitergibt, das kriegst du 
viel schneller hin als echtzeitfähige Windows-Software.

Verkorkst ist die Sache schon vorher, man sollte nicht nur den PC zum 
Master machen, weil ein µC viel geeigneter als Slave ist, es ist auch 
ungünstig, Protokolle durch Pausen zu definieren. Vielmehr sollte das 
Messageende durch ein spezielles Zeichen definiert sein wie CR oder EOT. 
Daraus lässt sich ein sofortiges Windows-Event ableiten, das 
wahrscheinlich schnell genug ist, um in weniger als 100 ms zu reagieren, 
allerdings nicht immer, aber meistens.

Georg

von Bernd K. (prof7bit)


Lesenswert?

Georg schrieb:
> es ist auch
> ungünstig, Protokolle durch Pausen zu definieren.

Bei Modbus ist das beispielsweise so definiert, dreieinhalb Bytelängen 
trennen die Telegramme voneinander. Wenn man einen guten und ziemlich 
direkten Draht zur UART-Hardware hat ist das eigentlich kein Problem. 
Das Problem ist hier dass das wohl unter Windows (oder generell durch 
dicke Schichten von Treibern und übereinandergelegten 
RS485-over-irgendwas-over-USB Stacks hindurch) alles andere als trivial 
ist.

von Oliver R. (superberti)


Lesenswert?

Hi,

> Bernd K. schrieb:
>> Ich hab mal was ähnliches versucht
>
> Hast Du dabei auch die Granularität des Windows-Schedulers umgestellt?
> Ohne das zu tun, bekommst Du nur Auflösungen im 10msec-Bereich.
>
> Die Multimedia-API-Funktion timeBeginPeriod
> 
(http://msdn.microsoft.com/de-de/library/windows/desktop/dd757624%28v=vs.85%29.aspx)
> ermöglicht es, diese Granularität auf 1msec zu setzen.

das hat unter reinem C++ auch immer ganz gut funktioniert.
Aber bei .NET hatte ich in meinen Versuchen kein Glück mehr, mit diesen 
Funktionen den Scheduler zu verändern. Es hat einfach gar nichts bewirkt 
:-(

Ganz ehrlich: Mit dieser Art des Protokolls und C# sehe ich keine 
Möglichkeit, dies zuverlässig in den Griff zu bekommen. Falls aber die 
Gegenstelle in Stein gemeißelt ist, dann würde ich mir eine kleine 
Schaltung mit MC und USB/Seriell-Wandler bauen, die als weiteres 
Interface für das "murksige" Protokoll dient.
Auf der PC-Seite kann man dann mit dem "neuen" MC ein zuverlässiges und 
Timing unabhängiges Protokoll definieren. Z.B. kann dieser MC Befehle an 
die Gegenstelle erst einmal zwischenpuffern und dann im richtigen Moment 
weiterleiten.

Gruß
Oliver

von Robert L. (lrlr)


Lesenswert?

schon mal die Einstellungen des USB<>serial Adapters kontrolliert (ist 
es überhaupt USB???)


ähnlich hier, ganz unter: (buffer noch auf ein Minimum.. usw.)

http://www.digi.com/support/kbase/kbaseresultdetl?id=3418

von Bernd K. (prof7bit)


Lesenswert?

Eine pragmatischere Möglichkeit wäre das Auftreten von Kollisionen 
einfach als gegeben hinzunehmen und einzuplanen (wie groß ist 
rechnerisch die Wahrscheinlichkeit einer Kollision?) und stattdessen 
einfach das Telegramm (nach kurzen zufällig langen Pausen) wiederholen, 
so oft bis ein korrektes ACK empfangen wurde. Das geht aber nur 
vernünftig wenn die Idle-Zeiten weitaus länger sind als die 
Telegrammlängen, also größtenteils Schweigen herrscht auf dem Bus.

von Bronco (Gast)


Lesenswert?

Hallo zusammen,

erstmal danke für die vielen Antworten und sorry, daß ich mich erst 
jetzt zurückmelde (war im Urlaub).

Kurz zum Verständnis meiner Anwendung:
Auf dem RS485-Bus kommunizieren normalerweise zwei µCs miteinander. Die 
haben überhaupt kein Problem mit dem Protokol.
Nun soll man zu Service-Zwecken das PC-Tool anstecken können.

Ich hab nun zwei mögliche Lösungen probiert:
1. Langsames Timing (20ms) auf PC-Seite -> geht, aber eben langsam, wenn 
man größere Datenmengen übertragen muß
2. Bus-Kollisionen einplanen -> geht auch, wenn man die Daten mehrfach 
sendet, kam mir aber etwas unschön vor

Ich denke, der Hinweis, den PC das nächste mal zum Master zu machen, ist 
am hilfreichsten. Kann ich im aktuellen System nicht mehr realisieren, 
aber bei zukünftigen Projekten berücksichtigen.

Danke!

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
Noch kein Account? Hier anmelden.