BCD (Binary-coded decimal)

二進化十進数(BCD)は、コンピューターにおける数値の表現方法の1種です。2進数の4桁(4ビット)で0~9の10個の数だけを扱います。たとえば10進数の「1234」を16進数で表したときに「1234h」となるのがBCDです。16進数で表したときに、10進数と同じ表現になるのが特徴です。

BCDは組み込みシステムでよく出番のある、RTCや7セグで用いられています。

目次

BCD対応表

10進数とBCDの関係は下記表のとおりです。

10進数(通常の)16進数BCD(16進数表記)
00000
10101
20202
30303
40404
50505
60606
70707
80808
90909
100A10
110B11
120C12
130D13
140E14
150F15

サンプルコード

[bcd.c]

/**
 * @file bcd.c
 * @brief BCD処理
 */

//------------------------------------------------------------------------------
// include
//------------------------------------------------------------------------------
#include "bcd.h"

//------------------------------------------------------------------------------
// private variable
//------------------------------------------------------------------------------
static const uint8_t m_hex_high[10] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90};

/** ----------------------------------------------------------------------------
 * @brief BCDからバイナリーに変換
 *
 * @param [in] bcd : BCD
 * @param len : BCDバイト長
 * @return バイナリー
 */
uint32_t BcdToBin(const uint8_t bcd[], uint8_t len)
{
  uint32_t bin = 0;

  for (uint8_t i = 0; i < len; i++) {
    bin *= 100;
    bin += BcdToBin1(bcd[i]);
  }

  return bin;
}

/** ----------------------------------------------------------------------------
 * @brief BCDからバイナリーに変換 (1バイト)
 *
 * @param bcd : BCD
 * @return バイナリー
 */
uint8_t BcdToBin1(uint8_t bcd)
{
  uint8_t high, low;
  uint8_t bin;

  high = bcd >> 4;
  low  = bcd & 0x0F;
  bin  = high * 10 + low;

  return bin;
}

/** ----------------------------------------------------------------------------
 * @brief バイナリーからBCDに変換
 *
 * @param bin : バイナリー
 * @param [out] bcd : BCD
 * @param len : BCDバイト長
 */
void BinToBcd(uint32_t bin, uint8_t bcd[], uint8_t len)
{
  uint8_t high, low;

  for (uint8_t i = 0; i < len; i++) {
    low = bin % 10;
    bin /= 10;
    high = bin % 10;
    bin /= 10;
    bcd[len - i - 1] = m_hex_high[high] | low;
  }
}

/** ----------------------------------------------------------------------------
 * @brief バイナリーからBCDに変換 (1バイト)
 *
 * @param bin : バイナリー [0-99]
 * @return BCD (1バイト)
 */
uint8_t BinToBcd1(uint8_t bin)
{
  uint8_t bcd;

  if (bin < 10) {
    bcd = bin;
  } else if (bin < 20) {
    bcd = bin + 6;
  } else if (bin < 30) {
    bcd = bin + 12;
  } else if (bin < 40) {
    bcd = bin + 18;
  } else if (bin < 50) {
    bcd = bin + 24;
  } else if (bin < 60) {
    bcd = bin + 30;
  } else if (bin < 70) {
    bcd = bin + 36;
  } else if (bin < 80) {
    bcd = bin + 42;
  } else if (bin < 90) {
    bcd = bin + 48;
  } else if (bin < 100) {
    bcd = bin + 54;
  } else {
    bcd = 0xff;
  }

  return bcd;
}

[bcd.h]

#ifndef BCDH
#define BCDH

#ifdef __cplusplus
extern "C" {
#endif

//------------------------------------------------------------------------------
// include
//------------------------------------------------------------------------------
#include <stddef.h>
#include <stdint.h>

//------------------------------------------------------------------------------
// function
//------------------------------------------------------------------------------
uint32_t BcdToBin(const uint8_t bcd[], uint8_t len);
uint8_t  BcdToBin1(uint8_t bcd);
void     BinToBcd(uint32_t bin, uint8_t bcd[], uint8_t len);
uint8_t  BinToBcd1(uint8_t bin);

#ifdef __cplusplus
}
#endif

#endif

サンプルコードの使用例

使用例代わりに、CppUTestによるテストコードを掲載しておきます。

#include "CppUTest/TestHarness.h"

#include "bcd.h"

// clang-format off
TEST_GROUP(bcd){
  TEST_SETUP(){
  }

  TEST_TEARDOWN(){
  }
};
// clang-format on

TEST(bcd, Test_BcdToBin)
{
  uint8_t  bcd[4];
  uint32_t bin;

  bcd[0] = 0x12;
  bcd[1] = 0x34;
  bcd[2] = 0x56;
  bcd[3] = 0x78;

  bin = BcdToBin(bcd, 1);
  UNSIGNED_LONGS_EQUAL(bin, 12);

  bin = BcdToBin(bcd, 2);
  UNSIGNED_LONGS_EQUAL(bin, 1234);

  bin = BcdToBin(bcd, 3);
  UNSIGNED_LONGS_EQUAL(bin, 123456);

  bin = BcdToBin(bcd, 4);
  UNSIGNED_LONGS_EQUAL(bin, 12345678);
}

TEST(bcd, Test_BcdToBin1)
{
  uint8_t bin;

  bin = BcdToBin1(0x00);
  UNSIGNED_LONGS_EQUAL(bin, 0);

  bin = BcdToBin1(0x12);
  UNSIGNED_LONGS_EQUAL(bin, 12);

  bin = BcdToBin1(0x34);
  UNSIGNED_LONGS_EQUAL(bin, 34);

  bin = BcdToBin1(0x56);
  UNSIGNED_LONGS_EQUAL(bin, 56);

  bin = BcdToBin1(0x78);
  UNSIGNED_LONGS_EQUAL(bin, 78);

  bin = BcdToBin1(0x99);
  UNSIGNED_LONGS_EQUAL(bin, 99);
}

TEST(bcd, Test_BinToBcd)
{
  uint8_t bcd[4];

  BinToBcd(1234, bcd, 4);
  UNSIGNED_LONGS_EQUAL(bcd[0], 0x00);
  UNSIGNED_LONGS_EQUAL(bcd[1], 0x00);
  UNSIGNED_LONGS_EQUAL(bcd[2], 0x12);
  UNSIGNED_LONGS_EQUAL(bcd[3], 0x34);
}

TEST(bcd, Test_BinToBcd1)
{
  uint8_t bcd;

  bcd = BinToBcd1(0);
  UNSIGNED_LONGS_EQUAL(bcd, 0x00);

  bcd = BinToBcd1(1);
  UNSIGNED_LONGS_EQUAL(bcd, 0x01);

  bcd = BinToBcd1(12);
  UNSIGNED_LONGS_EQUAL(bcd, 0x12);

  bcd = BinToBcd1(34);
  UNSIGNED_LONGS_EQUAL(bcd, 0x34);

  bcd = BinToBcd1(99);
  UNSIGNED_LONGS_EQUAL(bcd, 0x99);

  bcd = BinToBcd1(100);
  UNSIGNED_LONGS_EQUAL(bcd, 0xff);
}

変則仕様

これは何の規格でもなく、どこかの大手企業が考えたものでなく、ただ私が勝手に使用している変則仕様です。BCDでは使用しないA~Fを使用して、指数形式(+0.00000e+00)の文字列をBCD形式で保存できるようにします。これにより文字列のまま保存するのに比べて、メモリー使用量が半分で済むのです。

文字16進数
␣(空白)A
+B
eC
D
.E
NULL(終わり)F

[例]

+1.23456e-12  >>  B1 E2 34 56 CD 12
    1234.567  >>  AA AA 12 34 E5 67
-1.23456      >>  D1 E2 34 56 FF FF

コメント

コメントする

CAPTCHA


目次