VB.net将chr(255)返回为chr(63)。

4

我正在使用Visual Basic编写程序,遇到了一个奇怪的问题。我通过串口向望远镜发送字符串。当我发送“check”字符串时,范围可以返回chr(0)或chr(255)。在Python和C++中,这可以正常工作并返回chr(255)。但是,在Visual Basic中运行脚本时,它返回chr(0)或chr(63)。

下面是两个相同的函数,一个在Python中,一个在Visual Basic中。

有人能给我一个想法,为什么Visual Basic返回63而不是255吗?

Python中的函数(返回正确值0和255):

global d, check
d=chr(80)+chr(4)+chr(16)+chr(2)+chr(1)+chr(112)+chr(252)+chr(0)
check=chr(80) + chr(1) + chr(16) + chr(19) + chr(0) + chr(0) + chr(0)+chr(1)


def test():
    ser.write(d)
    time.sleep(.1)
    print ser.readline()
    ser.write(check)
    time.sleep(.1)
    out=ser.readline()[0]
    print "out=",ord(out)
    while out == chr(0):
            print "out = ", ord(out)
            ser.write(check)
        time.sleep(.1)
            out=ser.readline()[0]
        print "out=",ord(out)
    print "out is now", ord(out)
    ser.readline()

Visual Basic中的脚本(返回不正确的值0和63)

Public Sub test()
    Dim out As Char
    Dim d As String = Chr(80) + Chr(4) + Chr(16) + Chr(2) + Chr(1) + Chr(112) + Chr(252) + Chr(0)
    Dim check As String = Chr(80) + Chr(1) + Chr(16) + Chr(19) + Chr(0) + Chr(0) + Chr(0) + Chr(1)
    port.Write(d)
    Threading.Thread.Sleep(100)
    Console.Write(port.ReadTo("#"))
    port.Write(check)
    Threading.Thread.Sleep(100)
    out = port.ReadTo("#")
    Console.Write(vbNewLine & "out=" & out)
    While out = Chr(0)
        Console.Write("out = " & Convert.ToInt16(out))
        port.Write(check)
        Threading.Thread.Sleep(0.1)
        out = port.ReadTo("#")
        Console.Write("out=" & Convert.ToInt16(out))
    End While
    Console.Write("out is now" & Convert.ToInt16(out))
    port.ReadLine()


End Sub

根据 MSDN,char 类型保存无符号 16 位(2 字节)代码点。 - jeffpkamp
1个回答

9
.NET的SerialPort类有一个与之相关联的编码,用于在端口上发送文本和字节之间进行转换。文档说它用于“文本的前传和后传转换”。不太清楚Encoding是否用于将接收到的字节转换为ReadTo()返回的string中的文本(但这可能是“后传”所指的)。
无论如何,我很确定这就是发生在您的255个字符上的事情。 ReadTo()方法使用Encoding将接收到的数据转换为文本以放入string中。默认的EncodingASCIIEncoding,仅处理范围在0x00 - 0x7f之间的字符。该范围之外的字节将被编码为'?'字符,其ASCII值为63
改用ReadByte()方法从端口读取数据,而不涉及任何文本编码。 更新:我找到了BCL团队中的某个人发布的博客文章,证实了这一点,并指出了一个编码对象,可以将8位数据不加修改地传递。 Ryan Byington在2006年5月26日的一篇名为“Base Class Library(BCL)Blog上的SerialPort编码”的文章中写道:

The SerialPort class uses the encoding specified by the SerialPort.Encoding property to convert strings and character arrays to bytes to send across the serial port. This encoding also gets used when reading from the serial port to convert bytes received by the serial port to strings and character arrays.

By default the SerialPort class uses ASCII encoding which converts all characters with the value of 0-127 to a single byte with the same value. So "Hello" gets converted to the byte array {72, 101, 108, 108, 111}. However every other character gets converted to a byte with the value of 63 or the '?' character. This applies for reading as well so if the serial port received the byte array {72, 101, 108, 108, 111} it will convert this to "Hello" and any byte with a value greater then 127 will get converted to the '?' character.

The ASCII encoding works perfectly fine for most serial devices but there are still quite a few device that either send bytes with values beyond 127 or you need to send bytes with values greater then 127. You have two options; one would be to use the API’s that deal with byte[] and bypass the Encoding, or to use the correct Encoding. However finding the correct encoding is a bit tricky as most encodings that deal with values above 127 will use multiple bytes which probably won’t work with the device attached to the serial port. The only encoding that converts all characters with a value 0-255 to a single byte with the corresponding value and vice versa when converting bytes to characters is the "Western European (ISO)" encoding. Use the following code to use this Encoding with the SerialPort class:

SerialPort mySerialPort = new SerialPort("COM1");
mySerialPort.Encoding = Encoding.GetEncoding(28591);

哇,很高兴我回来看了一下。非常感谢你详尽的回答!如果可以的话,我会给你两个赞的。 - jeffpkamp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接