【问题标题】:VBnet Accessing individual bits of a byte // BitArray length & count are equal to the byte value?VB net 访问字节的各个位 // ByteArray 长度和计数等于字节值?
【发布时间】:2019-07-28 07:52:54
【问题描述】:

我正在尝试与接受/发送 16 位值的 PLC 通信,每个位都允许检查是否发生。

为此,我一直在尝试使用 .Net BitArray,但结果并不成功。

底层结构由两个字节的数组组成,两个字节都用值 0 初始化。

当我使用这些字节之一创建一个新的位数组时,我希望得到一个将 8 个值设置为 false 的数组。 情况并非如此

如果字节值为 0,则位数组的长度和计数也为零。虽然我可以假设前导零被丢弃,但这似乎非常违反直觉。

当我使用值为 200 的字节创建位数组时,我希望得到一个包含 8 个值的数组(True、True、False、False、True、False、False、False) .但是,我得到一个长度和计数为 200?

的位数组

代码目前是这样的:

Private FaultBits as Byte = 0
Public Sub SetBitValue(index As Integer, value As Boolean)
    Try
        If index < 0 Then
            Throw New Exception("Index is below zero!")
        End If

        If index > 7 Then
            Throw New Exception("Index out of bounds! Maximum allowed index value is 7")
        End If

        'If BitConverter.IsLittleEndian Then
            'ToDo
        'End If

        Dim bitArray_Section As BitArray = Nothing

            bitArray_Section = New BitArray(FaultBits)
            'bitArray_Section.Length = 8  'Truncates incorrectly
            bitArray_Section.Item(index) = value 'Set the individual bit
            FaultBits = ConvertToByte(bitArray_Section) 'Set back to byte


    Catch ex As Exception
        Throw New Exception("clsFaultBits : SetBitValue : w. Index " & index & " : Exception : " & ex.Message())
    End Try
End Sub

还有 get 等价物:

 Public Function GetBitValue(index As Integer) As Boolean
    Try
        If index < 0 Then
            Throw New Exception("Index is below zero!")
        End If

        If index > 7 Then
            Throw New Exception("Index out of bounds! Maximum allowed index value is 7")
        End If


        Dim bitArray_Section As BitArray = Nothing

            bitArray_Section = New BitArray(FaultBits)
            'bitArray_Section.Length = 8
            Return bitArray_Section.Item(index)

    Catch ex As Exception
        Throw New Exception("clsFaultBits : GetBitValue : w. Index " & index & " : Exception : " & ex.Message())
    End Try
End Function

转换函数,我认为它的长度是 8,这是错误的:

Public Function ConvertToByte(bits As BitArray) As Byte
    Try
        If bits.Count <> 8 Then
            Throw New Exception("Invalid amount of bits!")
        End If

        Dim returnbyte(1) As Byte
        bits.CopyTo(returnbyte, 0)
        Return returnbyte(0)
    Catch ex As Exception
        Throw New Exception("clsFaultBits : ConvertToByte : Exception : " & ex.Message())
    End Try
End Function

ByteValue :: BitarrayLength / Count

0 :: 0 / 0

200 :: 200 / 200

10 :: 10 / 10

我想完成什么:

接收一个字节(1-0-0-1-0-0-1-0)

通过读取各个位来启用程序中的布尔值: 检查1、检查4、检查7

设置从 0-0-0-0-0-0-0-0 开始的输出字节的各个位

开启 5 : 0-0-0-0-1-0-0-0

开启 2 : 0-1-0-0-1-0-0-0

发送字节

我是否完全滥用了 BitArray 类?我究竟做错了什么? 什么可以让我更改单个位值而不会陷入这种混乱?

为什么BitArray的长度/计数与Byte的值相同,而不是Byte由多少位组成?

我知道代码尚未考虑字节序。

提前致谢,


已解决:

我没有意识到向 BitArray 发送非数组字节会将其隐式转换为整数,因此 它会创建一个 长度/计数相等的 BitArray字节的值。现在完全说得通了。

这也让我意识到我的编译器警告不会触发隐式转换,因为字节到整数不被视为隐式,因为每当发生隐式转换时我通常都会收到通知。

感谢您的帮助!

【问题讨论】:

  • PLC的API接受什么数据类型?您可以链接到在线文档吗?
  • @djv PLC 接受通过 TCP/IP 发送的字节,它没有直接连接到系统,所以我不知道确切的类型,我可以与它通信并成功接收/发送字节。问题不仅仅是我无法将字节拆分为 8 个布尔值集,我需要知道它试图告诉我什么。 BitArray 类看起来像我需要的,但在这方面它似乎不起作用。
  • 那么要检查一个数字中是否设置了某个位,你可以这样做:Dim nThBitSet As Boolean = (number And n) = n

标签: vb.net byte bitarray


【解决方案1】:

我不确定 BitArray 类是否是您所需要的。无论如何,您不能从 Integer 值创建 BitArray。例如,语句 New BitArray(200) 将创建一个包含 200 个项目的 BitArray,所有项目都设置为 0。 如果您需要发送 16 位值,我认为使用 UShort(也称为 UInt16)数据类型而不是 BitArray 并使用 @djv 建议检查单个位会更简单。要设置位,您必须使用一些“二进制”代数和And 运算符。请记住始终使用无符号数据类型并注意位计数从右开始。

【讨论】:

  • 奇怪的是,我不是从整数值创建它,而是将一个字节传递给构造函数?是否将字节本身解释为数组大小的定义?
  • 就是这样,它隐式使用字节的值作为整数来定义BitArray的长度。谢谢。
【解决方案2】:

不幸的是,BitArray 不允许您转换为 16 位值。

但是,它确实适用于 Byte() 和 Integer()。

所以我们可以将 32 位整数转换为 32 位整数,这应该可以正常工作。

也不清楚您是如何获得原始数据的。作为两个单独的字节,还是作为一个 16 位值?

我将假设一个未分割的 16 位值。

所以我们会有这个代码:

Sub Testset()

    Dim i16 As UInt16
    i16 = 255
    SetBits(i16, 9, False)
    SetBits(i16, 9, True)

    Debug.Print(GetBits(i16, 9).ToString)

End Sub

上面的输出:

00000000 11111111
00000010 11111111
True

而这两个套路分别是:

Public Sub SetBits(ByRef My16Bits As UInt16, MyINdex As Integer, MyValue As Boolean)

    ' toss the passed 16 bits into a 32 bit interger 
    ' we do this, since the conversion routines only work
    ' for built in primitaves ike byte() or integer(). 

    Dim My32(0) As Integer
    My32(0) = My16Bits

    Dim My32Bits As New BitArray(New Integer() {My32(0)})

    My32Bits(MyINdex) = MyValue

    ' now convert bit array back to our 32 bit integer
    My32Bits.CopyTo(My32, 0)

    ' now copy our 32 bit interger back to that 16 bit
    My16Bits = My32(0)

    For i = 15 To 0 Step -1
        Debug.Write(IIf(My32Bits(i), "1", "0"))
        If i = 8 Then Debug.Write(" ")
    Next i
    Debug.Print("")

End Sub

Public Function GetBits(My16Bits As UInt16, MyIndex As Integer) As Boolean

    ' convert Int16 to bit array
    Dim My32(0) As Integer
    My32(0) = My16Bits
    Dim My32Bits As New BitArray(New Integer() {My32(0)})

    Return My32Bits(MyIndex)

End Function

当然可以删除显示值的循环。

如果在您希望位数组以一种或另一种方式转换之前必须调用“很多”次 - 那么您可以将转换为位数组作为一个单独的例程分离出来,并将其传递给获取/设置位例程,然后执行最后一次代码调用以将 bitArrary 转换回 Int16 值。这实际上取决于您期望获取/设置位的次数。所以1或2次,然后上面就可以了。如果您必须始终测试许多位并设置许多位,则在调用之前将值转换为位数组 + 使用两个例程来设置/获取值。因此,与位数组相互转换的代码可以作为单独的代码分离出来。

【讨论】:

  • 数据是在 byte() 数组中获得的,虽然我一直在研究一次处理一组 8 位,因为原始 PLC 消息在第一个字节中,传出通信是在第二个字节。我需要能够在字节数组的两个部分中设置单独的位。我不明白的是: Dim myByteArray() as Byte = {0,200} Dim bitArray_Section1 as BitArray = New BitArray(myByteArray(0)) Dim bitArray_Section2 as BitArray = New BitArray(myByteArray(1)) 为什么长度/计数和字节值一样吗?我没有向构造函数发送原始字节吗?
  • 已解决,Byte 被隐式转换为一个整数用作 BitArray 的长度,发送完整的数组得到了我需要和预期的行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
  • 2015-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多