使用 uint8 数组发送大于 255 的整数
sending integer greater than 255 with uint8 array
我想使用 uint8 数组通过蓝牙从移动设备向 Arduino 发送大于 255 的整数。
由于我使用的 BLE 模块不接受 Uint16Array,因此我只能使用 Uint8 数组。
我的应用代码:
var data = new Uint8Array(3);
data[0]= 1;
data[1]= 123;
data[2]= 555;
ble.writeWithoutResponse(app.connectedPeripheral.id, SERVICE_UUID, WRITE_UUID, data.buffer, success, failure);
我的设备特定代码:
void SimbleeBLE_onReceive(char *data, int len) {
Serial.print(data[0]); // prints 1
Serial.print(data[1]); // prints 123
Serial.print(data[2]); // failed to print 555
}
由于 uint8 只允许最大为 255 的整数,我如何发送大于 255 的整数?
在发送端和接收端对数据进行某种形式的缩放,使其保持在 0 到 255 的范围内。例如除法和乘法,因此数据发送到 255 以下,然后在接收端按比例放大。
另一种方法,如果您知道数据的高低范围,则可以使用 Arduino 映射功能。
y = map(mapped value, actual lo, actual hi, mapped lo, mapped hi)
如果您不知道完整范围,可以使用 constrain()
函数。
你必须拆分它。您已经知道(或者您应该知道)int16 有 16 位(所以需要两个字节来存储它)。
现在关于字节序的非常小的题外话。对于字节序,您的意思是存储时字节的顺序。例如,如果您的值为 0x1234,则可以将其存储为 0x12 0x34(大端)或 0x34 0x12(小端)。
我不知道你用的是什么语言,所以...通常在 C++ 中你会这样做:
const int datalen = 3;
uint16_t data[datalen];
data[0]= 1;
data[1]= 123;
data[2]= 555;
uint8_t sendingData[] = new uint8_t[datalen * sizeof(uint16_t)];
for (int i = 0; i < datalen; i++)
{
sendingData[i * 2] = (data[i] >> 8) & 0xFF;
sendingData[i * 2 + 1] = data[i] & 0xFF;
}
functionToSendData(sendingData, datalen * sizeof(uint16_t));
这以大端格式发送。如果你更喜欢小端,写
sendingData[i * 2] = data[i] & 0xFF;
sendingData[i * 2 + 1] = (data[i] >> 8) & 0xFF;
更简单的版本可以是
const int datalen = 3;
uint16_t data[datalen];
data[0]= 1;
data[1]= 123;
data[2]= 555;
functionToSendData((uint8_t*)data, datalen * sizeof(uint16_t));
在第一种情况下,您知道传输的字节序(大小取决于您的编码方式),在第二种情况下,它取决于架构 and/or 编译器。
在JavaScript中你可以使用这个:
var sendingData = new Uint8Array(data.buffer)
然后发送这个新数组。学分转到 this answer
当你收到它时,你必须做这三件事之一来转换它
// Data is big endian
void SimbleeBLE_onReceive(char *receivedData, int len) {
uint16_t data[] = new uint16_t[len/2];
for (int i = 0; i < len/2; i++)
data = (((uint16_t)receivedData[i * 2]) << 8) + receivedData[i * 2 + 1];
Serial.print(data[0]);
Serial.print(data[1]);
Serial.print(data[2]);
}
// Data is little endian
void SimbleeBLE_onReceive(char *receivedData, int len) {
uint16_t data[] = new uint16_t[len/2];
for (int i = 0; i < len/2; i++)
data = receivedData[i * 2] + (((uint16_t)receivedData[i * 2 + 1]) << 8);
Serial.print(data[0]);
Serial.print(data[1]);
Serial.print(data[2]);
}
// Trust the compiler
void SimbleeBLE_onReceive(char *receivedData, int len) {
uint16_t *data = receivedData;
Serial.print(data[0]);
Serial.print(data[1]);
Serial.print(data[2]);
}
最后一种方法是最error-prone,因为你必须知道编译器使用的字节序是什么,它必须与sendong匹配。
如果字节顺序不匹配,您将收到您认为的 "random" 数字。不过,它确实很容易调试。例如,您发送值 156(十六进制 0x9C),并收到 39936(十六进制 0x9C00)。看?字节被反转。另一个例子:发送 8942(十六进制 0x22EE)并接收 60962(十六进制 0xEE22)。
最后,我想你会遇到问题,因为有时你不会收到字节 "in one block",而是分开的。例如,当您发送 1 123 555(十六进制,例如大端字节序,这将是六个字节,特别是 00 01 00 7B 02 2B)时,您可能会收到对 SimbleeBLE_onReceive 的调用,只有 3 或 4 个字节,然后接收其他人。所以你必须定义一种协议来标记数据包的开始and/or结束,并在缓冲区中累积字节直到准备好处理它们。
我想使用 uint8 数组通过蓝牙从移动设备向 Arduino 发送大于 255 的整数。
由于我使用的 BLE 模块不接受 Uint16Array,因此我只能使用 Uint8 数组。
我的应用代码:
var data = new Uint8Array(3);
data[0]= 1;
data[1]= 123;
data[2]= 555;
ble.writeWithoutResponse(app.connectedPeripheral.id, SERVICE_UUID, WRITE_UUID, data.buffer, success, failure);
我的设备特定代码:
void SimbleeBLE_onReceive(char *data, int len) {
Serial.print(data[0]); // prints 1
Serial.print(data[1]); // prints 123
Serial.print(data[2]); // failed to print 555
}
由于 uint8 只允许最大为 255 的整数,我如何发送大于 255 的整数?
在发送端和接收端对数据进行某种形式的缩放,使其保持在 0 到 255 的范围内。例如除法和乘法,因此数据发送到 255 以下,然后在接收端按比例放大。
另一种方法,如果您知道数据的高低范围,则可以使用 Arduino 映射功能。
y = map(mapped value, actual lo, actual hi, mapped lo, mapped hi)
如果您不知道完整范围,可以使用 constrain()
函数。
你必须拆分它。您已经知道(或者您应该知道)int16 有 16 位(所以需要两个字节来存储它)。
现在关于字节序的非常小的题外话。对于字节序,您的意思是存储时字节的顺序。例如,如果您的值为 0x1234,则可以将其存储为 0x12 0x34(大端)或 0x34 0x12(小端)。
我不知道你用的是什么语言,所以...通常在 C++ 中你会这样做:
const int datalen = 3;
uint16_t data[datalen];
data[0]= 1;
data[1]= 123;
data[2]= 555;
uint8_t sendingData[] = new uint8_t[datalen * sizeof(uint16_t)];
for (int i = 0; i < datalen; i++)
{
sendingData[i * 2] = (data[i] >> 8) & 0xFF;
sendingData[i * 2 + 1] = data[i] & 0xFF;
}
functionToSendData(sendingData, datalen * sizeof(uint16_t));
这以大端格式发送。如果你更喜欢小端,写
sendingData[i * 2] = data[i] & 0xFF;
sendingData[i * 2 + 1] = (data[i] >> 8) & 0xFF;
更简单的版本可以是
const int datalen = 3;
uint16_t data[datalen];
data[0]= 1;
data[1]= 123;
data[2]= 555;
functionToSendData((uint8_t*)data, datalen * sizeof(uint16_t));
在第一种情况下,您知道传输的字节序(大小取决于您的编码方式),在第二种情况下,它取决于架构 and/or 编译器。
在JavaScript中你可以使用这个:
var sendingData = new Uint8Array(data.buffer)
然后发送这个新数组。学分转到 this answer
当你收到它时,你必须做这三件事之一来转换它
// Data is big endian
void SimbleeBLE_onReceive(char *receivedData, int len) {
uint16_t data[] = new uint16_t[len/2];
for (int i = 0; i < len/2; i++)
data = (((uint16_t)receivedData[i * 2]) << 8) + receivedData[i * 2 + 1];
Serial.print(data[0]);
Serial.print(data[1]);
Serial.print(data[2]);
}
// Data is little endian
void SimbleeBLE_onReceive(char *receivedData, int len) {
uint16_t data[] = new uint16_t[len/2];
for (int i = 0; i < len/2; i++)
data = receivedData[i * 2] + (((uint16_t)receivedData[i * 2 + 1]) << 8);
Serial.print(data[0]);
Serial.print(data[1]);
Serial.print(data[2]);
}
// Trust the compiler
void SimbleeBLE_onReceive(char *receivedData, int len) {
uint16_t *data = receivedData;
Serial.print(data[0]);
Serial.print(data[1]);
Serial.print(data[2]);
}
最后一种方法是最error-prone,因为你必须知道编译器使用的字节序是什么,它必须与sendong匹配。
如果字节顺序不匹配,您将收到您认为的 "random" 数字。不过,它确实很容易调试。例如,您发送值 156(十六进制 0x9C),并收到 39936(十六进制 0x9C00)。看?字节被反转。另一个例子:发送 8942(十六进制 0x22EE)并接收 60962(十六进制 0xEE22)。
最后,我想你会遇到问题,因为有时你不会收到字节 "in one block",而是分开的。例如,当您发送 1 123 555(十六进制,例如大端字节序,这将是六个字节,特别是 00 01 00 7B 02 2B)时,您可能会收到对 SimbleeBLE_onReceive 的调用,只有 3 或 4 个字节,然后接收其他人。所以你必须定义一种协议来标记数据包的开始and/or结束,并在缓冲区中累积字节直到准备好处理它们。