float
在 Arduino 上发送,double
和int16
over serial 的最佳方式是什么?
唯一的Serial.print()
发送值作为ASCII编码。但我想将值作为字节发送。Serial.write()
接受字节和字节数组,但是将值转换为字节的最佳方法是什么?
我试图将 anint16
转换为 an byte*
,但没有运气。我也使用了 memcpy,但它使用了许多 CPU 周期。Arduino 使用普通的 C/C++。这是一个ATmega328微控制器。
嗯。这个怎么样:
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));
}
是的,要发送这些数字,您必须先将它们转换为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 结尾的左调整(没有前导空格或零)字符串。
您可以随心所欲地进行转换;这些功能只是说明。
使用Firmata协议。引用:
Firmata 是一种通用协议,用于通过主机上的软件与微控制器进行通信。它旨在与任何主机计算机软件包一起使用。现在有许多语言的匹配对象。为其他软件添加对象以使用此协议很容易。基本上,这个固件建立了一个协议,用于从主机软件与 Arduino 对话。目的是让人们通过主机上的软件完全控制 Arduino。
您需要查找的行话是“序列化”。
这是串行连接上的一个有趣问题,它可能对哪些字符可以端到端进行限制,并且可能无法每个字符传递 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 协议是更好的答案。它的优点是它可以被人类理解,并且更能抵抗串行连接的问题。除非您发送大量浮点数据,否则表示的低效可能会因易于实施而被抵消。
只要对你接受的东西保持自由,对你发出的东西保持保守。
大小重要吗?如果是这样,您可以使用 ASCII85 将每个 32 位组编码为 5 个 ASCII 字符,请参阅http://en.wikipedia.org/wiki/Ascii85。
也许这是将浮点数转换为字节并将字节转换为浮点数的最佳方法,-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;
}
问候。`
结构和工会解决了这个问题。使用与结构匹配的字节大小联合的打包结构。将指向结构和联合的指针重叠(或在结构中添加联合)。使用 Serial.write 发送流。在接收端有一个匹配的结构/联合。只要字节顺序匹配没有问题,否则您可以使用“C”hto(s..l) 函数解包。添加“标题”信息以解码不同的结构/联合。
对于 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;
}
否则无法正常工作。