vb.net - 将 Int 转换为 BCD 字节数组
问题描述
Public Shared Function ToBcd(ByVal pValue As Integer) As Byte()
If pValue < 0 OrElse pValue > 99999999 Then Throw New ArgumentOutOfRangeException("value")
Dim ret As Byte() = New Byte(3) {} 'All bytes are init with 0's
For i As Integer = 0 To 3
ret(i) = CByte(pValue Mod 10)
pValue = Math.Floor(pValue / 10.0)
ret(i) = ret(i) Or CByte((pValue Mod 10) << 4)
pValue = Math.Floor(pValue / 10.0)
If pValue = 0 Then Exit For
Next
Return ret
End Function
这里的技巧是要知道,简单地使用 pValue /= 10 将舍入该值,因此如果参数是“16”,则字节的第一部分将是正确的,但除法的结果将是 2(如1.6 将向上取整)。因此我使用 Math.Floor 方法。
此功能运行良好,我也以相反的顺序使用结果。我已经尝试了几次调整,但我缺少一些东西。
我的问题是:
是否可以将 4 字节扩展到 5 字节?我正在使用它将频率转换为 BCD。一些业余无线电需要 5 个字节。
非常感谢您的回答吉米。
此例程有效,但在这两种情况下,4 字节 + 5 字节我的结果 BCD 是错误的结果没有分数部分
4-Byte 函数总是返回 4 Bytes
5 字节函数
正在根据输入值返回 Nr-of-Bytes。在这种情况下,返回的字节必须插入到另一个 5 字节数组的右字节中?分数部分是个问题。也许它需要一个 2. 函数调用
通过示例尝试使用两个函数获得有效结果:输入值:439700.11
我正在调整前面或后面带有“0”的单个返回值。也许还不够。
频率:Hz x 1000 = Khz * 1000 = MHz * 1000 = GHz 使用 4 字节我们达到 1 GHz - 1. 999999.99
数据 1 数据 2 数据 3 数据 4 100/10Hz 10/1 KHz 1MHz/100KHz 100/10MHz 01 00 97 43 (439700.01 KHz) 50 00 01 07 (7100.50 KHz)
示例:4 字节函数 输入:sfreq = "7000.00" sfreq = Replace(sfreq,".","") 结果:00 70 00 00 这是错误的 输入:sfreq = "70000.00" 结果:00 00 07 00 这是错误的
4字节
Dim sp As String = " " '1 space Dim ret As Byte() = New Byte(3) {} '所有字节均以 0 初始化 Dim hfreq, sStr As String Dim ddouble As Double Dim ssfreq As String = "700000" '我们总是输入小数#####.00
hfreq = ""
ret = ToBcd(Val(ssfreq))
For i As Integer = 0 To 3
sStr = Hex(ret(i))
'just for testing
value = Val("&H" & sStr)
value = Int(value / 16)
MsgBox(value.ToString())
'maybe byte values should adjusted based on the value
'or based on the total value string-Length
If Len(sStr) = 1 Then
If sStr = "0" Then
sStr = sStr + "0"
Else
sStr = "0" & sStr
End If
End If
hfreq = hfreq + sStr & sp 'sp = 1 space
Next
hfreq = Trim(hfreq)
'the 4-Byte answer
'00 70 00 00
'convert to number
Dim counter As Integer = 7
sStr = Replace(hfreq, " ", "")
Dim s1 As String = sStr
sStr = ""
While counter > 0 'read BCD/HEx from right to left
sStr = sStr & Mid$(s1, counter, 2)
counter = counter - 2
If counter = 0 Then counter = 1
End While
value = Val(sStr) ' with the right result the value must be divided / 100
我想使用这 2 个函数,因为我相信它们比我自己的函数更快。10 年前,我写了 2 个用于转换为 BCD 的函数。这两个函数都在读取任何数字并始终返回正确的 BCD 结果。我还使用这个函数来解释转换为 BCD 背后的逻辑。
我不再那么年轻了,但仍在为像我这样的业余无线电爱好者编程。
这里的 2 个函数 sfreq 必须是“7000”或“7000.01”而不是“7.000,01” 你调用:hfreq = SendHexStr(sfreq) 你调用:hfreq = SendHexStr4Byte(sfreq)
Private Sub InsertDec4Byte(ByVal frac)
Dim dd As Double
Dim freqfrac As String = frac
If frac Then
Dim f1, f2, h2 As Double
'even 50 even
dd = Val(freqfrac)
f1 = Val(shex4(1)) '10
f2 = Val(Mid(freqfrac, 1, 2)) '50
If (dd Mod 10 = 0) Then
'0.50
f2 = f2 / 10 '5
h2 = f1 + f2
If h2 < 10 Then
shex4(1) = "0" & h2.ToString() '15
Else
shex4(1) = h2.ToString() '15
End If
Else
'51 - Odd
f2 = Val(Mid(freqfrac, 1, 1)) '5
h2 = f1 + f2 ' 10 + 5
If h2 < 10 Then
shex4(1) = "0" & h2.ToString() '15
Else
shex4(1) = h2.ToString() '15
End If
f2 = Val(Mid(freqfrac, 2, 1)) '1
f2 = f2 * 10
shex4(0) = f2 '10 = 0.01
End If
End If
End Sub
'Hex 4 Byte
Private Function SendHexStr4Byte(ByVal hs)
Dim sStr As String = ""
Dim s1 As String = ""
Dim freq As String = ""
Dim freqfrac As String = ""
Dim ppos As Integer = 0
Dim frac As Boolean = False
'fill the array with Hex '00'
For i As Integer = 0 To 3
shex4(i) = "00"
Next
freq = hs
freq = Replace(freq, ",", ".")
s1 = freq
'copy the fraction part if any - 500.01 - 501.50
ppos = InStr(1, freq, ".", CompareMethod.Text)
If ppos > 0 Then
'copy only the integer part as frequency
s1 = Mid(s1, 1, ppos - 1)
'the fraction part
freqfrac = Mid(freq, ppos + 1, Len(freq) - ppos)
'correct input error
If Len(freqfrac) = 1 Then freqfrac = freqfrac & "0"
If Len(freqfrac) = 0 Then freqfrac = freqfrac & "00"
frac = Not frac 'fraction part = true 0.01..0.99
End If
'final hex-str array position is depending on the freq value
'insert the Hex str into array with inverted order from right to left = the final string
Dim dd As Double = 0
Dim bitpos As Integer = 1 'default Hex-array position
Dim le As Integer = Len(s1)
Dim v1000, v100, vdec As Integer
If le = 3 Then 'value is multiplied by 100
' below 1000 and over 99.99
'00 00 30 00 00 = 300
'00 10 30 00 00 = 301
'00 10 31 00 00 = 311
v100 = Val(Mid(s1, 1, 2))
vdec = Val(Mid(s1, 3, 1))
ElseIf le = 4 Then
'Freq Integer over 999.99 and below 10.000
'9900 - value * 1000
v1000 = Val(Mid(s1, 1, 1))
v100 = Val(Mid(s1, 2, 2))
vdec = Val(Mid(s1, 4, 1))
'freq Integer over 9999.99 and below 100.000,00
ElseIf le = 5 Then
'12345
v1000 = Val(Mid(s1, 1, 2))
v100 = Val(Mid(s1, 3, 2))
vdec = Val(Mid(s1, 5, 1))
End If
If le = 3 Then 'value is multiplied by 10
'310
' hex array position 0 1 2 3 4 | 2 1 0
'we use only the first 3 byte |10 15 31| 00 00 = 310 + 1.50 + 0.01 (10/10)
'first 2
bitpos = 1
shex4(3 - bitpos) = v100.ToString()
bitpos = bitpos + 1
'bitpos start with 3 = byte 1
ElseIf le = 4 Then 'value is multiplied by 1000
shex4(3 - bitpos) = "0" & v1000.ToString() 'is less then 10, below 10.000
bitpos = bitpos + 1
'bitpos start with 2 = byte 2
ElseIf le = 5 Then 'value is multiplied by 10000
shex4(3 - bitpos) = v1000.ToString() 'is > 9999.99 and less then 100.000
bitpos = bitpos + 1
End If
'123
If le = 3 Then
' + vdec
If vdec * 10 > 0 Then _
shex4(3 - bitpos) = vdec * 10.ToString()
If frac Then
InsertDec4Byte(freqfrac)
End If
End If
'1234, 12345
If (le = 4 Or le = 5) Then
' + v100 + vdec
If v100 < 10 Then
sStr = "0" & v100.ToString
Else
sStr = v100.ToString
End If
If v100 > 0 Then _
shex4(3 - bitpos) = sStr.ToString()
'else we do not consider, Hex value = already "00"
bitpos = bitpos + 1
If vdec * 10 > 0 Then _
shex4(3 - bitpos) = vdec * 10.ToString()
If frac Then
InsertDec4Byte(freqfrac)
End If
End If
If bcdinverted Then
sStr = ""
For i As Integer = 3 To 0 Step -1
sStr = sStr & shex4(i).ToString() & " "
Next
Else
sStr = ""
For i As Integer = 0 To 3
sStr = sStr & shex4(i).ToString() & " "
Next
End If
Return sStr
End Function
Private Sub InsertDec(ByVal frac)
Dim dd As Double
Dim freqfrac As String = frac
If frac Then
Dim f1, f2, h2 As Double
'even 50 even
dd = Val(freqfrac)
f1 = Val(shex5(1)) '10
f2 = Val(Mid(freqfrac, 1, 2)) '50
If (dd Mod 10 = 0) Then
'0.50
f2 = f2 / 10 '5
h2 = f1 + f2
If h2 < 10 Then
shex5(1) = "0" & h2.ToString() '15
Else
shex5(1) = h2.ToString() '15
End If
Else
'51 - Odd
f2 = Val(Mid(freqfrac, 1, 1)) '5
h2 = f1 + f2 ' 10 + 5
If h2 < 10 Then
shex5(1) = "0" & h2.ToString() '15
Else
shex5(1) = h2.ToString() '15
End If
f2 = Val(Mid(freqfrac, 2, 1)) '1
f2 = f2 * 10
shex5(0) = f2 '10 = 0.01
End If
End If
End Sub
Private Function SendHexStr(ByVal hs) As String
Dim sStr As String = ""
Dim s1 As String = ""
Dim freq As String = ""
Dim freqfrac As String = ""
Dim ppos As Integer = 0
Dim frac As Boolean = False
'fill the array with Hex '00'
For i As Integer = 0 To 4
shex5(i) = "00"
Next
freq = hs
freq = Replace(freq, ",", ".")
s1 = freq
'copy the fraction part if any - 500.01 - 501.50
ppos = InStr(1, freq, ".", CompareMethod.Text)
If ppos > 0 Then
'copy only the integer part as frequency
s1 = Mid(s1, 1, ppos - 1)
'the fraction part
freqfrac = Mid(freq, ppos + 1, Len(freq) - ppos)
'correct input error
If Len(freqfrac) = 1 Then freqfrac = freqfrac & "0"
If Len(freqfrac) = 0 Then freqfrac = freqfrac & "00"
frac = Not frac 'fraction part = true 0.01..0.99
End If
'final hex-str array position is depending on the freq value
'insert the Hex str into array with inverted order from right to left = the final string
Dim dd As Double = 0
Dim bitpos As Integer = 1 'default Hex-array position
Dim le As Integer = Len(s1)
Dim v100000, v1000, v100, vdec As Integer
If le = 3 Then 'value is multiplied by 100
' below 1000 and over 99.99
'00 00 30 00 00 = 300
'00 10 30 00 00 = 301
'00 10 31 00 00 = 311
v100 = Val(Mid(s1, 1, 2))
vdec = Val(Mid(s1, 3, 1))
ElseIf le = 4 Then
'Freq Integer over 999.99 and below 10.000
'9900 - value * 1000
v1000 = Val(Mid(s1, 1, 1))
v100 = Val(Mid(s1, 2, 2))
vdec = Val(Mid(s1, 4, 1))
'freq Integer over 9999.99 and below 100.000,00
ElseIf le = 5 Then
'12345
v1000 = Val(Mid(s1, 1, 2))
v100 = Val(Mid(s1, 3, 2))
vdec = Val(Mid(s1, 5, 1))
'freq Integer upto > 999.999,99
ElseIf le = 6 Then
'123456
v100000 = Val(Mid(s1, 1, 1))
v1000 = Val(Mid(s1, 2, 2))
v100 = Val(Mid(s1, 4, 2))
vdec = Val(Mid(s1, 6, 1))
'freq Integer upto > 1.999.999,99 stop x ICOM R 8500
ElseIf le = 7 Then
'1234567
v100000 = Val(Mid(s1, 1, 2))
v1000 = Val(Mid(s1, 3, 2))
v100 = Val(Mid(s1, 5, 2))
vdec = Val(Mid(s1, 7, 1))
End If
If le = 3 Then 'value is multiplied by 10
'310
' hex array position 0 1 2 3 4 | 2 1 0
'we use only the first 3 byte |10 15 31| 00 00 = 310 + 1.50 + 0.01 (10/10)
bitpos = 2
shex5(4 - bitpos) = v100.ToString()
bitpos = bitpos + 1
'bitpos start with 3 = byte 1
ElseIf le = 4 Then 'value is multiplied by 1000
shex5(4 - bitpos) = "0" & v1000.ToString() 'is less then 10, below 10.000
bitpos = bitpos + 1
'bitpos start with 2 = byte 2
ElseIf le = 5 Then 'value is multiplied by 10000
shex5(4 - bitpos) = v1000.ToString() 'is > 9999.99 and less then 100.000
bitpos = bitpos + 1
'bitpos start with 2 = byte 2
ElseIf le = 6 Then 'upto 999.999,99
shex5(4) = "0" & v100000.ToString()
'bitpos start with 1 = byte 3
ElseIf le = 7 Then 'upto 1.999.999,99 ICOM R8500 limit
'90 78 56 34 12 = 1,234,567,89
shex5(4) = v100000.ToString()
'bitpos start with 1 = byte 3
End If
'123
If le = 3 Then
' + vdec
If vdec * 10 > 0 Then _
shex5(4 - bitpos) = vdec * 10.ToString()
If frac Then
InsertDec(freqfrac)
End If
End If
'1234, 12345
If (le = 4 Or le = 5) Then
' + v100 + vdec
If v100 < 10 Then
sStr = "0" & v100.ToString
Else
sStr = v100.ToString
End If
If v100 > 0 Then _
shex5(4 - bitpos) = sStr.ToString()
'else we do not consider, Hex value = already "00"
bitpos = bitpos + 1
If vdec * 10 > 0 Then _
shex5(4 - bitpos) = vdec * 10.ToString()
If frac Then
InsertDec(freqfrac)
End If
End If
'123456 + 1234567
If le = 6 Or le = 7 Then
' + v1000 + v100 + vdec
If v1000 > 9 Then
shex5(4 - bitpos) = v1000.ToString()
bitpos = bitpos + 1
Else
shex5(4 - bitpos) = "0" & v1000.ToString()
bitpos = bitpos + 1
End If
If v100 < 10 Then
sStr = "0" & v100.ToString
Else
sStr = v100.ToString
End If
If v100 > 0 Then _
shex5(4 - bitpos) = sStr.ToString()
'else we do not consider, Hex value = already "00"
bitpos = bitpos + 1
If vdec * 10 > 0 Then _
shex5(4 - bitpos) = vdec * 10.ToString()
If frac Then
InsertDec(freqfrac)
End If
End If
sStr = ""
For i As Integer = 0 To 4
sStr = sStr & shex5(i).ToString() & " "
Next
Return sStr
End Function
'------------------------------------------------------------ '--- ------------------------------------------
Jimi提出的使用ToBcd5函数的最终程序
Private Sub HexFreq5Byte(ByVal sfreq)
'Using the ToBcd5 Function proposed by Jimi
'
'This procedure is only returning the correct Number considering the Fraction part
'For a use where always 5 bytes are requested this procedure must be extended
' and the returned bytes must be inserted into a 5-Byte BCD.
' A Radio connected to a Com-Port is always requesting a FIX BCD-Byte number.
' We must transmit and receive Bytes together with other Parameters.
'
' I will have to do that extension
Dim pPos As Integer = 0
Dim frac As Boolean = False
Dim value As Double = 0.0
Dim ssfreq As String = Replace(sfreq, ",", ".")
Dim sStr As String = ""
Dim hfreq As String = ""
Dim sp As String = " " '1 space dividing bytes
'eventual correction
ssfreq = Replace(ssfreq, ",", ".")
Try
'Adjust the Fraction part
'When Fraction (frac) is True the end result must be divided by 100
pPos = InStr(1, ssfreq, ".", CompareMethod.Text)
If pPos > 0 Then
'the fraction part
sStr = Mid(ssfreq, pPos + 1, Len(ssfreq) - pPos)
'correct input error
If Len(sStr) = 1 Then ssfreq = ssfreq & "0"
If Len(sStr) = 0 Then ssfreq = ssfreq & "00"
frac = Not frac 'fraction part = true 0.01..0.99
End If
hfreq = ""
sStr = ""
ssfreq = Replace(sfreq, ".", "")
ssfreq = Replace(sfreq, ",", "")
'get the BCD Bytes
'the function is returning the nr of bytes used as "bcd5bytes"
Dim ret As Byte() = New Byte(bcd5bytes) {}
ret = ToBcd5(Val(ssfreq))
sStr = ""
'Adjust the Byte with "0" in front or behind
For i As Integer = 0 To bcd5bytes - 1
sStr = Hex(ret(i))
If Len(sStr) = 1 Then
If sStr = "0" Then
sStr = sStr + "0"
Else
sStr = "0" & sStr
End If
End If
'insert a space between the bytes if you need it
hfreq = hfreq + sStr & sp 'sp = 1 space
Next
hfreq = Trim(hfreq)
'cut the spaces between the bytes x adding values
hfreq = Replace(hfreq, " ", "")
'Convert to Number
'2 Byte = 4 Digit. Read first the last byte pos 3 + 4
'counter is a double to get out of the 'While loop'.
Dim counter As Double = bcd5bytes * 2 - 1
Dim s1 As String = hfreq
sStr = ""
While counter > 0 'read BCD/Byte from right to left
sStr = sStr & Mid$(s1, counter, 2)
counter = counter - 2
If counter = 0 Then counter = 1
End While
'adjust the return value and the fraction part if any
value = Val(sStr)
If value > 0.0 Then
If frac Then value = value / 100
'The end result
sStr = value.ToString("f2")
End If
Catch ex As Exception
MsgBox("Value exceeding Frequency maximum.")
End Try
结束子
解决方案
推荐阅读
- vue.js - 是否可以在 vuejs 的一个组件中使用多个“模板”元素?
- python - 在 python sqlalchemy 中编写选择请求
- pyspark - 如何从 pyspark 中的多个目录读取数据
- flash - 没有 Adobe Flash Player 的投影仪内嵌入视频
- wolfram-mathematica - ListPlot:数据不是数字或数字对的列表
- javascript - 无法将 Firebase 实时数据库中的数据检索到 Web 应用程序中
- azure-devops - 如何获取谁/何时更改了 vsts 中的工作项类型?
- python - 无法在 CloudML (1.8) 上保存 Keras 检查点错误:ImportError: `save_model` requires h5py
- visual-studio - 独立 IntelliTrace 收集的记录仅显示外部代码
- javascript - 在 three.js 中使用点云创建平面网格