在工作中要对接一些下位机,返回的数据中有些是BCD码(Binary-Coded Decimal),用4位二进制数来表示1位十进制中的0~9这10个数码,是一种二进制的数字编码形式。以下是8421类型的BCD码,还有其它格式的BCD码,但是没怎么遇到过,暂时不表。

十进制8421-BCD码
(M10)D C B A
00 0 0 0
10 0 0 1
20 0 1 0
30 0 1 1
40 1 0 0
50 1 0 1
60 1 1 0
70 1 1 1
81 0 0 0
91 0 0 1

在下位机返回的数据中通常以{0x21, 0x69, 0x10, 0x00, 0x00, 0x02}这样的形式来表示字符串216910000002。所以需要将BCD码转成十进制数值然后再转成字符串。


Visual Studio C代码如下

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#pragma warning(disable:4996)

static uint8_t BCD2DEC(uint8_t bcd)
{
    return (bcd - (bcd >> 4) * 6);
}

static uint8_t DEC2BCD(uint8_t dec)
{
    return (dec + (dec / 10) * 6);
}

int main(void)
{
    int tmp_int;
    char tmp_str[3];

    uint8_t raw_data[] = { 0x21, 0x69, 0x10, 0x01, 0x01, 0x02 };
    int raw_len = sizeof(raw_data) / sizeof(uint8_t);
    char * last_data = malloc(raw_len*2+1);

    for (int i = 0; i < raw_len; i++)
    {
        tmp_int = BCD2DEC(raw_data[i]);
        // 如果是0,直接写入"00"字符
        if (tmp_int == 0)
        {
            strcpy(tmp_str, "00");
            memcpy(last_data + (i * 2), tmp_str, 2);
        }
        // 如果小于10,则在前一位添加"0"字符
        else if (tmp_int < 10)
        {
            sprintf(tmp_str, "%d", tmp_int);
            memcpy(last_data + (i * 2), "0", 1);
            memcpy(last_data + (i * 2)+1, tmp_str, 1);
        }
        else
        {
            sprintf(tmp_str, "%d", tmp_int);
            memcpy(last_data + (i * 2), tmp_str, 2);
        }
    }
    last_data[raw_len*2] = '\0';

    printf("%s\n", last_data);

    free(last_data);

    /*char raw_data[] = "216910010102";
    int raw_len = strlen(raw_data)/2;
    uint8_t * last_data = malloc(raw_len);
    char str[3];
    unsigned int n;
    for (int i = 0; i < raw_len; i++)
    {
        memcpy(&str, &raw_data[i*2], 2);         
        sscanf(str, "%x", &n);
        memcpy(last_data + i, &n, 1);
        printf("0x%02x,",last_data[i]);
    }
    free(last_data);*/

    return 0;
}

使用了上一篇文章中number <---> string相互转换的代码


参考资料:

十进制与BCD码转换的算法

标签: none

评论已关闭