10

float在 Arduino 上发送,doubleint16over serial 的最佳方式是什么?

唯一的Serial.print()发送值作为ASCII编码。但我想将值作为字节发送。Serial.write()接受字节和字节数组,但是将值转换为字节的最佳方法是什么?

我试图将 anint16转换为 an byte*,但没有运气。我也使用了 memcpy,但它使用了许多 CPU 周期。Arduino 使用普通的 C/C++。这是一个ATmega328微控制器。

4

9 回答 9

10

嗯。这个怎么样:

void send_float (float arg)
{
  // get access to the float as a byte-array:
  byte * data = (byte *) &arg; 

  // write the data to the serial
  Serial.write (data, sizeof (arg));
}
于 2010-07-17T09:49:14.427 回答
9

是的,要发送这些数字,您必须先将它们转换为ASCII字符串。如果您正在使用 C,sprintf()则 IMO 是进行此转换的最方便的方法:

[后来添加:啊啊啊!我忘记了ints/ longs,函数的输入参数想要无符号。对于传递给的格式字符串也是如此sprintf()。所以我在下面改了。很抱歉我的糟糕疏忽,这将是一个很难找到的错误。另外,ulong让它更通用一点。]

char *
int2str( unsigned long num ) {
    static char retnum[21];       // Enough for 20 digits plus NUL from a 64-bit uint.
    sprintf( retnum, "%ul", num );
    return retnum;
}

浮点数和双打也类似。进行转换的代码是事先知道的。必须告诉它 - 它正在转换什么样的实体,所以你最终可能会得到函数char *float2str( float float_num)char *dbl2str( double dblnum).

您将从转换中得到一个以 NUL 结尾的左调整(没有前导空格或零)字符串。

您可以随心所欲地进行转换;这些功能只是说明。

于 2010-07-17T10:01:58.200 回答
3

使用Firmata协议。引用:

Firmata 是一种通用协议,用于通过主机上的软件与微控制器进行通信。它旨在与任何主机计算机软件包一起使用。现在有许多语言的匹配对象。为其他软件添加对象以使用此协议很容易。基本上,这个固件建立了一个协议,用于从主机软件与 Arduino 对话。目的是让人们通过主机上的软件完全控制 Arduino。

于 2010-09-07T07:30:44.173 回答
2

您需要查找的行话是“序列化”。

这是串行连接上的一个有趣问题,它可能对哪些字符可以端到端进行限制,并且可能无法每个字符传递 8 位。

对某些字符代码的限制相当普遍。这里有一些现成的:

  • 如果使用软件流控制,则通常控制字符 DC1 和 DC3(Ctrl-Q 和 Ctrl-S,有时也称为 XON 和 XOFF)不能作为数据传输,因为它们被发送以启动和停止发送方电缆的末端。

  • 在某些设备上,NUL 和/或 DEL 字符(0x00 和 0x7F)可能会简单地从接收器的 FIFO 中消失。

  • 如果接收方是 Unix tty,并且未正确设置 termio 模式,则字符 Ctrl-D(EOT 或 0x04)会导致 tty 驱动程序向打开 tty 的进程发出文件结束信号。

串行连接通常可配置字节宽度和可能包含的奇偶校验位。某些连接需要使用带有奇偶校验的 7 位字节,而不是 8 位字节。甚至可以连接到(非常旧的)旧硬件来配置许多 5 位和 6 位字节的串行端口。如果每个字节可用的位少于 8 位,则需要更复杂的协议来处理二进制数据。

ASCII85是一种流行的技术,用于处理 7 位数据和控制字符的限制。这是仅使用 85 个精心挑选的 ASCII 字符代码重写二进制数据的惯例。

此外,您当然必须担心发送方和接收方之间的字节顺序。您可能还需要担心浮点格式,因为并非每个系统都使用 IEEE-754 浮点。

最重要的是,通常选择纯 ASCII 协议是更好的答案。它的优点是它可以被人类理解,并且更能抵抗串行连接的问题。除非您发送大量浮点数据,否则表示的低效可能会因易于实施而被抵消。

只要对你接受的东西保持自由,对你发出的东西保持保守。

于 2010-09-07T07:55:44.360 回答
1

这很有效。使用 Serial.println()函数

void setup() {
  Serial.begin(9600);

}

void loop() {
  float x = 23.45585888;
  Serial.println(x, 10);
  delay(1000);
}

这是输出:

在此处输入图像描述

于 2019-10-12T10:36:46.453 回答
0

大小重要吗?如果是这样,您可以使用 ASCII85 将每个 32 位组编码为 5 个 ASCII 字符,请参阅http://en.wikipedia.org/wiki/Ascii85

于 2010-07-17T16:39:12.690 回答
0

也许这是将浮点数转换为字节并将字节转换为浮点数的最佳方法,-Hamid Reza。

int breakDown(int index, unsigned char outbox[], float member)
{
  unsigned long d = *(unsigned long *)&member;

  outbox[index] = d & 0x00FF;
  index++;

  outbox[index] = (d & 0xFF00) >> 8;
  index++;

  outbox[index] = (d & 0xFF0000) >> 16;
  index++;

  outbox[index] = (d & 0xFF000000) >> 24;
  index++;
  return index;
}


float buildUp(int index, unsigned char outbox[])
{
  unsigned long d;

  d =  (outbox[index+3] << 24) | (outbox[index+2] << 16)
    | (outbox[index+1] << 8) | (outbox[index]);
  float member = *(float *)&d;
  return member;
}

问候。`

于 2014-04-23T11:13:36.513 回答
0

结构和工会解决了这个问题。使用与结构匹配的字节大小联合的打包结构。将指向结构和联合的指针重叠(或在结构中添加联合)。使用 Serial.write 发送流。在接收端有一个匹配的结构/联合。只要字节顺序匹配没有问题,否则您可以使用“C”hto(s..l) 函数解包。添加“标题”信息以解码不同的结构/联合。

于 2017-10-09T13:08:33.333 回答
0

对于 Arduino IDE:

float buildUp(int index, unsigned char outbox[])
{
  unsigned long d;
 d = (long(outbox[index +3]) << 24)  |   \
     (long(outbox[index +2]) << 16) |   \
     (long(outbox[index +1]) << 8)  |   \
     (long(outbox[index]));
 float member = *(float *)&d;
 return member;
}

否则无法正常工作。

于 2020-12-03T20:54:04.210 回答