Обмен данными между ардуинами. VirtualWire-проводное соединение Ардуин 38

Эта статья поможет получить ответ на следующие вопросы:

Как соединить несколько ардуин?
Как осуществить обмен данными между ардуинами?
Как передать сообщение на другой контроллер?

Одним из ответов на все эти вопросы является использование библиотеки .

Хочу отметить, что связь между ардуинами может быть как односторонней, так и с обратной связью. Как проводной так и беспроводной. Мы рассмотрим проводное соединение с обратной связью, с использованием библиотеки для беспроводного соединения.

Схема подключения сети из контроллеров(один Ардуино UNO и пять Ардуино ПРО МИНИ):
Схема подключения VirtualWire

Для односторонней связи, достаточно исключить из схемы серый провод, диоды и резистор.

Описание:
Ардуино МИНИ выполняют свои программы, ожидая сигнала на 9 пине. Ардуино УНО посылает сообщения по одному проводу(TX) для всех Ардуино МИНИ. Ардуино МИНИ обрабатывает все пакеты сообщений и посылают ответ по другому проводу(RX).

Пример клиента(для Ардуино УНО):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <VirtualWire.h>
void setup()
{
Serial.begin(9600);
vw_set_tx_pin(12);
vw_set_ptt_inverted(true);
vw_setup(9000);
vw_rx_start();
pinMode(9, OUTPUT);
}
 
void loop()
{
 
digitalWrite(9, HIGH);
sendd("A1");//сообщение для первого контроллера
sendd("A2");//сообщение для второго контроллера
sendd("A3");//сообщение для третьего контроллера
sendd("A4");//сообщение для четвертого контроллера
sendd("A5");//сообщение для пятого контроллера
digitalWrite(9, LOW);
 
}
 
void sendd(const char *msg){
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
String aa;
vw_send((uint8_t *)msg, strlen(msg));
vw_wait_tx();
 
if (vw_wait_rx_max(30))//30
{
if (vw_get_message(buf, &buflen))
{
digitalWrite(13, true);
int i;
 
for (i = 0; i < buflen; i++)
{
aa=aa+(char)buf[i];
}
Serial.println("Ответ от: "+aa);
digitalWrite(13, false);
} else Serial.println("GetMes");
}
 
}
#include <VirtualWire.h>
void setup()
{
Serial.begin(9600);
vw_set_tx_pin(12);
vw_set_ptt_inverted(true);
vw_setup(9000);
vw_rx_start();
pinMode(9, OUTPUT);
}

void loop()
{

digitalWrite(9, HIGH);
sendd("A1");//сообщение для первого контроллера
sendd("A2");//сообщение для второго контроллера
sendd("A3");//сообщение для третьего контроллера
sendd("A4");//сообщение для четвертого контроллера
sendd("A5");//сообщение для пятого контроллера
digitalWrite(9, LOW);

}

void sendd(const char *msg){
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
String aa;
vw_send((uint8_t *)msg, strlen(msg));
vw_wait_tx();

if (vw_wait_rx_max(30))//30
{
if (vw_get_message(buf, &buflen))
{
digitalWrite(13, true);
int i;

for (i = 0; i < buflen; i++)
{
aa=aa+(char)buf[i];
}
Serial.println("Ответ от: "+aa);
digitalWrite(13, false);
} else Serial.println("GetMes");
}

}

Пример сервера(для Ардуино ПРО МИНИ):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <VirtualWire.h>
 
void setup()
{
Serial.begin(9600);
vw_set_tx_pin(10);
vw_set_rx_pin(9);
vw_set_ptt_inverted(true);
vw_setup(9000);
vw_rx_start();
}
 
void loop()
{
if (digitalRead(12)==HIGH)
{
read_send();
}
}
 
void read_send(){
const char *msg = "hello";
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
String aa;
vw_wait_rx();
if (vw_get_message(buf, &buflen))
{
int i;
for (i = 0; i < buflen; i++)
{
aa=aa+(char)buf[i];
}
Serial.print(aa);
Serial.println("");
if (aa=="A2")
{
const char *msg = "A2";
digitalWrite(13, true);
vw_send((uint8_t *)msg, strlen(msg));
vw_wait_tx();
digitalWrite(13, false);
}
}
}
#include <VirtualWire.h>

void setup()
{
Serial.begin(9600);
vw_set_tx_pin(10);
vw_set_rx_pin(9);
vw_set_ptt_inverted(true);
vw_setup(9000);
vw_rx_start();
}

void loop()
{
if (digitalRead(12)==HIGH)
{
read_send();
}
}

void read_send(){
const char *msg = "hello";
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
String aa;
vw_wait_rx();
if (vw_get_message(buf, &buflen))
{
int i;
for (i = 0; i < buflen; i++)
{
aa=aa+(char)buf[i];
}
Serial.print(aa);
Serial.println("");
if (aa=="A2")
{
const char *msg = "A2";
digitalWrite(13, true);
vw_send((uint8_t *)msg, strlen(msg));
vw_wait_tx();
digitalWrite(13, false);
}
}
}

И в заключении — видео работы скетчей:

Недостатки библиотеки:
— библиотека использует таймеры

38 комментс для “Обмен данными между ардуинами. VirtualWire-проводное соединение Ардуин

  1. Ответить Андрей Фев 18, 2015 13:10

    А если у каждой ардуинки будет свое индивидуальное питание, данный вид связи будет работать?
    И какое может быть расстояние между ардуинками если использовать витую пару?

    • Ответить Slava Фев 19, 2015 09:41

      При использовании проводной схемы, что мешает сделать общую точку?
      Опыты проводились на расстоянии до 30 метров. Потери сигнала отсутствовали!

  2. Ответить Артем Фев 24, 2015 23:17

    Интересная статья спасибо, сам ищу сейчас способ построения сети ардуин с одним мастер-ардуино. Как вариант еще можно использовать RS-485 to TTL конвертер и передавать данные по двум проводам.(описание от adatum.ru http://adatum.ru/podklyuchenie-konvertera-rs-485-v-ttl-k-arduino.html).

    А в чем недостаток, использования библиотекой таймеров??

  3. Ответить Сергей Мар 3, 2015 08:48

    Отличный материал, спасибо. Да и весь сайт просто кладезень. Вопросик: каковы номинал или маркировка диода?

  4. Ответить tosic Мар 27, 2015 13:38

    Подскажите, а как можно передать большие сообщения ?
    например
    отправляю:
    sendd(«{\»key\»:\»3de1be3b5167a2d0f4b97fd55da6c6e7\»,\»status\»:\»ok\», \»sensor1\»:208,\»time\»:1427451215}»);
    Получаю :
    {«key»:»3de1be3b5167a2d0f4b97fd55da6c6e7″,»s

    Хочу что бы общение происходила по json стандарту

  5. Ответить tosic Мар 31, 2015 11:41

    А можно немного подробнее про выпрямительный диод ?
    почему он именно на tx стоит ?
    я понимаю что он пропустить сигнал только в одну сторону, только пока не пойму зачем ?

    • Ответить Slava Мар 31, 2015 18:08

      он пропускает от тх мастера к rx слейвов

      все входа слейв контроллеров активируют вход rx в результате чего получается падение напряжения, что в свою очередь сказывается на определение логической единицы

  6. Ответить Паха Май 19, 2015 21:54

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

  7. Pingback: Обмен данными между ардуинами. VirtualWire-проводное соединение Ардуин | InfoGetsPro

  8. Ответить Jan Сен 25, 2015 22:20

    Не получается связать Mini и Uno. Если используется 1 Mini вместо 5, как у вас, то код ведь можно не править?
    На рисунке глаза сломаешь, пока разглядишь куда провода подключать.
    Проверьте меня: 9 пин Uno к 12 пину Mini, 12 пин Uno к 9 пину Mini, и 11 пин Uno к 10 пину Mini через резистор и диод. Диод брал 1N4007. В чем может быть причина? Абсолютно ни каких действий не происходит, порт молчит, светодиод не горит 🙁

    Не завелось 🙁 Подключение 9 пин Uno к 12 пину Mini, а 12 пин Uno к 9 пину Mini; и 11 пин Uno к 10 пину Mini через резистор и диод (1N4007). Если Mini одна, а не 5, как у вас, ведь код не обязательно редактировать, он же все равно должен работать? Как ни старался, ничего не выходит, просто 0 реакции, в порту тишина и светодиод на Mini никак не реагирует. Что это может быть?
    Можете для примера накидать простенький код для проверки, посылки не строки, а к примеру одной цифры без ожидания ответа. Спасибо.

    • Ответить Slava Сен 26, 2015 10:10

      1. установите на обоих ардуинах пины передачи и приема

      vw_set_tx_pin(7);//пин передачи
      vw_set_rx_pin(8);//пин приема

      2. Соедините rx одной с tx другой

      Все больше ничего не нужно…

      скетч slave ардуины

      void setup() {
      //настройка vitrualwire
      vw_set_tx_pin(7);
      vw_set_rx_pin(8);
      vw_set_ptt_inverted(true);
      vw_setup(9000);
      vw_rx_start();//включаем прием сообщение через virtualwire
      }

      void loop()
      {
      if (vw_get_message(buf_in, &buflen))//если пришло сообщение
      {
      int value_1;//сообщение с главного контроллера
      value_1=buf_in[1];

      switch (value_1){

      case 0xf1://команда с главного контроллера
      digitalWrite(13,HIGH)
      break;

      }

      }

    • Ответить Slava Сен 26, 2015 10:18

      Скетч Мастер контроллера, подключенного к сериал
      uint8_t buf_out1[10];//исходящее сообщение 1 контроллера
      void setup() {
      //настройка virtualWire
      vw_set_tx_pin(7);//пин передачи
      vw_set_rx_pin(8);//пин приема
      vw_set_ptt_inverted(true);
      vw_setup(9000);//скорость передачи данных

      /*———————————————————————*/
      Serial.begin(19200);
      /*———————————————————————*/
      }

      void loop() {
      if (Serial.available())//Ожидаем опроса сериал
      {
      int sr;
      sr = Serial.read();
      delay(40);
      set_param = sr-‘0’;
      if (set_param==5) //если через сериал-консоль послали текст равный 5
      {
      buf_out1[0]=0xf1;//формируем буфер для отправки
      vw_send(buf_out1, sizeof(buf_out1));//отправляем
      }
      }
      }

      открываем сериал консоль, пишем 5 и на слейв ардуинке должен включиться 13 пин(светодиод)

      • Ответить Jan Сен 26, 2015 12:41

        Спасибо, но что-то не хочет работать так как надо, точнее проблема в расшифровке отправленных данных.
        Полный скетч для Uno
        // Uno
        #include

        uint8_t buf_out1[10]; //исходящее сообщение 1 контроллера
        int sr;

        void setup()
        {
        //настройка virtualWire
        vw_set_tx_pin(7);//пин передачи
        vw_set_rx_pin(8);//пин приема
        vw_set_ptt_inverted(true);
        vw_setup(9000);//скорость передачи данных

        /*———————————————————————*/
        Serial.begin(9600);
        /*———————————————————————*/
        }

        void loop()
        {
        if (Serial.available()) //Ожидаем опроса сериал
        {
        sr = Serial.read();
        delay(40);

        if (sr == 53) //если через сериал-консоль послали текст равный 5
        {
        Serial.println(«5»);
        buf_out1[0] = 0xf1; //формируем буфер для отправки
        vw_send(buf_out1, sizeof(buf_out1)); //отправляем
        }
        }
        }

        Полный скетч для Mini
        // Mini
        #include

        uint8_t buf_in[VW_MAX_MESSAGE_LEN];
        uint8_t buflen = VW_MAX_MESSAGE_LEN;

        void setup()
        {
        //настройка vitrualwire
        vw_set_tx_pin(7);
        vw_set_rx_pin(8);
        vw_set_ptt_inverted(true);
        vw_setup(9000);
        vw_rx_start(); //включаем прием сообщение через virtualwire
        }

        void loop()
        {
        if (vw_get_message(buf_in, &buflen)) //если пришло сообщение
        {
        digitalWrite(13, HIGH);
        delay(500);
        digitalWrite(13, LOW);
        int value_1;//сообщение с главного контроллера
        value_1 = buf_in[1];
        switch (value_1)
        {
        case 0xf1: //команда с главного контроллера
        digitalWrite(13, HIGH);
        break;
        }
        }
        }

        Светодиод 13 на Mini загорается на 500 мс, когда что-то пришло, но совсем не хочет загораться от того, что пришло (0xf1). Я пробовал и с if тоже не понимает. Т.е. что-то приходит на Mini и та на это реагирует, но распознать что именно, никак пока не могу.
        Я так понимаю, что в int value_1 должно содержаться отправленное число (0xf1), в десятичной системе 241, я прав? Простите за глупые вопросы 🙂

        • Ответить Slava Сен 26, 2015 16:42

          вот здесь ошибка value_1 = buf_in[1];

          надо value_1 = buf_in[0];

          слейв контроллер

          • Ответить Jan Сен 26, 2015 17:32

            Да, верно, все получилось !!! Спасибо, т.е. отправляли «0» байт буфера, а читали «1», в котором ничего нет.
            Вроде работа библиотеки начала проясняться.
            А про число 0xf1 = 241 я прав?

  9. Ответить Алексей Янв 20, 2016 09:50

    какую связи лучше использовать? эту или rs485/
    надо по дому на земле развести ардуинки про мини. Пока не определился для чего именно, как дострою дом определюсь.
    А пока на участке в парники да автоматику для грибов сделать.
    Витой пары километры в наличии.

    • Ответить Slava Янв 20, 2016 09:54

      Все зависит от расстояния.
      Вы можете использовать VirtualWire,а соединение осуществить через преобразователи rs485. У rs485 дальность более 100м

  10. Ответить dmitry Янв 26, 2016 23:34

    Добрый день. Столкнулся с проблемой, использую 3 arduino
    Arduino server0 TX- 12 порт передачи, RX-11 порт приема
    Arduino client1 TX- 12 порт передачи, RX-11 порт приема
    Arduino client2 TX- 12 порт передачи, RX-11 порт приема

    1) При соединении 2-х Arduino server0 и Arduino client1 TX-12 c RX-11, данные передаются в обе стороны.
    2) Если поставить диод между TX ->- RX то данные не передаются.
    3) Если соединить Arduino server0 с Arduino client1 и client2 ( server0_TX-client1_RX-client2_RX и

    server0_RX-client1_TX-client2_TX ) данные с server0 на client1 и client2 идут, а обратно не идут
    4) так же если поставить диод client1_TX ->- server0_RX и client2_TX ->- server0_RX данные не идут

    Передачу данные от client1_TX и client2_TX на server0_RX проверял светодиодом, он помогает синхронно

    диоду на ардуинках

    Предполагаю что идет падения напряжения и server0_RX не воспринимает сигнал.

    Просьба помочь с настройкой.

    #include «VirtualWire.h»
    void setup()
    {
    Serial.begin(9600);
    vw_set_tx_pin(12);
    vw_set_rx_pin(11); // с нему идут сигнала от других Arduino
    vw_set_ptt_inverted(true);
    vw_setup(7000);
    vw_rx_start();
    }

    void loop()
    {
    //Передаем сообщение
    digitalWrite(13, true);
    const char *msg = «server0»;
    //const char *msg = «client1»;
    //const char *msg = «client2»;
    vw_send((uint8_t *)msg, strlen(msg));
    digitalWrite(13, false);
    delay(3000);

    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    String aa;
    if (vw_wait_rx_max(30))//30
    {
    if (vw_get_message(buf, &buflen))
    {
    digitalWrite(13, true);
    for (int i = 0; i < buflen; i++) {
    aa=aa+(char)buf[i]; }
    Serial.println("Ответ от: "+aa);
    digitalWrite(13, false);
    }
    else
    Serial.println("GetMes");
    }
    }

    • Ответить Slava Янв 27, 2016 13:02

      Отключайте virtualwire при обратной передачи на других контроллерах

      • Ответить dmitry Янв 27, 2016 23:24

        1) не совсем понял, что именно отключать
        пробовал как в примерах через прерывания, когда server подает прерывание на client 1 и 2 они включают прием и потом отвечают, и выключат прием через vw_rx_start(); и vw_rx_stop();

        если можно что именно мне надо делать и на каком устройстве server или client1 или client2 при передачи сигнала от client1 на server если TXclient1 — TXclient2 — RXserver соединены

        2) данные от server одновременно на вход client 1 и 2 идут, оба client видят сообщение от server, но когда client передает данные на server, данные не приходят, если TXclient1 — TXclient2 — RXservet соединены, если отсоединить TX одного из client то от другого сразу же идут данные

        3) диоды не использую т.к. с ними вообще никие данные никуда не передаются

        PS: может где на форуме можно пообщаться а суда уже выложить готовый результат?

  11. Ответить Slava Янв 28, 2016 00:24

    Диоды ставятся от тх слейвов к rx мастера, + притяните к земле через резистор обе линии

  12. Ответить Григорий Мар 5, 2016 16:00

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

  13. Ответить Игорь Сен 12, 2016 17:53

    Добрый день!
    Подключил две ардуины к компьютеру. В Serial первой ардуины пишу какую-либо команду, передаю ее с помощью VirtualWire в Serial второй ардуины. Но там выходят непонятные символы. Хотя если передаю уже обозначенные команды в коде, по примеру «char *msg = «Hello World»;» то в Serial второй ардуины так и выводится Hello World.
    Подскажите, такое вообще возможно организовать?
    Ко второй ардуине хочу подключить LCD экран.
    Вот код передатчика:

    #include
    #include

    #define LED 13
    #define TRANS 12

    void setup()
    {
    vw_set_tx_pin(TRANS);
    vw_setup(2000);
    pinMode(LED, OUTPUT);
    Serial.begin(9600);
    }

    void loop() {
    if (Serial.available()) {
    const char *msg = Serial.read();
    Serial.println(*msg);
    digitalWrite(LED, HIGH);
    vw_send((uint8_t *)msg, strlen(msg));
    vw_wait_tx();
    delay (500);
    } else {
    digitalWrite(LED, LOW);
    }
    }

    • Ответить Slava Сен 30, 2016 11:13

      библиотека virtualwire передает данные пакетами, которые ограничены размером VW_MAX_MESSAGE_LEN

  14. Ответить Alexdesinger Сен 30, 2016 11:00

    Здравствуйте, скажите какой способ перепрошивки возможен при таком типе соединения? Есть ли возможность перепрошивать удаленно? Или нужно будет перепрошивать по uart? Или придется разобрать все подключение, чтобы иметь возможность перепрошить мастера и слэйвы?

    • Ответить Slava Сен 30, 2016 11:14

      к сожалению, с удаленной прошивкой не получится

      • Ответить Alexdesinger Окт 3, 2016 12:41

        Скажите, возможно ли будет перепрошивать контроллеры не отсоединяя их от шины, скаже программатором или минипк через uart?

        • Ответить Slava Окт 3, 2016 15:10

          Дело в том, что для удаленной прошивки нужно использовать не rs-232 а rs-485, значит требуется ставить преобразователи интерфейсов.

          Для отсоединения не нужных контроллеров при прошивки использовать tiny 85 в сочетании с реле.

          т.е. у вас два канала связи и по дополнительному контроллеру для управления прошивками. нужный контроллер tiny коммутируют нужный контроллер и прошивает.

          • Ответить Alexdesinger Окт 5, 2016 10:45

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

  15. Ответить dmitry Мар 27, 2017 20:03

    а можно использовать тока два провода для TX и RX без прерывания для передачи данных? или 3-й провод для прерывания обязателен?

    • Ответить Slava Мар 27, 2017 23:56

      При данной схеме подключения — обязателен

    • Ответить Дмитрий Апр 8, 2017 19:47

      dmitry, у вас что-нибудь получилось? Такие же проблемы как и у вас. Диоды не работают. Два контроллера обмениваются данными, а с тремя уже проблемы — ответа от сервера клиент не получает. Если не инициализировать VirtualWire на одном из серверов — клиент получает ответ от второго сервера. Каким образом динамически отключать VW на серверах? Сигнальный провод по большому счету не нужен. Имеет смысл использовать его приема сообщений через прерывания.

Добавить комментарий