Laden...

RS232 lesen

Erstellt von schnurzli vor 18 Jahren Letzter Beitrag vor 18 Jahren 8.757 Views
S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren
RS232 lesen

hallo,

habe ein problem mit meiner seriellen schnittstelle.

diese hat folgende eckdaten:
Kartenleser
Port: COM1
Baud: 9600
Parity: Even
Stopbit: 1

Habe ein C# Projekt(.Net2, VC# Express 2005 ) erstellt, System.IO.Ports eingefügt.

dann habe ich aus den Komponeneten ein Serialport1 in mein Form gezogen.
Dort habe ich die obigen Einstellungen getätigt.

Nun stehe ich ziemlich an, es gibt zwar tausende möglichekeiten und Varianten im Inet, ich verstehe aber nicht ganz, wann ich welche Möglichkeit in Erwägung ziehen kann...

Ich möchte das Programm ausführen und dann per Klick auf einen Button aufgefordert werden, um eine Karte darüberzuziehen. Das soll mit einem Timeout von 10 Sekunden versehen sein. Danach ausgabe der eingelesen Daten in einem Label...

Mein Ansatz:

ich habe in der public form

serialPort1.Open();

eingegeben und auf dem Button, mit dem ich das ereignis auslöse:

label1.Text = serialPort1.ReadLine();

. Weiss da jemand Rat?
Ich bin schon relativ verzweifelt...

Vielen Dank schon im voraus,
LG
Richi

S
8.746 Beiträge seit 2005
vor 18 Jahren

Ich denke, du musst schon etwas mehr Energie reinstecken, damit sich jemand motiviert fühlt zu helfen.... es riecht einfach zu sehr danach die Arbeit auf andere abzuwälzen (auch wenn das vielleicht gar nicht deine Intention ist).

Vielleicht machst du einfach mal ein paar Spiel-Projekte oder analysierst fremde Code-Beispiele bevor du dein Problem angehst.

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

ich möchte auf jeden fall keine fertige lösung. mein problem ist nur, dass ich mich mit der vielzahl an lösungen überfordert sehe. teilweise funktionieren sie auch wiederum nicht unter vc# express....

gibt es denn eine solides buch, url oder ähnliches, das unter anderem sockets, die verwendung von system.io und ähnliches unter verwendung von .net2 erklärt?

in der hoffnung, hilfe zu finden....

L
8 Beiträge seit 2004
vor 18 Jahren

Teste doch erst mal mit einem Terminalprogramm (Hyperterminal ...), ob der Leser funktioniert.
So wie Du das beschrieben hast, solltest Du erst die Karte lesen und dann den Button klicken, denn das ReadLine() im Click-Ereignis läuft sonst ins Leere.

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

im hyperterminal funktioniert es problemlos. bei auflegen der karte erscheinen die ausgelesenen zeichen...

es sind immer exakt 24 zeichen, die ausgelesen werden - zahlen und buchstaben...

nach dem klick auf den button hängt das programm... kann es sein, dass ich auch noch eine art timeout definieren muss?

L
8 Beiträge seit 2004
vor 18 Jahren

Womit wird denn der Datensatz abgeschlossen? Evtl. mal mit SerialPort.NewLine experimentieren.

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

es endet mit einem Enter.

Habs so Probiert:

SerialPort1.ReadTo((Char)13);

doch irgendwie hängt das form sobald ich auf den button klicke...

L
8 Beiträge seit 2004
vor 18 Jahren

Was kommt genau? "\r\n", "\r", "\n"? ReadLine liest bis zum angegebenen NewLine. Das ist standardmäßig "\n".

D
82 Beiträge seit 2005
vor 18 Jahren

Du benutz doch die SerialPort Komponente ?

Wo führst du das readline aus?
Wenn du es direkct nach dem Button klick ausführst könnte es sein das noch keine Daten zum lesen das sind.

Benutze das Event des SerialPort "OnDataRecived" und führe darin das readline aus.

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

wie mache ich es denn, dass ich einfach ab dem klick oder gleich bei programmstart an com1 horche? sobald etwas ausgelesen wird, gibt er es mir dann in einem label oder textfeld aus...

kann man dazu die timer_tick komponente verwenden?

readline wir im button_klick event ausgeführt...

ondatareceived werde ich testen. wird das auch als private void ausgeführt?

L
667 Beiträge seit 2004
vor 18 Jahren

Hallo schnurzli,

es gibt eine Methode in einer Windows-API dll (ich glaube es ist die kernel32.dll, aber auswendig weiss ich es grad auch nicht), die Methode heisst jedenfalls CreateFile.

Die kannst Du benutzen um den seriellen Port quasi als "File" zu öffnen. Da kannst dann ganz normal reinschreiben oder draus lesen.

Such einfach mal bei Codeproject, da gibt es einen Artikel dazu, der erklärt wie man genau auf dieser Methode aufbauend von .NET aus auf die RS232 Schnittstelle kommt.

Das .NET Framework selbst bietet leider keinen direkten Zugang, da man das neuerdings bei Microsoft wohl als Sicherheitsrisiko einstuft.

"It is not wise to be wise" - Sun Tzu

S
8.746 Beiträge seit 2005
vor 18 Jahren

Für alle Probleme, die im Zusammenhang mit serieller Kommunikation auftreten gibt es ein tolles Tool namens "PortMon".

Kann man hier downloaden:

http://www.sysinternals.com/utilities/portmon.html

Zeigt alle Daten an, die irgendwie über die serielle Schnittstelle flitzen. Daran kann man dann gut erkennen, ob man vielleicht ewig auf ein Zeichen wartet, was vielleicht nie kommt...

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

hallo,

habe portmon gestartet und dann auch etwas eingelesen...

die ausgabe funktioniert noch nicht in dem form...

laut dem portmon werden die daten alle richtig übertragen... auch die einstellungen, 9600,7, even, 1...

ich weiss nicht mehr weiter...
ich habe versucht, ondatareceived zu inkludieren, jedoch wird der code nicht angenommen...

hier das logfile:


0	0.00006509	rs232.vshost.ex	IRP_MJ_CREATE	Serial0	SUCCESS	Options: Open 	
1	0.00000363	rs232.vshost.ex	IOCTL_SERIAL_GET_PROPERTIES	Serial0	SUCCESS		
2	0.00000475	rs232.vshost.ex	IOCTL_SERIAL_GET_MODEMSTATUS	Serial0	SUCCESS		
3	0.00000307	rs232.vshost.ex	IOCTL_SERIAL_GET_BAUD_RATE	Serial0	SUCCESS		
4	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_LINE_CONTROL	Serial0	SUCCESS		
5	0.00000279	rs232.vshost.ex	IOCTL_SERIAL_GET_CHARS	Serial0	SUCCESS		
6	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_HANDFLOW	Serial0	SUCCESS		
7	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_BAUD_RATE	Serial0	SUCCESS		
8	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_LINE_CONTROL	Serial0	SUCCESS		
9	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_CHARS	Serial0	SUCCESS		
10	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_HANDFLOW	Serial0	SUCCESS		
11	0.00001201	rs232.vshost.ex	IOCTL_SERIAL_SET_BAUD_RATE	Serial0	SUCCESS	Rate: 9600	
12	0.00000643	rs232.vshost.ex	IOCTL_SERIAL_SET_RTS	Serial0	SUCCESS		
13	0.00000670	rs232.vshost.ex	IOCTL_SERIAL_CLR_DTR	Serial0	SUCCESS		
14	0.00000475	rs232.vshost.ex	IOCTL_SERIAL_SET_LINE_CONTROL	Serial0	SUCCESS	StopBits: 1 Parity: EVEN WordLength: 7	
15	0.00000279	rs232.vshost.ex	IOCTL_SERIAL_SET_CHAR	Serial0	SUCCESS	EOF:1a ERR:3f BRK:3f EVT:1a XON:11 XOFF:13	
16	0.00000838	rs232.vshost.ex	IOCTL_SERIAL_SET_HANDFLOW	Serial0	SUCCESS	Shake:0 Replace:44 XonLimit:1024 XoffLimit:1024	
17	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_BAUD_RATE	Serial0	SUCCESS		
18	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_LINE_CONTROL	Serial0	SUCCESS		
19	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_CHARS	Serial0	SUCCESS		
20	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_HANDFLOW	Serial0	SUCCESS		
21	0.00001201	rs232.vshost.ex	IOCTL_SERIAL_SET_BAUD_RATE	Serial0	SUCCESS	Rate: 9600	
22	0.00000643	rs232.vshost.ex	IOCTL_SERIAL_SET_RTS	Serial0	SUCCESS		
23	0.00000643	rs232.vshost.ex	IOCTL_SERIAL_CLR_DTR	Serial0	SUCCESS		
24	0.00000475	rs232.vshost.ex	IOCTL_SERIAL_SET_LINE_CONTROL	Serial0	SUCCESS	StopBits: 1 Parity: EVEN WordLength: 7	
25	0.00000279	rs232.vshost.ex	IOCTL_SERIAL_SET_CHAR	Serial0	SUCCESS	EOF:1a ERR:3f BRK:3f EVT:1a XON:11 XOFF:13	
26	0.00000475	rs232.vshost.ex	IOCTL_SERIAL_SET_HANDFLOW	Serial0	SUCCESS	Shake:0 Replace:44 XonLimit:1024 XoffLimit:1024	
27	0.00000670	rs232.vshost.ex	IOCTL_SERIAL_CLR_DTR	Serial0	SUCCESS		
28	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_BAUD_RATE	Serial0	SUCCESS		
29	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_LINE_CONTROL	Serial0	SUCCESS		
30	0.00000223	rs232.vshost.ex	IOCTL_SERIAL_GET_CHARS	Serial0	SUCCESS		
31	0.00000251	rs232.vshost.ex	IOCTL_SERIAL_GET_HANDFLOW	Serial0	SUCCESS		
32	0.00001201	rs232.vshost.ex	IOCTL_SERIAL_SET_BAUD_RATE	Serial0	SUCCESS	Rate: 9600	
33	0.00000670	rs232.vshost.ex	IOCTL_SERIAL_CLR_RTS	Serial0	SUCCESS		
34	0.00000643	rs232.vshost.ex	IOCTL_SERIAL_CLR_DTR	Serial0	SUCCESS		
35	0.00000475	rs232.vshost.ex	IOCTL_SERIAL_SET_LINE_CONTROL	Serial0	SUCCESS	StopBits: 1 Parity: EVEN WordLength: 7	
36	0.00000279	rs232.vshost.ex	IOCTL_SERIAL_SET_CHAR	Serial0	SUCCESS	EOF:1a ERR:3f BRK:3f EVT:1a XON:11 XOFF:13	
37	0.00000838	rs232.vshost.ex	IOCTL_SERIAL_SET_HANDFLOW	Serial0	SUCCESS	Shake:0 Replace:4 XonLimit:1024 XoffLimit:1024	
38	0.00000643	rs232.vshost.ex	IOCTL_SERIAL_CLR_RTS	Serial0	SUCCESS		
39	0.00000279	rs232.vshost.ex	IOCTL_SERIAL_SET_TIMEOUTS	Serial0	SUCCESS	RI:-1 RM:-1 RC:-2 WM:0 WC:0	
40	0.00000419	rs232.vshost.ex	IOCTL_SERIAL_SET_WAIT_MASK	Serial0	SUCCESS	Mask: RXCHAR RXFLAG CTS DSR RLSD BRK ERR RING 	
41	0.00000307	rs232.vshost.ex	IOCTL_SERIAL_SET_QUEUE_SIZE	Serial0	SUCCESS	InSize: 1024 OutSize: 2048	
42	41.18181473	rs232.vshost.ex	IOCTL_SERIAL_WAIT_ON_MASK	Serial0	SUCCESS		
43	0.00000838	rs232.vshost.ex	IOCTL_SERIAL_WAIT_ON_MASK	Serial0	SUCCESS		
44	0.00753979	rs232.vshost.ex	IOCTL_SERIAL_WAIT_ON_MASK	Serial0	SUCCESS		
45	0.00000866	rs232.vshost.ex	IOCTL_SERIAL_WAIT_ON_MASK	Serial0	SUCCESS		
46	0.00799180	rs232.vshost.ex	IOCTL_SERIAL_WAIT_ON_MASK	Serial0	SUCCESS		
47	0.00000838	rs232.vshost.ex	IOCTL_SERIAL_WAIT_ON_MASK	Serial0	SUCCESS		
48	1.91058249	rs232.vshost.ex	IOCTL_SERIAL_WAIT_ON_MASK	Serial0	SUCCESS		
49	0.00000950	rs232.vshost.ex	IOCTL_SERIAL_WAIT_ON_MASK	Serial0	SUCCESS		
50	0.00000000	rs232.vshost.ex	IOCTL_SERIAL_WAIT_ON_MASK	Serial0		
S
8.746 Beiträge seit 2005
vor 18 Jahren

Du öffnest die Schnittstelle, aber Zeichen kommen da keine reine...... daher wohl auch nicht im Programm.

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

was auch komisch ist, dass die konfigurationsdaten 3 mal übertragen werden...

SERIAL_WAIT_ON_MASK sollte ja nur einmal erscheinen, es erscheint aber gleich 5mal wenn ich die karte auf den leser lege und 4 mal wenn ich die karte wegnehme...

S
8.746 Beiträge seit 2005
vor 18 Jahren

Benutze mal PortMon in Zusammenhang mit Hyperterminal. Und falls dort was ankommt, schau dir nochmal das Log an.

185 Beiträge seit 2005
vor 18 Jahren

Hallo,

wenn ich das richtig gesehen habe, löscht du RTS. Vielleicht sendet deshalb der Kartenleser nicht. Hyperterminal setzt RTS immer.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Ich vermute mal, dass der Kartenleser sowieso nur mit ner 3-Drahtleitung verbunden ist. Damit wird RTS überhaupt nicht übertragen. Es wird ja auch kein HW-Handshake benutzt. Zudem schien ja im Hyperterm was anzukommen, nur in seiner App nicht.

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

@svenson: habe es bereits getestet. beim ht kommt die konfiguration einmal und dann wird bei auflegen der karte ein string ausgelesen... bei dem script kommt die konf mehrmals und bei auflegen der karte erscheint nur das bereits erwähnte SERIAL_WAIT_ON_MASK....

@martinh: wie setze ich das rts im script? habe versucht RTSEnable auf true zu setzen, doch kein erfolg....

kann es sein, dass ich den read irgendwie mit einem write anstossen muss?

mein code:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace rs232
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            serialPort1.Open();
        }
        private void Form1_Load(object sender, EventArgs e)
        {     
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Close();
        }
        private void serialPort1_onDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            textBox1.Text = serialPort1.ReadLine();
            textBox1.Text = serialPort1.ReadTo("\n");
        }
    }
}

ja und das steht in der designer.cs des forms:


 this.serialPort1 = new System.IO.Ports.SerialPort(this.components);
            // 
            // serialPort1
            // 
            this.serialPort1.DataBits = 7;
            this.serialPort1.Parity = System.IO.Ports.Parity.Even;
            this.serialPort1.ReadBufferSize = 1024;
            this.serialPort1.RtsEnable = true;

185 Beiträge seit 2005
vor 18 Jahren

Ich benutze OpenNetCF für meine Progs die mit der Seriellen Schnittstelle arbeiten. Das funktioniert gut bei mir. Ich benutze aber auch .Net 1.1.

Ich würde einfach mal mit einer 2. Schnittstelle und einen Nullmodemkabel versuchen etwas aus der Schnittstelle zu lesen.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Lass mal die Read-Funktionen in OnDataReceived weg und setze mal einfach einen Breakpoint mit dem Debugger rein. Der sollte auch angesprungen werden.

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

springt leider nicht bis dort hin. ich glaube mir fehlt die verbindung zu ondatareceived...

S
8.746 Beiträge seit 2005
vor 18 Jahren

In deinem Code ist zumindest kein Einhängen in den Event zu sehen.....

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

🙁 das ist gemein, aber ich verstehs natürlich. anders lerne ich nur das abschreiben des codes, was ncith sehr förderlich wäre 🙂 ich werde versuchen, ein "event einzuhängen"

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

wo finde ich ausreichend informationen, um rs232 unter .net2 ausführen zu können? gibt es da eine gute empfehlung?

lg

S
8.746 Beiträge seit 2005
vor 18 Jahren

Vermutlich gibts da nicht viel, denn eigentlich ist es ziemlich einfach und die Hilfe beschreibt das auch ausreichend. Es gibt - wie praktisch überall in .NET - die Möglichkeit synchron zu arbeiten (z.B. mit ReadLine()) oder ereignisgesteuert, also asynchron über den OnDataReceived-Event. Viel mehr gibts eigentlich nicht zu wissen. Über RS-232 im Allgemeinen gibts viel im Netz (Handshaking, Steuerleitungen, etc.).

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

hallo,

habe jetzt das ondatareceived event eingebaut. bemerkte, dass ich wie in vb.net ein delegate benötige... zumindest funktioniert es so teilweise...

in meinem form.cs rufe ich das wie folgt auf:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace rs232
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            serialPort1.Open();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            Close();
        }
        
        delegate void MessageDataDelegate(string data);
        private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            MessageDataDelegate dlgte = new MessageDataDelegate(MessageData);
            string recvData = serialPort1.ReadExisting();
            this.Invoke(dlgte, new object[] { recvData });
        }
        private void MessageData(string data)
        {
            textBox1.Text = data;
        }
    }
}

jetzt werden aber nur noch die letzten 6 zeichen des strings in der textbox ausgegeben. laut port mon werden sie immer zu 8 zeichen großen teilen eingelesen. ds heisst, dass die textbox sehr wohl alle ausgibt aber eben nur nacheinander...

wie schafft man es, dass man den string als gesamtes ausliest und in der textbox ausgibt?

meine idee wäre eben, dass ich anstelle von readexisting mit readline arebeite und dann auf ein ende warte.... das funkr aber so nicht wie ich es probiert habe...

S
8.746 Beiträge seit 2005
vor 18 Jahren

Kurz gesagt: Gar nicht. Du musst bei asynchronem Vorgehen immer davon ausgehend, dass dir gesendet Daten in beliebigen "Paketen" eingehen. Obwohl dein Leser vielleicht 8 Zeichen am Stück gesendet hat, kommen auf Empfängerseite erst 6, dann 2 Zeichen an, oder sogar jedes Zeichen einzeln. Es ist also an dir die Zeichen zusammenzubasteln. Die serielle Schnittstelle verhält sich wie ein Stream (ist auch einer) und ist kein Paketdienst, der sicherstellt, dass Daten auch gemeinsam eintrudeln.

Wenn du tatsächlich zu jedem Zeitpunkt weisst, wie viel Zeichen erwartet werden, bzw. du ein Trennerzeichen kennst, was ein Paket abschliesst, dann ist es i.d.R. wirklich besser mit densychronen Funktionen zu arbeiten, aber eben nicht in OnDataReceived, sondern in einer eigene Ablaufkonstruktion. Üblicherweise definiert man für solche Protokolle eine Zustandsmaschine.

OnDatareceived hingegen bietet sich eher für streamorientierte Protokolle an.

S
schnurzli Themenstarter:in
34 Beiträge seit 2006
vor 18 Jahren

habs jetzt hinbekommen. es funkt doch 🙂
mit readto... hatte ich schon mal probiert aber mit \n.
funktioniert anscheinend aber nur mit \r...


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace rs232
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            serialPort1.Open();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            Close();
        }
        
        delegate void MessageDataDelegate(string data);
        private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            MessageDataDelegate dlgte = new MessageDataDelegate(MessageData);
            string recvData = serialPort1.ReadTo("\r");
            this.Invoke(dlgte, new object[] { recvData });
        }
        private void MessageData(string data)
        {
            label1.Text = data;
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }
    }
}