[原创]PB中读取地磅BCD解码

PB 中读取地磅 BCD 解码

我在《 PB 中读取地磅称量数据》中简述了 PB 读取地磅操作过程,有网友反映对 BCD 码的读取及解码不是很清楚。在此,特追加此部分内容来解释 BCD 解码过程。

认识 BCD 编码

BCD 编码是一种数字压缩存储编码,大家都知道一个字节有 8 个位,而数字 0 到 9 最多只需要使用 4 个位,如果用一个字节来存储一个数字相对就会有一定的浪费,尤其是在传输过程中,由此人们就想出了压缩的办法,于是 BCD 编码就产生了。

BCD 编码将一个字节的 8 个位拆分成高 4 位和低 4 位两个部分,也就是说一个字节能存储两个数字。所以 BCD 的编码过程就是将数字压缩的过程,将两个字节的数字压缩成一个字节。反之,解码就是把一个字节的数字拆分为两个数字单独存放(大部分的处理都是按字节处理的)。

示例:

编码过程,将数字 69 进行 BCD 编码(注: BCD 编码低位在前,后面将不再注释)。

1. 将 6 , 9 分别转换成二进制表示: 6 ( 00000110 ) 9 ( 00001001 ),大家可以看到,最大的数字 9 也只要 4 个位,在传输过程中白白浪费了 4 个位;

2. 将 69 合并为一个字节,分别取 6 , 9 二进制编码的低 4 位,按照低位在前的原则,将 9 的低四位放前面 6 的低四位放后面得出新的字节二进制编码是 10010110 ;

3. 完成编码过程, 69 的 BCD 编码结果为 10010110 。

解码过程:将 69 的 BCD 码 10010110 进行解码。

1. 将 10010110 的高 4 位与低 4 位拆分开,得到两个二进制数 1001 和 0110 ;

2. 分别将 1001 和 0110 的前面补充 4 位 0000 得到两个 8 位的二进制数 00001001 , 00000110 ;

3. 因为编码时低位在前,所以我们将两个二进制数编排顺序为 00000110 000010001 ;

4. 将二进制数转换为十进制得出解码结果为 69 (正确解码)。

PB 中如何对 BCD 码进行解码

大家知道在 PB 中有二进制类型的变量 blob ,但要无法按位操作,那么我们如何进行 BCD 编码的数字进行解码呢?

我想大家都会不约而同的想到 ASCII 码,没错,就是她。 ASCII 就是数字和字符在计算机中存储的的值,她在 PB 中给我们呈现的并不是 01 组成的二进制数而是十进制数值。

BCD 解码需要将一个字节的高 4 位和低 4 位进行拆分,那么我们怎么来使用十进制的 ASCII 编码做到呢?

因为 PB 不提供位运算所以我们只能自己写函数来做些简单的处理了,那又如何处理呢?

方法一:我们写函数将十进制的 ASCII (单字节)转化为二进制的字符串,当然,如此一来你还要写一个将二进制字符串转换为 10 进制数字的函数,有兴趣的朋友可以尝试一下。

方法二:在我上次写的内容中已经提到了,就是借助十六进制来完成转换。大家仔细研究不难发现十六进制表示等同于将一个字节的内容高 4 位和低 4 位分别转换为十进制,如果不信你可以自己验算一下。这样我们就只需要写一个转换函数了,将十进制数转换为十六进制字符串。转换后将十六串的两个字符位置对换(因为编码的时候低位在前),然后直接将这个串强制转换为数值型就得到了解码后的数值。(注:后面有一转换函数是网上一网友所写)

有了解码方法我们在读 BCD 码的地磅数据的时候就很容易处理了,因为我上次写过处理过程这里我只简单描述一下:

1. 用二进制类型 blob 将串口(现在有的用 usb 口)的数据读出来;

2. 将 blob 强制转换为 string ,这样就把二进制流按 8 位存储格式编码了,也就是说 BCD 码在这个 string 中,不过是压缩格式;

3. 将 string 的每个字节都分割开来,然后分别译为 ASCII 编码, PB 中有函数 ASC ;

4. 根据具体设备出厂参数识别 string 中状态位,校验位,数字位等的位置;

5. 找到数字位进行 BCD 解码,方法如上;

6. 完成解码,得到称量数据。

附件:

//=============================================================================

// Function: of_Hex()

//-----------------------------------------------------------------------------

// Description: 转换 integer 到 16 进制字符串

//-----------------------------------------------------------------------------

// Aagument: Integer pssl

//-----------------------------------------------------------------------------

// Return: string 16 进制字符串

//-----------------------------------------------------------------------------

// Log: excerpt by tubx 2004.03.10

//=============================================================================

string vs,vstmp,vsret

integer vi1,vilen,i,vimod,viy,visl

vilen=Len(String(pssl))

char vc_he[6]

vimod=Mod(pssl,16)

visl=pssl

If vimod>=0 Then

vstmp=String(vimod)

If vstmp='10' Then vstmp='A'

If vstmp='11' Then vstmp='B'

If vstmp='12' Then vstmp='C'

If vstmp='13' Then vstmp='D'

If vstmp='14' Then vstmp='E'

If vstmp='15' Then vstmp='F'

vc_he[1]=vstmp

End If

For i =1 To vilen + 1

viy=Truncate(visl/16,0)

If viy>0 Then

vstmp=String(viy)

If vstmp='10' Then vstmp='A'

If vstmp='11' Then vstmp='B'

If vstmp='12' Then vstmp='C'

If vstmp='13' Then vstmp='D'

If vstmp='14' Then vstmp='E'

If vstmp='15' Then vstmp='F'

vc_he[i+1]=vstmp

End If

If viy=0 Then exit

visl=viy

Next

vsret=''

If IsNull(vc_he[6]) Or vc_he[6]='' Then

vsret=vsret

Else

vsret=vsret+vc_he[6]

End If

If IsNull(vc_he[5]) Or vc_he[5]='' Then

vsret=vsret

Else

vsret=vsret+vc_he[5]

End If

If IsNull(vc_he[4]) Or vc_he[4]='' Then

vsret=vsret

Else

vsret=vsret+vc_he[4]

End If

If IsNull(vc_he[3]) Or vc_he[3]='' Then

vsret=vsret

Else

vsret=vsret+vc_he[3]

End If

If IsNull(vc_he[2]) Or vc_he[2]='' Then

vsret=vsret

Else

vsret=vsret+vc_he[2]

End If

If IsNull(vc_he[1]) Or vc_he[1]='' Then

vsret=vsret

Else

vsret=vsret+vc_he[1]

End If

Return vsret

Published At
Categories with 数据库类
Tagged with
comments powered by Disqus