[英]How do I send bytes to a serial device in C#?
我有一个使用串行(通过USB适配器)与我的PC连接的设备。 我真的很难让它在C#中很好地发挥。 我知道它工作正常,因为供应商提供的软件表现得如预期的那样。 我也知道我能够使用我的代码接收数据,这要归功于一个重复发送“OK”的测试模式。
这是我的代码:
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);
}
目前我正在使用另一种测试模式,该模式应该回显它收到的任何内容。 因此,我用以下字节调用SendCommand:
byte[] {
0x50,
0x69,
0x6E,
0x67
}
但似乎没有任何东西被送回去。
我不知道下一步该尝试什么。 有人有什么建议吗?
对于一个附属问题,我发布了一些PortMon日志。 我认为它们在这里也可能有用,所以它们在这里:
每个RS-232设备都需要使用某种流量控制机制来通知相对的部分正在进行的通信。 有三种基本机制:
(开始升级)
旧版应用中的初始队列长度和超时:
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
而你没有设置它们。 尝试使用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
设置为true
。
第二个问题是你不打开握手。 遗留应用程序:
16 IOCTL_SERIAL_SET_HANDFLOW Shake:1 Replace:0 XonLimit:0 XoffLimit:0
18 IOCTL_SERIAL_SET_RTS
…
21 IOCTL_SERIAL_CLR_RTS
你做的时候:
16 IOCTL_SERIAL_SET_HANDFLOW Shake:0 Replace:0 XonLimit:4096 XoffLimit:4096
将SerialPort.Handshake
设置为Handshake.RequestToSend
将其打开。
此外,您似乎经常打开,关闭和重新配置串行端口。 尝试设置端口,然后在整个会话中使用相同的SerialPort
实例。 不要尝试重新打开它,因为您将导致重新配置物理端口引脚的状态。
串行通信不是黑魔法,但它对设置非常敏感,各种设备需要特殊的设置和处理。 适当的命令时序也可能是个问题。
如果您的设备确实有一些技术文档,请先阅读两次,并在第一时间遵守它。 至少应妥善记录握手模式,命令等。
如果您没有任何文档,请尝试逐个缓解差异。
更新:发送和接收数据。
您写道,您发送了命令'Ping'
(从十六进制解码为ASCII)。 但是,您没有提到发送和命令终止序列。 通常,串行设备期望行结束序列(通常是CR LF)作为命令的终止。 在设备收到包含行结束的完整命令之前,它无法回复。
您正在通过调用ReadLine
来处理数据接收事件 - 但是,在您不能指望完整数据行的位置(即包括行结束以检测COMlete行)。 您应该检查提供的事件参数并逐字节读取输入。
创建一个包装类是个好主意,它将提供定制的发送命令,接收响应,发送数据,接收数据功能。 包装器必须在内部与代码的其余部分异步工作。 这样,您将拥有可用的自定义API和良好的串行端口处理。
请注意, SerialPort.NewLine
属性用于指定行尾序列的外观。 (在你提到的另一个问题中,你试图将它设置为特殊字符集。这确实是错误的。)
曾经有一段时间我是一个串行通讯英雄(那些是我们没有vmware的日子,但有两台486供电的PC和一对直接连接的调制解调器来开发和调试通信应用程序:-)),但我希望这至少有帮助一点点。
最后但并非最不重要的一些常用术语:
您是否尝试过更改Handshake属性? 也许设备在接受数据之前需要在控制引脚上进行一些握手。
您应该打开RtsEnable或DtrEnable属性,设备将忽略您发送的任何内容,也不会在这些信号未在线检测到您时发回任何内容。 将Handshake属性设置为RTS应该已经这样做了。
请注意,ReadLine()方法将阻塞,直到获取NewLine字符。 你没有发送一个,所以你也不会回来。 使用Read()将是一个更好的测试。
首先使用已知的工作程序进行一些基本的故障排除,消除接线问题,错误的波特率或设备根本不回显。 使用超级终端或腻子。
汤姆,
我有类似的问题,
我打赌我的赌注是ReadLine()只有在收到\\ r \\ n或者.NET认为是新行的东西后才会返回。
在你的日志中,我没有看到Winbird报告任何新行字符,我相信APP正在逐字节读取,而不是等待换行。
因此,您可以向其发送许多字节的数据,并且它将继续阻塞,直到它收到正确的新行字符。
所以试试SerialPort.Read,一次读取1个字节给初学者,
public int Read (
byte[] buffer,
int offset,
int count
)
如果这没有解决它,您可能需要考虑以下内容
我的一些问题通过添加一些Thread.Sleep()来解决,因为我意识到PC的UART速度不够快,不能正确地通过RS232 / RS485端口电传输数据,也可以在打开端口后等待几毫秒。
我还建议你创建一个单独的线程来处理串行通信,而不是使用SerialDataReceivedEventHandler,创建一个发送缓冲区,它以正确的增量发送而不阻塞你的应用程序,也读取数据并将接收到的字节追加到缓冲区,直到你收到了足够的数据。
您还需要第二个串行设备来捕获数据,以确保您的C#应用程序正在传输正确的数据。
要消除握手问题,只需连接PIN 2,3 + PIN 5(GND)即可进行测试。
希望这可以帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.