从一个ESP32到另一个ESP32的 I2C主设备在下一次requestFrom() 调用时获取数据
我有一台主设备向从设备发送数据。从设备随后在处理数据。
2秒后,主设备向从设备请求数据。 (这段时间足以完成所有数据处理。)
请求的数据总是在下一次调用 requestFrom() 时收到
下面是我的主设备代码。
void setup()
{
Serial.begin(115200);
delay(2000);
Wire.begin();
delay(2000);
Serial.println("Start I2C Intermediary");
}
int Counter = 0;
void loop()//void * pvParameters)
{
delay(10000);
Wire.beginTransmission(SLAVE_ADDRESS);
Wire.write(tx_testing[Counter], sizeof(tx_testing[Counter])); // Send multiple bytes
Wire.endTransmission();
Serial.printf("\n\nSent data = %#04x", tx_testing[Counter][0]);
for (int i = 1; i < sizeof(tx_testing[Counter]); i++)
{
Serial.printf(", %#04X", tx_testing[Counter][i]);
//Serial.print(", " + String(rx_buf[i]));
}
Serial.print("\n");
Counter++;
if (Counter > 7) { Counter = 0; }
delay(2000);
// Receive data
Wire.requestFrom(SLAVE_ADDRESS, 7, true);
while(Wire.available())
{
byte b = Wire.read(); // Read one byte
Serial.print(b, HEX);
Serial.print(" ");
}
}
下面是从设备代码
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
Serial.print("Setup is running on core ");
delay(1000);
Serial.println(xPortGetCoreID());
BaseType_t taskCore = (xPortGetCoreID() == 0) ? 1: 0;
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
motionUpdate, /* Task function. */
"MotionTask", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
taskCore); /* pin task to core 0 */
delay(500);
Wire.begin(SLAVE_ADDRESS);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
delay(1000);
Serial.println("Setup has finished");
}
int ReceivedBytesLength = 0;
bool NewDataToHandle = false;
void loop()
{
if (NewDataToHandle)
{
HandleByteData(ReceivedBytesLength);
NewDataToHandle = false;
}
delay(1);
}
void receiveEvent(int howMany) // Handle incoming
{
int c = 0;
while(Wire.available())
{
ReceivedBytes[c] = Wire.read(); // Read one byte
c++;
}
ReceivedBytesLength = howMany;
NewDataToHandle = true;
}
int byteTest = 0;
void requestEvent() // Send data
{
if(TransmitLength > 0)
{
Wire.write(TransmittedBytes, 7); // Was TransmitLength. Set to 7 on startup.// Send multiple bytes
}
else
{
uint8_t bytes[] = {byteTest,0x01,0x02,0x03,0x04,0x05,0x06};
Wire.write(bytes, 7); // Send multiple bytes
byteTest++;
}
}
主设备发送的数据在从设备端被处理,在任何请求之前。ESP32的另一核上的任务此刻并未在执行任何操作。
这是来自主设备的输出数据。
Sent data = 0x50, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0X50
F4 FF FF FF FF FF FF // This is where 0 1 2 3 4 5 6 should be.
Sent data = 0x51, 0XF0, 0X0A, 0XBA, 0X95, 0000, 0XF4, 0X05, 0X91, 0X51
0 1 2 3 4 5 6 // This is where 1 1 2 3 4 5 6 should be.
Sent data = 0x52, 0XF0, 0X8A, 0XAB, 0X52, 0XC0, 0XF4, 0X03, 0X20, 0X52
1 1 2 3 4 5 6 // This is where 2 1 2 3 4 5 6 should be.
Sent data = 0x53, 0XE0, 0X80, 0XB3, 0XE4, 0000, 0X2D, 0000, 0000, 0X53
2 1 2 3 4 5 6 // This is where 3 1 2 3 4 5 6 should be.
Sent data = 0x54, 0XE0, 0X80, 0X0F, 0XE4, 0000, 0X9C, 0000, 0000, 0X54
3 1 2 3 4 5 6 // This is where 4 1 2 3 4 5 6 should be.
Sent data = 0x55, 0XE8, 0X03, 0X52, 0XEC, 0X21, 0X4F, 0000, 0000, 0X55
4 1 2 3 4 5 6 // This is where 5 1 2 3 4 5 6 should be.
Sent data = 0x56, 0XE8, 0X03, 0XB7, 0XEC, 0X3B, 0XAA, 0000, 0000, 0X56
5 1 2 3 4 5 6 // This is where 6 1 2 3 4 5 6 should be.
Sent data = 0x57, 0XF1, 0XF5, 0XF8, 0XE1, 0XE5, 0XE9, 0XED, 0XD1, 0X57
6 1 2 3 4 5 6 // This is where 77 78 79 7A 7B 7C 7D should be.
Sent data = 0x50, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0X50
77 78 79 7A 7B 7C 7D // This data is the data received from the call above.
所有接收到的数据都在下一次调用中,例如0x57是应该接收数据的那个 77 78 79 7A 7B 7C 7D
当我添加串口输出时,时间戳显示数据早在调用 requestFrom() 之前就已准备好。
我在主设备的SDA和 SCL线上接着到3.3V的 4.7k电阻。我使用的是标准线。我没有把主从的3.3V电源线和地线连接在一起。(因为通过USB连接到电脑时会有地环路故障,无法接地)
我期望的工作方式是
- 主设备向从设备发送数据。
- 主设备向从设备请求数据。
- 主设备处理数据。
当前的执行顺序。
- 主设备向从设备发送数据。
- 主设备向从设备请求数据
- 由于数据与首次调用不对齐,主设备必须重新向从设备请求数据。
为什么在第一次调用requestFrom() 时就没有收到数据?如何同步以确保在调用时能够接收到正确的数据?这是硬件问题还是我的代码问题?
使用阻塞函数时总是需要两次请求数据,没有超时,并且ESP32在第一次调用前就有充足时间准备数据,似乎不是正确的实现。
解决方案
Wire.write(tx_testing[Counter], sizeof(tx_testing[Counter])); // Send multiple bytes
这段代码的实际效果并不像你想象的那样。你没有贴出完整代码,无法显示 tx_testing 在哪里定义,以及 tx_testing 的数据类型是什么。但这并不重要。假设 tx_testing 的数据类型是 byte 或 uint8_t。sizeof(tx_testing[0] 返回1,sizeof(tx_testing[6]) 仍然是1。要获取uint8_t数组的大小,应该是 sizeof(tx_testing)。
你的代码基本上是在发送1 字节,而不是你所认为的“发送多字节”。
Wire.write(tx_testing[Counter], 1); // send only 1 byte
因此你在经过7 次迭代后才会收到7 字节的请求。正确的代码应该是:
uint8_t tx_testing[7]{0}; // an array of 7 bytes intialized to 0
...
Wire.write(tx_testing[Counter], sizeof(tx_testing)); // send bytes up to size of tx_testing
...