4

我正在用 Visual Basic 编写一个程序,但遇到了一个奇怪的问题。我正在通过串行端口将字符串发送到望远镜支架。当我发送check字符串时,范围可以返回 chr(0) 或 chr(255)。这在返回 chr(255) 的 python 和 c++ 中运行良好。但是,当我在 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
4

1 回答 1

9

.NETSerialPort类有一个Encoding与之关联的用于在端口上发送的文本和字节之间的转换。文档说它用于“文本的传输前和传输后转换”。尚不清楚Encoding用于将接收到的字节转换为string返回 fromt的文本ReadTo()(但这可能是“传输后”的意思)。

无论如何,我很确定这就是你的255角色所发生的事情。该ReadTo()方法使用Encoding将接收到的数据转换为文本以放入string. 默认Encoding值为ASCIIEncoding,它只处理0x00-范围内的字符0x7f。超出该范围的字节将被编码为'?'字符,其 ASCII 值恰好为63.

改用该ReadByte()方法从端口读取数据,而不涉及任何文本编码。

更新:我发现 BCL 团队中某人的博客文章证实了这一点,并指出了一个编码对象,它将传递未经修改的 8 位数据。Ryan Byington 于2006 年 5 月 26 日在 Base Class Library (BCL) 博客上的一篇名为“SerialPort Encoding”的文章中写道:

该类SerialPort使用该 SerialPort.Encoding属性指定的编码将字符串和字符数组转换为字节以通过串行端口发送。当从串口读取时,也会使用这种编码,将串口接收到的字节转换为字符串和字符数组。

默认情况下,SerialPort该类使用 ASCII 编码,它将所有值为 0-127 的字符转换为具有相同值的单个字节。所以“Hello”被转换为字节数组 {72, 101, 108, 108, 111}。但是,每个其他字符都会转换为值为 63 的字节或'?'字符。这也适用于读取,因此如果串行端口接收到字节数组 {72、101、108、108、111},它会将其转换为“Hello”,并且任何值大于 127 的字节都将转换为'?'字符。

ASCII 编码对大多数串行设备都非常有效,但仍有不少设备发送值超过 127 的字节,或者您需要发送值大于 127 的字节。您有两种选择;一种是使用处理byte[] 和绕过Encoding,或使用正确的编码。然而,找到正确的编码有点棘手,因为大多数处理高于 127 的值的编码将使用多个字节,这可能不适用于连接到串行端口的设备。将值 0-255 的所有字符转换为具有相应值的单个字节(反之亦然)的唯一编码是“西欧 (ISO)”编码。使用以下代码将此编码与 SerialPort 类一起使用:

SerialPort mySerialPort = new SerialPort("COM1");
mySerialPort.Encoding = Encoding.GetEncoding(28591);
于 2015-06-13T05:23:23.137 回答