VB net Accessing individual bits of a byte // ByteArray 长度和计数是否等于字节值?

VBnet Accessing individual bits of a byte // BitArray length & count are equal to the byte value?

我正在尝试与 accepts/sends 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-equivalent :

 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

convert 函数,我假设它的长度为 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

我想完成的事情:

Receive a byte (1-0-0-1-0-0-1-0)

Enable the booleans in the program by reading the individual bits: Check1, Check4, Check7

Set the individual bits of the output Byte starting at 0-0-0-0-0-0-0-0

Turn on 5 : 0-0-0-0-1-0-0-0

Turn on 2 : 0-1-0-0-1-0-0-0

Send Byte

我是否完全滥用了 BitArray class?我究竟做错了什么? 什么可以让我在没有 运行 的情况下更改单个位值进入这种混乱状态?

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

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

提前致谢,


已解决:

我没有意识到将非数组字节发送到 BitArray 会隐式将其转换为整数,因此它创建了一个 BitArray,它具有length/count 等于字节 的值。现在完全有道理了。

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

感谢您的帮助!

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

不幸的是,BitArray 不允许您转换 to/from 16 位值。

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

因此我们可以将 from/to 转换为 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

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

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