从一个ESP32到另一个ESP32的 I2C主设备在下一次requestFrom() 调用时获取数据

编程语言 2026-07-09

我有一台主设备向从设备发送数据。从设备随后在处理数据。

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连接到电脑时会有地环路故障,无法接地)

我期望的工作方式是

  1. 主设备向从设备发送数据。
  2. 主设备向从设备请求数据。
  3. 主设备处理数据。

当前的执行顺序。

  1. 主设备向从设备发送数据。
  2. 主设备向从设备请求数据
  3. 由于数据与首次调用不对齐,主设备必须重新向从设备请求数据。

为什么在第一次调用requestFrom() 时就没有收到数据?如何同步以确保在调用时能够接收到正确的数据?这是硬件问题还是我的代码问题?

使用阻塞函数时总是需要两次请求数据,没有超时,并且ESP32在第一次调用前就有充足时间准备数据,似乎不是正确的实现。

解决方案

Wire.write(tx_testing[Counter], sizeof(tx_testing[Counter])); // Send multiple bytes

这段代码的实际效果并不像你想象的那样。你没有贴出完整代码,无法显示 tx_testing 在哪里定义,以及 tx_testing 的数据类型是什么。但这并不重要。假设 tx_testing 的数据类型是 byteuint8_tsizeof(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
...
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章