二進化十進数(BCD)は、コンピューターにおける数値の表現方法の1種です。2進数の4桁(4ビット)で0~9の10個の数だけを扱います。たとえば10進数の「1234」を16進数で表したときに「1234h」となるのがBCDです。16進数で表したときに、10進数と同じ表現になるのが特徴です。
BCDは組み込みシステムでよく出番のある、RTCや7セグで用いられています。
RTC (Real Time Clock)
リアルタイムクロック(RTC)は、電子機器のカレンダー(年月日)や時間を管理するICです。単に日時の管理のみでなく、アラームやタイマー機能を内包しているのが一般的…
目次
BCD対応表
10進数とBCDの関係は下記表のとおりです。
10進数 | (通常の)16進数 | BCD(16進数表記) |
---|---|---|
0 | 00 | 00 |
1 | 01 | 01 |
2 | 02 | 02 |
3 | 03 | 03 |
4 | 04 | 04 |
5 | 05 | 05 |
6 | 06 | 06 |
7 | 07 | 07 |
8 | 08 | 08 |
9 | 09 | 09 |
10 | 0A | 10 |
11 | 0B | 11 |
12 | 0C | 12 |
13 | 0D | 13 |
14 | 0E | 14 |
15 | 0F | 15 |
サンプルコード
[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);
}
CppUTestでC/C++コードをテストする
CppUTestは、単体テストを自動化するためのフリーソフトウェアです。 C/C++は非常に自由度が高く何でもできる反面、ちょっとしたミスですぐに不具合を起こします。この…
変則仕様
これは何の規格でもなく、どこかの大手企業が考えたものでなく、ただ私が勝手に使用している変則仕様です。BCDでは使用しないA~Fを使用して、指数形式(+0.00000e+00)の文字列をBCD形式で保存できるようにします。これにより文字列のまま保存するのに比べて、メモリー使用量が半分で済むのです。
文字 | 16進数 |
---|---|
␣(空白) | A |
+ | B |
e | C |
– | 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
コメント