воскресенье, 16 февраля 2014 г.

Arduino+Arduino

Попробовал связать 2 Arduino по SPI протоколу. Я не нашел в сети официальной информации о максимальной длине кабеля, по которому можно передавать сигналы по SPI протоколу. Если у вас есть ссылочка на официальную документацию, буду благодарен. А у меня пока есть только мнения на форумах. В основном считают, что по SPI можно передавать информацию на совсем короткие расстояния. Но тут человек делится опытом, мол на 300 метров сигнал идёт, и можно использовать большую длину, если делить частоту.

Поэтому я решил проверить, как будет работать связь между платами по длинному кабелю.
И вот что получилось.

Сперва соединил 2 платы короткими проводками, чтобы отладить взаимодействие устройств.
С кодом как и раньше не заморачивался и сделал на основе этой статьи.
Код для Master
/*
MASTER При нажатии на кнопку зажигаем свой светодиод
  и отправляем 1 на ведомый контроллер
*/ #include <SPI.h> #define SS_PIN 10 void setup() { // LED pinMode(3, OUTPUT);
  // Button
pinMode(5, INPUT); pinMode(SS_PIN, OUTPUT); SPI.begin(); } void loop() { if (digitalRead(5)) {
    // Set the LED on
digitalWrite(3, HIGH);
    // Send 1 to Slave
digitalWrite(SS_PIN, LOW); SPI.transfer(1); digitalWrite(SS_PIN, HIGH); } else {
    // Set the LED off
digitalWrite(3, LOW);
    // Send 0 to Slave
digitalWrite(SS_PIN, LOW); SPI.transfer(0); digitalWrite(SS_PIN, HIGH); }
}

Код для Slave
/*
  SLAVE
  Принимаем сигнал по SPI
  и зажигаем светодиод, если сигнал = 1
 */

// Определяем пины SPI
#define MOSI_PIN 11 
#define MISO_PIN 12 
#define SCK_PIN  13
#define SS_PIN 10

byte recievedByte;

void setup() {
  // Обнуляем регистр управления SPI
  SPCR = B00000000;
  // Разрешаем работу SPI
  SPCR = (1<<SPE);

  // LED
  pinMode(3, OUTPUT);

  // Определяем пины для работы с SPI
  pinMode(MOSI_PIN, INPUT);
  pinMode(MISO_PIN, OUTPUT);
  pinMode(SCK_PIN, INPUT);
  pinMode(SS_PIN, INPUT);
}

void loop() {
  while (digitalRead(SS_PIN)==LOW) {
    // Принимаем байт
    recievedByte = spi_receive();
    if (recievedByte) {
      digitalWrite(3, HIGH);
    }
    else {
      digitalWrite(3, LOW);
    }
  }
}

// Приём байта
byte spi_receive()
{
  // Пока не выставлен флаг окончания передачи, принимаем биты
  while (!(SPSR & (1<<SPIF))){};
  // Возвращаем содержимое регистра данных SPI
  return SPDR;                    
}

Заработало с первого раза и без проблем. В Arduino просто напрямую соединил выводы 10 с 10, 11 с 11, 12 с 12 и 13 с 13 короткими проводками. Это видно на первом видео.

А потом решил опробовать реальный кабель. Взял обычный не экранированный Ethernet кабель длиной чуть больше 20 метров и точно так же соединил контакты. Не работает!!! Вернее то работает, то не работает, никакой стабильности. Сперва думал, что дело в контактах, так как при шевелении кабеля что-то улучшалось. А потом воткнул контакты кабеля в макетную плату, это видно на видео ниже, и начал замыкать контакты параллельно короткими кабелями.

В итоге оказалось вот что. Оказалось, что я наугад посадил одну витую пару на MOSI (11), MISO (12), а другую витую пару на SCK(13), SS (10) и это, как оказалось, не хорошо. Изменил порядок соединения. Одну витую пару посадил на SS(10), MOSI (11), а другую - на MISO(12), SCK (13). И всё заработало отлично! В спецификации к SPI не нашел информации о соединении по витой паре. Может быть плохо искал. Если есть ссылочка, буду благодарен.

Вот, длина кабеля чуть больше 20 метров:

UPD1: Пара ссылок
Extending the SPI bus for long-distance communication
Architecture, Design and Implementation of Embedded System for Real-Time Applications

UPD2: Информация от инструктора курса

See page 1355 of tm4c123gh6pm.pdf. The TM4C123 timing is rated for a maximum of 50 pF load. As the capacitance goes up, the signals rise and fall too slowly.


The simplest solution is RS232 or RS422 added to the UART in chapter 11.

CAN is a nice network for 20m and built into this processor.http://users.ece.utexas.edu/~valvano/EE345M/view23_CAN.pdf