Как отправить массив неизвестного размера по I2C (от ведомого к ведущему)?

i2c

Когда я пытаюсь сделать что-то подобное, все работает.

Подчиненный:

# define DEFAULT_DATA_SIZE 256

byte DATA[DEFAULT_DATA_SIZE];

void requestEvent()
{
  Wire.write( (byte*) DATA, sizeof(DATA));
}

void receiveEvent(int numBytes)
{
  for (int i = 0; i < numBytes; i++) {
    DATA[i] = Wire.read();
  }
}

Мастер:

# define DEFAULT_DATA_SIZE 5

void writeData(byte data[], int numBytes) {
  Wire.beginTransmission(I2C_SLAVE_ADDRESS);
  for (int i = 0; i < numBytes; i++)
  {
    Wire.write(data[i]);
  }
  Wire.endTransmission();
}

void readData() {
  byte data[DEFAULT_DATA_SIZE];
  Wire.requestFrom( I2C_SLAVE_ADDRESS, DEFAULT_DATA_SIZE );
  if ( Wire.available() == sizeof( data))
  {
    Wire.readBytes( (byte *) data, DEFAULT_DATA_SIZE);
  }
  Serial.print("Byte Array: ");
  for (int i = 0; i < DEFAULT_DATA_SIZE; i++ ) {
    Serial.print(data[i]);
    Serial.print(" ");
  }
  Serial.println();
}

byte data[5] = {0x1, 0x2, 0x3, 0x4, 0x5 };

void setup()
{
  Wire.begin();
  Serial.begin(9600); 

  writeData(data, sizeof(data));
  delay(500);
  readData();
}

void loop() {

}

Но это работает только тогда, когда мастер знает, какой длины должен быть массив. Если я задаю значение DEFAULT_DATA_SIZE не 5, а больше, то получаю набор случайных чисел.

Я попытался заставить подчиненное устройство сначала передать длину массива, а затем сам массив. Но по какой-то причине это не работает, и я также получаю случайные числа.

Подчиненный:

#include <Wire.h>
# define I2C_SLAVE_ADDRESS 12
# define DEFAULT_DATA_SIZE 256

byte DATA[DEFAULT_DATA_SIZE];
int RECEIVED_NUMBYTES = 0;
bool isNumBytesSended = false;

void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS);
  delay(1000);
  Wire.onRequest(requestEvent);
  Wire.onReceive(receiveEvent);
}

void loop()
{
}

void requestEvent()
{
  if (!isNumBytesSended) {
    isNumBytesSended = true;
    Wire.write(RECEIVED_NUMBYTES); 
  }
  else {
    isNumBytesSended = false;
    Wire.write( (byte*) DATA, sizeof(DATA)); 
  }
}

void receiveEvent(int numBytes)
{
  RECEIVED_NUMBYTES = numBytes;
  for (int i = 0; i < numBytes; i++) {
    DATA[i] = Wire.read();
  }
}

Мастер:

#include <Wire.h>
# define I2C_SLAVE_ADDRESS 12
# define DEFAULT_DATA_SIZE 10


void writeData(byte data[], int numBytes) {
  Wire.beginTransmission(I2C_SLAVE_ADDRESS);
  for (int i = 0; i < numBytes; i++)
  {
    Wire.write(data[i]);
  }
  Wire.endTransmission();
}

void readData() {
  Wire.requestFrom( I2C_SLAVE_ADDRESS, 1 );
  int numBytes = Wire.read();
  Serial.println("numBytes: " + String(numBytes));
  
  byte data[numBytes];
  if ( Wire.available() == sizeof( data))
  {
    Wire.readBytes( (byte *) data, numBytes);
  }
  Serial.print("Byte Array: ");
  for (int i = 0; i < numBytes; i++ ) {
    Serial.print(data[i]);
    Serial.print(" ");
  }
  Serial.println();
} 

byte data[5] = {0x1, 0x2, 0x3, 0x4, 0x5 };

void setup()
{
  Wire.begin();
  Serial.begin(9600); 

  writeData(data, sizeof(data));
  delay(100);
  readData();
}

void loop() {

}

Основные результаты:

01:20:13.844 -> numBytes: 5
01:20:13.878 -> Byte Array: 11 8 212 8 22 
01:21:51.222 -> numBytes: 0
01:21:51.255 -> Byte Array: 
01:21:54.323 -> numBytes: 5
01:21:54.323 -> Byte Array: 11 8 212 8 22 
01:22:01.682 -> numBytes: 0
01:22:01.717 -> Byte Array: 
01:22:04.280 -> numBytes: 5
01:22:04.314 -> Byte Array: 11 8 212 8 22 
01:22:06.879 -> numBytes: 0
01:22:06.912 -> Byte Array: 
01:22:10.386 -> numBytes: 5
01:22:10.420 -> Byte Array: 11 8 212 8 22 

Подскажите, пожалуйста, как лучше всего решить эту проблему. Может, все значения передавать по одному байту, а между началом новых данных ставить специальный разделитель?

, 👍0

Обсуждение

Вы решаете проблему, отправляя сначала длину. Я бы отредактировал вопрос, включив в него этот код, который, как вы сказали, не работает, а также точные данные, которые вы отправляете, и точные данные, которые вы получили., @romkey

@romkey, добавил, @yoloy

Я получаю набор случайных чисел... числа не случайны, потому что они повторяются... хотя числа недействительны, @jsotola

Попробуйте сделать первый байт длиной. Это удержит вас от отправки нулевого размера, но первый байт будет 0. Создайте функцию, которая будет отправлять массив байт за байтом. Ваше получение также должно знать формат., @Gil


1 ответ


1

да, идея отправлять по одному байту за раз и указывать длину массива сработала. Удивлен, что не сделал этого раньше :)

РАБ:

#include <Wire.h>
# define I2C_SLAVE_ADDRESS 12
# define DEFAULT_DATA_SIZE 256

byte DATA[DEFAULT_DATA_SIZE];
int pointer = 0;

void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS);
  delay(1000);
  Wire.onRequest(requestEvent);
  Wire.onReceive(receiveEvent);
}

void loop()
{
}

void requestEvent()
{
  if (pointer > DATA[0]) {
    Wire.write(0);
  }
  else {
    Wire.write(DATA[pointer++]);
  }
}

void receiveEvent(int numBytes)
{
  DATA[0] = numBytes;
  for (int i = 1; i <= numBytes; i++) {
    DATA[i] = Wire.read();
  }
  pointer = 0;
}

МАСТЕР:

#include <Wire.h>
# define I2C_SLAVE_ADDRESS 12

void writeData(byte data[], int numBytes) {
  Wire.beginTransmission(I2C_SLAVE_ADDRESS);
  for (int i = 0; i < numBytes; i++)
  {
    Wire.write(data[i]);
  }
  Wire.endTransmission();
}

void readData() {
  Wire.requestFrom( I2C_SLAVE_ADDRESS, 1 );
  int numBytes = Wire.read();
  Serial.println("numBytes: " + String(numBytes));

  byte data[numBytes];
  
  for (int i = 0; i < numBytes; i++) { 
    Wire.requestFrom( I2C_SLAVE_ADDRESS, 1 );
    data[i] = Wire.read();
  } 
  Serial.print("Byte Array: ");
  for (int i = 0; i < numBytes; i++ ) {
    Serial.print(data[i]);
    Serial.print(" ");
  }
  Serial.println();
}

byte data[8] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 };

void setup()
{
  Wire.begin();
  Serial.begin(9600);

  writeData(data, sizeof(data));
  delay(100);
  readData();
}

void loop() {

}
,