I needed to convert some numbers received from a PLC from their original packed BCD format to binary (hex) format. The numbers to convert are split into two 16-bit halves, and need to be converted into one 32-bit number.

(Packed BCD values contain two digits for every byte.)

There is a method that exists that will convert numbers from BCD into a true hex number, by using string formatting, but this is relatively expensive in terms of performance and I required the best performance possible.

So, I came up with this function:

1: /// <summary>

2: /// Convert two PLC words in BCD format (forming 8 digit number) into single binary integer.

3: /// e.g. If Lower = 0x5678 and Upper = 0x1234, then Return is 12345678 decimal, or 0xbc614e.

4: /// </summary>

5: /// <param name="lower">Least significant 16 bits.</param>

6: /// <param name="upper">Most significant 16 bits.</param>

7: /// <returns>32 bit unsigned integer.</returns>

8: /// <remarks>If the parameters supplied are invalid, returns zero.</remarks>

9: private uint BCD2ToBin(uint lower, uint upper)

` 10: {`

11: uint binVal = 0;

` 12: `

13: if ((lower | upper) != 0)

` 14: {`

15: int shift = 0;

16: uint multiplier = 1;

17: uint bcdVal = (upper << 16) | lower;

` 18: `

19: for (int i = 0; i < 8; i++)

` 20: {`

21: uint digit = (bcdVal >> shift) & 0xf;

` 22: `

23: if (digit > 9)

` 24: {`

` 25: binVal = 0;`

26: break;

` 27: }`

28: else

` 29: {`

` 30: binVal += digit * multiplier;`

` 31: shift += 4;`

` 32: multiplier *= 10;`

` 33: }`

` 34: }`

` 35: }`

` 36: `

37: return binVal;

` 38: }`

The function takes in two unsigned itegers that hold each of the 16-bit weighted BCD values, and returns a 32-bit unsigned integer.

It is important to note that the return is an unsigned integer, as this allows BCD values up to 0x99999999 to be converted correctly.

I have also taken the approach of returning zero if any of the values supplied are incorrect, i.e. contain an invalid digit. (BCD values can only contain digits ranging between 0 and 9, and not A to F.)

Of course, it may be desirable to return a different value, or to throw an exception if the parameters supplied are invalid, but for my purposes, returning a zero was sufficient.

This method proved to be around four to five times quicker than by using the string format method.

## 0 comments:

Post a Comment