我如何发送字节在C#中的串行设备? [英] How do I send bytes to a serial device in C#?

查看:249
本文介绍了我如何发送字节在C#中的串行设备?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用串行(通过USB适配器)的设备可以与电脑连接。我在得到它在C#中发挥很好真正的困难。我知道它正常工作,因为供应商提供的软件行为与预期相同。我也知道,我可以用我的代码感谢测试模式,重复发送OK接收数据



下面是我的代码:

 私人的SerialPort端口; 

公共SerialConnection()
{
this.port =新的SerialPort(COM3,38400,Parity.None,8,StopBits.One);
this.port.WriteTimeout = 2000; port.ReadTimeout = 2000;

this.port.Open();

this.port.DataReceived + =新SerialDataReceivedEventHandler(port_DataReceived);
}

公共无效SendCommand(字节[]命令)
{
this.port.Write(指挥,0,command.Length);
串字符=;
的foreach(在命令字节charbyte)字符+ =(char)的charbyte;
Console.WriteLine( - >中+字符);
}

无效port_DataReceived(对象发件人,SerialDataReceivedEventArgs E)
{
字符串数据= this.port.ReadLine();
Console.WriteLine(&下; - +数据);
}



目前我使用的是应该回显另一个测试模式不管它接收。因此,我打电话SendCommand具有以下字节:

 字节[] {
为0x50,
0×69,
0x6E,
0x67
}

却迟迟没有似乎得到送回。



我不知道下一个尝试的东西。任何人有什么建议吗?






有关附属公司的问题,我已经发布了一些PortMon日志。我想他们可能是有用的在这里,所以在这里,他们是:




  1. 厂商的软件 - 以过滤掉

  2. <所有 IOCTL_SERIAL_GET_COMMSTATUS 项A HREF =htt​​p://tdwright.co.uk/myapp.log相对=nofollow>我的脚趾浸尝试


< DIV CLASS =h2_lin>解决方案

每一个RS-232设备需要使用某种形式的流量控制机制来通知有关正在进行的通信相反的一部分。有三种基本机制:




  • 基于硬件的 RTS / CTS通过两个专用的电线,通常用于控制发送数据的各个块

  • 基于硬件的 DTR / DSR 通过两个专用的电线,通常用于控制整个通信会话

  • softwa基的 XON / XOFF 通过一对专用字符(请注意,在这种情况下,需要的数据被编码,以防止与控制字符碰撞)



(开始更新)



初始队列中的遗留应用程序的长度和超时:

  1 IOCTL_SERIAL_SET_QUEUE_SIZE INSIZE:1024如雷贯耳:1024 
2 IOCTL_SERIAL_SET_TIMEOUT RI:2000 RM:0 RC:2000 WM:0 WC:2000

而你没有设置它们。请尝试使用队列大小 SerialPort.WriteBufferSize 和的 SerialPort.ReadBufferSize 。同样一套超时使用 的SerialPort .ReadTimeout 和的 SerialPort.WriteTimeout



(最终更新)



在您的情况下,传统的应用程序所做的:

  12 IOCTL_SERIAL_CLR_RTS 
13分配IOCTL_SERIAL_SET_DTR

,而你做的:

  12 IOCTL_SERIAL_CLR_RTS 
13 IOCTL_SERIAL_CLR_DTR

您没有设置DTR(数据终端就绪)信号,因此设备没有期待在串行线路上的任何数据或命令。因此,设置 SerialPort.DtrEnable 真正



第二个问题是,你不转上握手。继承应用程序所做的:

  16 IOCTL_SERIAL_SET_HANDFLOW摇:1替换:0 XonLimit:0 XoffLimit:0 
18 IOCTL_SERIAL_SET_RTS
...
21 IOCTL_SERIAL_CLR_RTS

,而你做的:

  16 IOCTL_SERIAL_SET_HANDFLOW摇:0替换:0 XonLimit:4096 XoffLimit:4096 

打开它通过设置的 SerialPort.Handshake 来的 Handshake.RequestToSend



此外,你似乎被打开,关闭和重新配置串口非常频繁。尝试设置的端口,然后使用的SerialPort 的同一个实例整个会话。不要试图重新打开它,因为你会导致重新配置到物理端口的引脚的状态。



串行通讯是不是黑魔法,但它的设置非常敏感和各种设备需要特殊的设置和治疗。命令适当的时机可能是一个问题也是如此。



如果你有你的设备的一些技术文档,不要读了两遍,并在第一个地方服从。至少握手模式,命令等应妥善记录。



如果您还没有任何文件,试图通过一个减轻区别之一。






更新:发送和接收数据。



你写你发送的命令'平'(如解码从十六进制ASCII)。但是,你不提送和指挥终止序列。 一般的串行设备期望尾线的序列(通常是CR LF)作为命令的终止。设备接收之前的完整的命令行,包括结束,所以不能回答。



您正在处理中的数据通过调用的ReadLine 接收事件 - 但是,你不能指望一个地方数据的全线(即包括一个线端,以便能够检测comlete线)。您应检查所提供的事件参数和读取输入逐字节。



这是创建一个包装类,将提供量身定做的发送命令是个好主意,接收响应,发送数据,接收数据的功能。该包装将不得不在内部方面异步工作在你的代码的其余部分。这样,你就拥有了一个可用的自定义API和一个乖巧的串行端口的处理。



请注意, SerialPort.NewLine 酒店供应指定尾线序列的模样的目的。 (在你的其他问题,你提到你试图将其设置为一组特殊字符,这是错误的确实。)






它已经有一段时间我是一个串口通信的英雄(那些日子,我们有没有VMware但有两个486马力的电脑和一对直接连接调制解调器的开发和调试交流的应用:-)),但我希望这有助于。至少有一点



最后但并非最不重要的,一些常用的术语:




  • DTE - 数据终端设备=您的comupter

  • DCE - 数据通信设备=您的设备,例如:调制解调器


I have a device that uses serial (via a USB adaptor) to interface with my PC. I'm having real difficulty getting it to play nicely in C#. I know that it works properly because the vendor-supplied software behaves as expected. I also know that I am able to receive data using my code thanks to a test mode which repeatedly sends "OK".

Here's my code:

    private SerialPort port;

    public SerialConnection()
    {
        this.port = new SerialPort("COM3", 38400, Parity.None, 8, StopBits.One);
        this.port.WriteTimeout = 2000; port.ReadTimeout = 2000;

        this.port.Open();

        this.port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
    }

    public void SendCommand(byte[] command)
    {
        this.port.Write(command,0,command.Length);
        string chars = "";
        foreach (byte charbyte in command) chars += (char)charbyte;
        Console.WriteLine(" -> " + chars);
    }

    void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        string data = this.port.ReadLine();
        Console.WriteLine(" <- " + data);
    }

At the moment I'm using another test mode which is supposed to echo back whatever it receives. Accordingly, I'm calling SendCommand with the following bytes:

byte[] {
    0x50,
    0x69,
    0x6E,
    0x67
}

But nothing ever seems to get sent back.

I've no idea what to try next. Anyone got any suggestions?


For a subsidiary question I've posted some PortMon logs. I think they might be useful here too, so here they are:

  1. Vendors software - with all the IOCTL_SERIAL_GET_COMMSTATUS entries filtered out
  2. My toe-dip attempt

解决方案

Every RS-232 device needs to use some sort of flow control mechanism to notify the opposite part about ongoing communication. There are three basic mechanisms:

  • hardware-based RTS/CTS via two dedicated wires, usually used for controlling sending of individual chunks of data
  • hardware-based DTR/DSR via two dedicated wires, usually used for controlling the whole communication session
  • softwa-based XON/XOFF via a pair of dedicated characters (note that in this case data needs to be encoded to prevent collisions with control characters)

(start update)

Initial queue length and timeouts in the legacy app:

1  IOCTL_SERIAL_SET_QUEUE_SIZE  InSize: 1024 OutSize: 1024
2  IOCTL_SERIAL_SET_TIMEOUT  RI:2000 RM:0 RC:2000 WM:0 WC:2000

while you don't set them. Try setting the queue sizes using SerialPort.WriteBufferSize and SerialPort.ReadBufferSize. Likewise set timeouts using SerialPort.ReadTimeout and SerialPort.WriteTimeout.

(end update)

In your case the legacy app does:

12  IOCTL_SERIAL_CLR_RTS
13  IOCTL_SERIAL_SET_DTR

while you do:

12  IOCTL_SERIAL_CLR_RTS
13  IOCTL_SERIAL_CLR_DTR

You don't set the DTR (Data Terminal Ready) signal and hence the device is not expecting any data or commands on the serial line. Hence set SerialPort.DtrEnable to true.

Second problem is you don't turn on handshaking. The legacy app does:

16  IOCTL_SERIAL_SET_HANDFLOW  Shake:1 Replace:0 XonLimit:0 XoffLimit:0
18  IOCTL_SERIAL_SET_RTS
…
21  IOCTL_SERIAL_CLR_RTS

while you do:

16  IOCTL_SERIAL_SET_HANDFLOW  Shake:0 Replace:0 XonLimit:4096 XoffLimit:4096

Turn it on by setting SerialPort.Handshake to Handshake.RequestToSend.

Also, you seem to be opening, closing, and reconfiguring the serial port very frequently. Try to setup the port and then use the same instance of SerialPort for the whole session. Do not try to reopen it, because you will be causing reconfigurations to the state of the physical port's pins.

Serial communication is not black magic, but it's quite sensitive on setup and various devices require special settings and treatment. Proper timing of commands may be an issue as well.

If you do have some technical documentation for your device, do read it twice and obey it at the first place. At least handshaking modes, commands, etc. should be documented properly.

If you don't have any documentation, try to mitigate differences one by one.


UPDATE: Sending and receiving data.

You wrote you sent the command 'Ping' (as decoded from hex to ASCII). However, you don't mention sending and command termination sequence. Usually serial devices expect an end-of-line sequence (typically a CR LF) as the termination of the command. Before the device receives a complete command including line end, it can't reply.

You are handling the data receive event by calling ReadLine — however, at the place you can't expect a full line of data (i.e. including a line end to be able to detect a comlete line). You should inspect the event arguments provided and read the input byte-by-byte.

It's a good idea to create a wrapper class that will provide a tailored send-command, receive-response, send-data, receive-data features. The wrapper will have to internally work asynchronously in respect to the rest of your code. That way you will have a usable custom API and a well-behaved serial port handling.

Note that the SerialPort.NewLine property serves the purpose of specifying how a an end-of-line sequence looks like. (In your other question you mentioned you were trying to set it to the set of special characters. That was wrong indeed.)


It's been some time I was a serial comm hero (those were the days we had no vmware but two 486-powered PCs and a pair of directly connected modems to develop and debug communication apps :-)), but I hope this helps at least a bit.

Last but not least, some common terminology:

  • DTE — Data Terminal Equipment = your comupter
  • DCE — Data Communications Equipment = your device, e.g. a modem

这篇关于我如何发送字节在C#中的串行设备?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆