BCD(卡西欧串行接口)中的编码数字

时间:2018-08-20 08:45:01

标签: c++ encoding arduino bcd

我正在尝试创建一个与Arduino通过其串行端口与Casio fx-9750计算器对话的设备。我已经弄清楚了如何接收值和对BCD进行解码,但是我仍然坚持如何从浮点数(回传)中创建所需的值。

计算器发送一个数据包,该数据包具有一个指数值,几个数据值以及一个字节,其中包含有关负性,虚部等信息。每个数据值都相当于前一个值的百分之一,因此第一个是10s,下一个0.1s,下一个0.001s,依此类推。这种情况一直持续到0.0000000000001s,尽管这超出了我真正需要的范围,所以准确度对我来说并不重要。我的接收程序的输出如下所示:

Exponent: 1
10s: 1
0.1s: 23
0.001s: 40

代表12.34。
我得出的一般方程是:(让a = 10s,b = 0.1s,e =指数等)

((a*10)+(b*0.1)+(c*0.001))*10^(E-1)

如果指数更改为两个:

Exponent: 2
10s: 1
0.1s: 23
0.001s: 40

这代表123.4

大概使用这种每次下降百分之一的方法,因为它们可以在BCD的每个字节中存储两位数字,因此当每一行存储为一个字节时,让每一行都具有两位数字是最有效的。

我想出了一个方程,该方程可以通过计算小数点前的位数并减去两位来计算指数,但是这似乎很麻烦,因为它涉及字符串。我认为,如果可能的话,纯数学解决方案会更优雅。

从正常数字(例如123.4)转换为这种排列方式最快又最简单的方法是什么? 以Arduino语言提供的解决方案将不胜感激,但是对所需数学过程的任何见解都将得到同等重视。

编辑有关彩车的信息: 我应该澄清-我将在程序的其他部分处理浮点数,并希望我输入的值与任何大小的数字兼容(如前所述)。将它们乘以int或将其强制转换为其他数据类型都没有问题。

1 个答案:

答案 0 :(得分:0)

哈哈,真有趣!

#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <float.h>

struct num_s {
  // exponent
  int e;

  // v[0] is *10
  // v[1] is *0.01
  // v[2] is *0.0001
  // and so on...
  // to increase precision increase array count
  int v[6];
};

#define NUM_VALSCNT (sizeof(((struct num_s*)0)->v)/sizeof(((struct num_s*)0)->v[0]))

// creates num_s object from a double
struct num_s num_create(double v) {
  struct num_s t;

  // find exponent so that v <= 10
  t.e = 0;
  while (fabs(v) >= 10.0) {
    ++t.e;
    v /= 10.0;
  }

  // for each output number get the integral part of number
  // then multiply the rest by 100 and continue
  for (size_t i = 0; i < sizeof(t.v) / sizeof(t.v[0]); ++i) {
    const double tmp = fmod(v, 1.0);
    t.v[i] = v - tmp;
    v = tmp * 100;
  }
  return t;
}

// converts back from num object to double
double num_get(struct num_s t) {
  double denom = 10;
  double ret = 0;
  for (size_t i = 0; i < sizeof(t.v) / sizeof(t.v[0]); ++i) {
    ret += denom * t.v[i];
    denom /= 100;
  }
  return ret * pow(10, t.e - 1);
}

void num_println(struct num_s t) {
  printf("%f =", num_get(t));
  for (size_t i = 0; i < sizeof(t.v) / sizeof(t.v[0]); ++i) {
    printf(" %d", t.v[i]);
  }
  printf(" %d\n", t.e);
}

// returns the precision of numbers
// the smallest number we can represent in num object
double num_precision(void) {
  return pow(0.1, (NUM_VALSCNT - 1) * 2) * 10;
}

int num_unittests(void) {
  const double tests[][3] = {
    { 123.49, 123.5, 123.51, }
  };
  for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
    const double tmp = num_get(num_create(tests[i][1]));
    if (!(tests[i][0] <= tmp && tmp <= tests[i][2])) {
      return i + 1;
    }
  }
  return 0;
}

int main() {
  num_println(num_create(12.3456789));
  num_println(num_create(123.5));
  num_println(num_create(12.35));
  printf("%d\n", num_unittests());
  return 0;
}