Android 事物 Raspberry Pi UART 可靠性问题
Android Things Raspberry Pi UART Reliability Issue
我正在通过 UART 从 Arduino 接收数据。我按照文档进行操作,大部分时间都按预期获得数据。有时读取没有完成,得到几个零,然后用其余数据开始新的读取。这可以在示例输出中看到,所有数据都在那里,但分为 2 个读取。我每秒只发送一次数据,所以应该有足够的时间。
我的代码:
private UartDeviceCallback mUartCallback = new UartDeviceCallback() {
@Override
public boolean onUartDeviceDataAvailable(UartDevice uart) {
// Read available data from the UART device
try {
readUartBuffer(uart);
} catch (IOException e) {
Log.w(TAG, "Unable to access UART device", e);
}
// Continue listening for more interrupts
return true;
}
private void readUartBuffer(UartDevice uart) throws IOException {
// Maximum amount of data to read at one time
final int maxCount = 20;
byte[] buffer = new byte[maxCount];
uart.read(buffer, maxCount);
Log.i(TAG, Arrays.toString(buffer));
}
@Override
public void onUartDeviceError(UartDevice uart, int error) {
Log.w(TAG, uart + ": Error event " + error);
}
};
示例输出:
[50, 48, 54, 46, 52, 53, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 54, 46, 57, 51, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 54, 46, 48, 52, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 55, 46, 51, 52, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 54, 46, 53, 48, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 55, 46, 51, 54, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 54, 46, 57, 51, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 0, 0, 0, 0]
[51, 48, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[50, 48, 55, 46, 51, 56, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 0, 0, 0, 0]
[51, 48, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[50, 48, 54, 46, 52, 57, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
我很确定问题出在 R Pi 上,因为我可以毫无问题地从 Arduino 返回到我的 PC。我还发现,除非我将 maxCount 设置为我发送的确切字节数,否则问题会更加普遍。因此,数据以随机包的形式出现,但顺序正确。我在浪费时间吗?我应该只使用 I2C 吗?
"Should I just use I2C?" - 没有。
R Pi没有问题,因为"all the data is there"。它们(可以)拆分(或不拆分,尤其是如果它很短)分成 2 个(或更多)读取,因为 onUartDeviceDataAvailable()
可以在所有数据可用之前触发(但只有一部分可用),所以你应该阅读它们循环播放,直到您收到所有这些。而且,根据您的代码:maxCount - Maximum amount of data to read at one time
不是所有数据的大小,而是最大值。一次性读取的大小。您的代码可以是这样的(注意!这只是示例,不是完整的解决方案):
private void readUartBuffer(UartDevice uart) throws IOException {
// Buffer for all data
final int maxSizeOfAllData = 30;
byte[] completaDataBuffer = new byte[maxSizeOfAllData];
// Buffer for one uart.read() call
final int maxCount = 20;
byte[] buffer = new byte[maxCount];
int bytesReadOnce; // number of actually available data
int totalBytesRead = 0;
// read all available data
while ((bytesReadOnce = uart.read(buffer, maxCount))) > 0) {
// add new data to "all data" buffer
for (int i = 0; i < bytesReadOnce; i++) {
completaDataBuffer[totalBytesRead + i] = buffer[i]
if (totalBytesRead + i == maxSizeOfAllData - 1) {
// process complete buffer here
...
totalBytesRead = 0;
break;
}
}
totalBytesRead += bytesReadOnce;
}
}
另外,看看 NmeaGpsModule.java from Android Things user-space drivers and LoopbackActivity.java from Android Things samples。
我最后添加了一个结束字符 (0x36) 并使用了 dataCompleteFlag:
private void readUartBuffer(UartDevice uart) throws IOException {
// Maximum amount of data to read at one time
final int maxCount = 32;
byte[] buffer = new byte[maxCount];
boolean dataCompleteFlag = false;
uart.read(buffer, maxCount);
Log.i(TAG, Arrays.toString(buffer));
if (!dataCompleteFlag) {
for (int i = 0; i < maxCount; i++) {
if (buffer[i] == 36) {
dataCompleteFlag = true;
dataCount = 0;
}
else if(dataCount > maxCount) {
dataCount = 0;
}
else if(buffer[i] != 0) {
finalDataBuffer[dataCount] = buffer[i];
dataCount++;
}
}
}
if (dataCompleteFlag) {
//process data
}
}
@Override
public void onUartDeviceError(UartDevice uart, int error) {
Log.w(TAG, uart + ": Error event " + error);
}
};
我正在通过 UART 从 Arduino 接收数据。我按照文档进行操作,大部分时间都按预期获得数据。有时读取没有完成,得到几个零,然后用其余数据开始新的读取。这可以在示例输出中看到,所有数据都在那里,但分为 2 个读取。我每秒只发送一次数据,所以应该有足够的时间。
我的代码:
private UartDeviceCallback mUartCallback = new UartDeviceCallback() {
@Override
public boolean onUartDeviceDataAvailable(UartDevice uart) {
// Read available data from the UART device
try {
readUartBuffer(uart);
} catch (IOException e) {
Log.w(TAG, "Unable to access UART device", e);
}
// Continue listening for more interrupts
return true;
}
private void readUartBuffer(UartDevice uart) throws IOException {
// Maximum amount of data to read at one time
final int maxCount = 20;
byte[] buffer = new byte[maxCount];
uart.read(buffer, maxCount);
Log.i(TAG, Arrays.toString(buffer));
}
@Override
public void onUartDeviceError(UartDevice uart, int error) {
Log.w(TAG, uart + ": Error event " + error);
}
};
示例输出:
[50, 48, 54, 46, 52, 53, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 54, 46, 57, 51, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 54, 46, 48, 52, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 55, 46, 51, 52, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 54, 46, 53, 48, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 55, 46, 51, 54, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
[50, 48, 54, 46, 57, 51, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 0, 0, 0, 0]
[51, 48, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[50, 48, 55, 46, 51, 56, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 0, 0, 0, 0]
[51, 48, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[50, 48, 54, 46, 52, 57, 32, 50, 49, 46, 55, 48, 32, 51, 51, 46, 51, 48, 32, 0]
我很确定问题出在 R Pi 上,因为我可以毫无问题地从 Arduino 返回到我的 PC。我还发现,除非我将 maxCount 设置为我发送的确切字节数,否则问题会更加普遍。因此,数据以随机包的形式出现,但顺序正确。我在浪费时间吗?我应该只使用 I2C 吗?
"Should I just use I2C?" - 没有。
R Pi没有问题,因为"all the data is there"。它们(可以)拆分(或不拆分,尤其是如果它很短)分成 2 个(或更多)读取,因为 onUartDeviceDataAvailable()
可以在所有数据可用之前触发(但只有一部分可用),所以你应该阅读它们循环播放,直到您收到所有这些。而且,根据您的代码:maxCount - Maximum amount of data to read at one time
不是所有数据的大小,而是最大值。一次性读取的大小。您的代码可以是这样的(注意!这只是示例,不是完整的解决方案):
private void readUartBuffer(UartDevice uart) throws IOException {
// Buffer for all data
final int maxSizeOfAllData = 30;
byte[] completaDataBuffer = new byte[maxSizeOfAllData];
// Buffer for one uart.read() call
final int maxCount = 20;
byte[] buffer = new byte[maxCount];
int bytesReadOnce; // number of actually available data
int totalBytesRead = 0;
// read all available data
while ((bytesReadOnce = uart.read(buffer, maxCount))) > 0) {
// add new data to "all data" buffer
for (int i = 0; i < bytesReadOnce; i++) {
completaDataBuffer[totalBytesRead + i] = buffer[i]
if (totalBytesRead + i == maxSizeOfAllData - 1) {
// process complete buffer here
...
totalBytesRead = 0;
break;
}
}
totalBytesRead += bytesReadOnce;
}
}
另外,看看 NmeaGpsModule.java from Android Things user-space drivers and LoopbackActivity.java from Android Things samples。
我最后添加了一个结束字符 (0x36) 并使用了 dataCompleteFlag:
private void readUartBuffer(UartDevice uart) throws IOException {
// Maximum amount of data to read at one time
final int maxCount = 32;
byte[] buffer = new byte[maxCount];
boolean dataCompleteFlag = false;
uart.read(buffer, maxCount);
Log.i(TAG, Arrays.toString(buffer));
if (!dataCompleteFlag) {
for (int i = 0; i < maxCount; i++) {
if (buffer[i] == 36) {
dataCompleteFlag = true;
dataCount = 0;
}
else if(dataCount > maxCount) {
dataCount = 0;
}
else if(buffer[i] != 0) {
finalDataBuffer[dataCount] = buffer[i];
dataCount++;
}
}
}
if (dataCompleteFlag) {
//process data
}
}
@Override
public void onUartDeviceError(UartDevice uart, int error) {
Log.w(TAG, uart + ": Error event " + error);
}
};