我用 C# 2.0 编写了一个简单的应用程序,使用 .Net Framework 2.0 Serialport 类通过 COM1 与控制器卡进行通信。
最近出现一个问题,Read方法返回的字节不正确。 它返回了正确的字节数,只是值不正确。 不过,用 Delphi 编写的类似应用程序仍然返回正确的值。
我使用 Portmon 记录两个应用程序串行端口上的活动,比较了两个日志,其中有一些(显然)细微的不同设置,我尝试尽可能地模仿 Delphi 应用程序,但无济于事。
那么,什么会影响 Read 方法返回的字节值呢?
这两个应用程序之间的大多数设置都是相同的。
以下是 Portmon 日志中不同行的列表:
Delphi 应用程序:
IOCTL_SERIAL_SET_CHAR Serial0 SUCCESS EOF:dc
ERR:0 BRK:0 EVT:0 XON:11 XOFF:13
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS 震动:0
替换:0 XonLimit:256
XoffLimit:256 IOCTL_SERIAL_SET_TIMEOUTS Serial0 SUCCESS RI:-1
RM:100 RC:1000 WM:100 WC:1000 IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS 掩码:
RXCHAR RXFLAG TXEMPTY CTS DSR RLSD
BRK ERR RING RX80FULL
C# 应用程序:
IOCTL_SERIAL_SET_CHAR Serial0 成功 EOF:1a
ERR:0 BRK:0 EVT:1a XON:11 XOFF:13
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS 震动:0
替换:0 XonLimit:1024
XoffLimit:1024 IOCTL_SERIAL_SET_TIMEOUTS Serial0 SUCCESS RI:-1
RM:-1 RC:1000 WM:0 WC:1000 IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS 掩码:
RXCHAR RXFLAG CTS DSR RLSD BRK ERR
戒指
更新:
正确返回的字节为:91、1、1、3、48、48、50、69、66、51、70、55、52、93(14 个字节)。
最后一个值是一个简单的校验和。
返回的错误值是:91、241、254、252、242、146、42、201、51、70、55、52、93(13 个字节)。
正如您所看到的,返回的第一个和最后五个字节是对应的。
ErrorReceived 事件表示发生了帧错误,这可以解释错误的值。 但问题是为什么 SerialPort 会遇到帧错误,而 Delphi 应用程序显然不会遇到帧错误?
I've written a simple app in C# 2.0 using the .Net Framework 2.0 Serialport class to communicate with a controller card via COM1.
A problem occurred recently were the bytes returned by the Read method are incorrect. It returned the right amount of bytes, only the values were incorrect. A similar app written in Delphi still returned the correct values though.
I used Portmon to log the activity on the serial port of both apps, compared the two logs and there where some (apparently) minor different settings and I tried to the imitate the Delphi app as closely as possible, but to no avail.
So, what could affect the byte values returned by Read method ?
Most settings between the two apps are identical.
Here is a list of the lines which differed in the Portmon log :
Delphi App :
IOCTL_SERIAL_SET_CHAR Serial0 SUCCESS EOF:dc
ERR:0 BRK:0 EVT:0 XON:11 XOFF:13
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:0
Replace:0 XonLimit:256
XoffLimit:256 IOCTL_SERIAL_SET_TIMEOUTS Serial0 SUCCESS RI:-1
RM:100 RC:1000 WM:100 WC:1000 IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask:
RXCHAR RXFLAG TXEMPTY CTS DSR RLSD
BRK ERR RING RX80FULL
C# App :
IOCTL_SERIAL_SET_CHAR Serial0 SUCCESS EOF:1a
ERR:0 BRK:0 EVT:1a XON:11 XOFF:13
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:0
Replace:0 XonLimit:1024
XoffLimit:1024 IOCTL_SERIAL_SET_TIMEOUTS Serial0 SUCCESS RI:-1
RM:-1 RC:1000 WM:0 WC:1000 IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask:
RXCHAR RXFLAG CTS DSR RLSD BRK ERR
RING
UPDATE:
The correct returned bytes were : 91, 1, 1, 3, 48, 48, 50, 69, 66, 51, 70, 55, 52, 93 (14 bytes).
The last value being a simple checksum.
The incorrect values returned were : 91, 241, 254, 252, 242, 146, 42, 201, 51, 70, 55, 52, 93 (13 bytes).
As you can see the first and the last five bytes returned correspond.
The ErrorReceived event indicates that a framing error occurred, which could explain the incorrect values. But the question is why would SerialPort encounter a framing error when the Delphi app apparently does not ?
发布评论
评论(4)
好吧,看来问题已经解决了(至少暂时是这样)。
显然,帧错误导致返回不正确的值。 我使用 MSComm 控件编写了一个 VB6 应用程序,运行良好,并比较了 Portmon 生成的日志文件。
以下差异
我发现了VB6 App 的
C# 应用程序:
尝试设置我发现如果我设置
_serialPort.DtrEnable = true
C# 应用程序生成以下日志条目:
这似乎可以防止帧错误,并且应用程序似乎工作正常。
Well, it seems as if the problem has been resolved (at least for the time being).
Apparently a framing error caused the return of incorrect values. I wrote a VB6 app, using the MSComm control, which worked fine, and compared the log files generated by Portmon.
I picked up the following differences
VB6 App :
C# App :
Playing around with the settings I found that if I set
_serialPort.DtrEnable = true
the C# App generates the following log entry :
That seemed to prevent the framing error and the application seems to be working fine.
不幸的是,您没有具体提及您得到的差异类型。 是偶尔有不同的字符还是您所有传入的数据都是乱码?
请注意,由于 SerialPort.Encoding 属性。 此设置会影响传入文本的解释,因为它是 ASCII、Unicode、UTF8 或 Windows 用于“原始字节”到“可读文本”转换的任何其他编码方案的文本。
Unfortunately you did not mention exactly what type of differences you get. Is it an occasional character that is different or is all your incoming data garbled ?
Note that characters read through the SerialPort.Read function could be changed by the system due to the setting of the SerialPort.Encoding property. This setting affects the interpretation of the incoming text as it was text in ASCII, Unicode, UTF8 or any other coding scheme Windows uses for 'raw byte(s)' to 'readable text' conversion.
您是否检查过数据位数、停止位和奇偶校验的设置?
奇偶校验位是一种错误检测机制。 例如:如果使用 7 个数据位和 1 个奇偶校验位发送,则第八位将用于检测位反转错误。 如果接收器期望 8 个数据位且没有奇偶校验位,则结果将是乱码。
Have you checked the settings for number of data bits, stop bits and parity?
The parity bit is a kind of error detection mechanism. For instance: If you send using 7 data bits and one parity bit, the eighth bit will be used for detecting bit inversion errors. If the receiver expects 8 data bits and no parity bits, the result will be garbled.
如果您正在读入字节数组(例如:SerialPort.Read),您应该准确地获得在 PortMon 上看到的字节。
如果您要转换为字符(SerialPort.ReadLine 或 SerialPort.ReadChar),则数据将使用当前编码(SerialPort.Encoding 属性)进行编码,这解释了您所看到的差异。
如果您想查看与线路上的字节具有相同二进制值的字符,可以使用 Latin-1 进行良好的编码,如 这篇文章。
例子:
If you are reading into a byte array (ex: SerialPort.Read) you should get exactly the bytes you are seeing on PortMon.
If you are converting to characters (SerialPort.ReadLine or SerialPort.ReadChar) then the data will be encoded using the current encoding (SerialPort.Encoding property), which explains the differences you are seeing.
If you want to see characters with the same binary values as the bytes on the wire, a good encoding to use is Latin-1 as described in this post.
Example: