Отправлять строки через SPI в обе стороны, используя два Arduino UNO (ведущий к ведомому и ведомый к ведущему)

Мне нужно создать двухсторонний обменник строк через SPI с двумя Arduino UNO. Строки и их длины являются независимыми переменными основного цикла и могут изменяться при каждой итерации. Мне нужно, чтобы оба Arduino общались друг с другом независимо от того, что содержат строки. Я хочу видеть в основном тот же экран с последовательным монитором.

Вроде работает. Я не знаю, как это объяснить, я просто покажу это ниже.

Основная идея обоих Arduino такова:

Master: hey
Slave: hi

Вместо этого я получаю это на мастере:

Slave: 
Slave: 
Master: hey
Slave: y
Slave: 
Slave: 
.
.
.
Slave: i
Slave: 
Slave: 
.
.

А ведомое устройство отображает только себя:

Slave: hi

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


Соединения:

Arduino1.pin13 --- Arduino2.pin13

Arduino1.pin12 --- Arduino2.pin12

Arduino1.pin11 --- Arduino2.pin11

Arduino1.pin10 --- Arduino2.pin10


Мастер-код

//МАСТЕР

#include<SPI.h>

String textSend="", textReceive="";

void setup(){

  Serial.begin(115200);

  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV8);    //Устанавливает часы для связи SPI на 8 (16/8 = 2 МГц)
  digitalWrite(SS,LOW);
}

void loop(){

  textSend=""; textReceive="";
  textSend = Serial.readString();
  if(textSend != ""){
    for(int i = 0; i < textSend.length(); i++){
      delayMicroseconds (20);
      SPI.transfer(textSend[i]);
    }

    Serial.print ("Master: ");
    Serial.println (textSend);
  }else{
    int i = 0;
    char c;
    do{
      delayMicroseconds (20);
      c = SPI.transfer(1);
      textReceive += c;
      i++;
    }while(textReceive[i] != 0);

    if(textReceive[i] == 0){
      Serial.print ("Slave: ");
      Serial.println (textReceive);
      textReceive = "";
    }
  }
}

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

//ВЕДОМЫЙ

#include<SPI.h>

String textSend="";
String textReceive="";

void setup (void){
  Serial.begin(115200);
  pinMode(MISO, OUTPUT);
  SPCR |= _BV(SPE);
  SPCR |= _BV(SPIE);
  SPI.attachInterrupt();

}

ISR (SPI_STC_vect){ //Прерывание процедуры обслуживания

  byte c = SPDR;

  if(c != 1){ // Ведомый получает
    for(int i = 0; i < textReceive.length(); i++){
      textReceive += SPDR;
    }
    if(textReceive.length() > 0){
      Serial.print("Master: ");
      Serial.println(textReceive);
      textReceive = "";
    }
  }else{
    for(int i = 0; i < textSend.length(); i++){
      delayMicroseconds(20);
      SPDR = textSend[i];
    }
    if(textSend != ""){
      Serial.print("Slave: ");
      Serial.println(textSend);
      textSend = "";
    }
  }
}

void loop() {
  if(textSend == "")
    textSend = Serial.readString();


}

, 👍0


1 ответ


2

Необходимо, чтобы оба Arduino взаимодействовали друг с другом, поскольку SPI является шиной ведущий-ведомый. Это означает, что ведомое устройство не может начать передачу, вместо этого связь всегда должно инициировать ведущее устройство. Еще одна особенность SPI заключается в том, что вы не можете прочитать ведомое устройство без записи в него. SPI работает как регистр сдвига: в каждом такте оба устройства передают друг другу байт в своем SPDR. Таким образом, чтобы прочитать длинную строку от подчиненного устройства, мастер должен передать точно такое же количество фиктивных байтов и одновременно прочитать входящий поток. Это удобно, если необходимо передать только определенное количество байтов (например, обмен переменными, которые всегда состоят из одного и того же числа байтов), но становится сложнее, когда количество байтов меняется. Затем вам нужно будет реализовать некоторый протокол, способный считывать переменное количество байтов с ведомого устройства (например, вам нужно будет сообщить ведущему количество байтов, которые должны быть прочитаны).

Я думаю, что последовательная связь, такая как UART, идеально подходит для ваших целей, поскольку связь является настоящей полнодуплексной, это не система ведущий-ведомый, а общий протокол использует завершающий символ для завершения потока данных, что делает его идеальным для передачи строк. Также Arduino может запускать несколько последовательных интерфейсов (вам может понадобиться еще один для отладочного вывода).

,

Прежде всего, SPI является обязательным для моего задания, поэтому я не могу использовать ничего другого (но спасибо, что предложили альтернативу решению). Можем ли мы поддерживать среду, в которой Мастер постоянно отправляет фиктивный байт для получения байтов Подчиненного, чтобы Мастер прослушивал подчиненное устройство (когда Мастеру нечего отправлять). Подчиненный не примет во внимание фиктивный байт и не добавит в строку что-нибудь еще? Теоретически я думаю, что так должно работать, но я не могу заставить это работать., @Ekin Karadağ

Да, вы можете как бы эмулировать протокол UART на SPI, а это означает, что вам, вероятно, понадобится мастер для непрерывной отправки. Затем вам нужно будет определить фиктивный байт, который будет игнорироваться как ведущим/ведомым устройством, так и завершающим байтом (в UART это обычно \n), чтобы отметить конец строки в потоке байтов. Несмотря на то, что это не самый элегантный способ, я не вижу причин, по которым он не должен работать., @Sim Son

Причина, по которой это не работает, — некоторые ошибки в вашем коде. Например, while(textReceive[i] != 0); неверен, поскольку вы постоянно проверяете условие, которое не может измениться во время его проверки. Таким образом, подпрограмма либо не входит в этот цикл, либо зависает навсегда. Ваш мастер-код выглядит так, будто вы не до конца поняли механизм SPI. Имейте в виду, что вам придется записывать **и** читать **каждый байт** одновременно. Это означает, что цикл for, такой как в вашем случае for(int i = 0; i < textSend.length(); i++), не работает, потому что вы не обрабатываете входящие байты, которые при этом теряются., @Sim Son