Одновременное общение ардуин по проводу и по радиоканалу.

Paul_B
Offline
Зарегистрирован: 05.12.2016

Бьюсь уже вторую неделю. Есть три ардуины. Две должны общаться по проводам. Одна из них должна общаться с третьей по радиоканалу.

Для общение по проводам пробовал варианты SoftwareSerial и вариант Wire. Пришел к выводу, что через Wire гораздо стабильнее связь и проще реализуема.

По радиоканалу тоже просто реализовал через VirtualWire.

Но вот со "склейкой" на той ардуине, что по проводам и по радиоканалу никак не выходит, т.к. библиотеки Wire и VirtualWire начинают конфликтовать.

Пробовал реализовать все только через VitrualWire. Почти получилось, остался затык. На той ардуине, что по проводам и радиоканал, когда к TX-пину (передающему) подключен провод и передатчик, то все замечательно, сигнал одновременно идет по проводу на одну ардуину и по радиоканалу на вторую, а вот на RX-пине (принимающем) начинается чехарда и сигнал по проводу и по радиканалу начинают друг друга давить.

Пробовал менять RX-пин через такую реализацию

    if(R_RX==3)
      {
       vw_rx_stop(); 
       R_RX=2;
       vw_set_rx_pin(R_RX);       // устанавливаем пин приемника
       vw_setup(1500);            // скорость передачи данных в Kbps
       vw_rx_start();
      } 

, вешая анализ приходящего сигнала по проводу на 2-пин, по радио на 3 пин и используя

  attachInterrupt(0, receive_Radio, CHANGE); // вешаем функцию приема на прерывание 
  attachInterrupt(1, receive_Line, CHANGE);

Но тогда начинают теряться передаваемые сообщения.

Поэтому прошу помощи в идее. 

Либо надо как-то разделить работу библиотек Wire и VirtualWire, либо как-то придумать как разделить приходящий сигнал с провода и по радио. Да, пробовал еще подключать через диоды провод и радиоприемник (по прямой и обратной полярностью) - не помогло.

arDubino
Offline
Зарегистрирован: 12.01.2017

хз че ты там делаешь.

но по логике надо сеансы связи делать с главной - одной .

другие передают только когда получат сигнал с главной о начале приема.

вот и все. таким образом и будешь вначале опрашивать по проводу потом по радио.

Paul_B
Offline
Зарегистрирован: 05.12.2016

Еще нюанс.

Ардуина, что по проводу и по радио принимает и отсылает по проводу через Wire все отлично, одновременно с этим может принимать радио. Все замечательно работает. Но стоет ей только послать команду по радио, тут же все затыкается, символы на экран перестают правильно выводиться, через Wire начинают вместо правильных сообщений отсылаться "пустые" строки с 0-м количеством входящих байтов.

Вот как реализованы функции радиоприема и радиопередачи


void send_Radio(String S) // передача по радиоканалу 
{
    char msg[27];

// преобразуем строковую переменную в последовательность байт т.к. Wire отправляет байты     
    S.toCharArray(msg, S.length()+1);
    vw_send((byte *)msg, strlen(msg));
    vw_wait_tx();                     // Wait until the whole message is gone
     Serial.print("Send Radio [");   
     for (int i = 0; i < strlen(msg); i++)
         Serial.print(msg[i]);
     Serial.println("]");
// для наглядности печатаем отправляемую команду       
}

void receive_Radio()    // прием по радиоканалу
{
 uint8_t i; 
 char buf[VW_MAX_MESSAGE_LEN];
 uint8_t buflen = VW_MAX_MESSAGE_LEN;

 if (vw_get_message(buf, &buflen))
    {
     Serial.print("Read Radio [");   
     for (i = 0; i < buflen; i++)
         Serial.print(buf[i]);
     Serial.println("]");
    }

}

 

Paul_B
Offline
Зарегистрирован: 05.12.2016

А вот как реализованы команды приема и передачи через Wire (пины A4 A5)


void send_I2C(uint8_t adr, String S) // передача по шине I2C 
{
  uint8_t c;
  char msg[32];

// преобразуем строковую переменную в последовательность байт т.к. Wire отправляет байты 
  S.toCharArray(msg, S.length()+1);  

// передаем последовательность байт по шине I2C на устройство с адресом adr  
  Wire.beginTransmission(adr); // transmit to device #8
  Wire.write((byte *)msg, strlen(msg));       // sends five bytes
  Wire.endTransmission();    // stop transmitting
  
  // печатаем для наглядности передаваемую команду
  Serial.print("Send I2C [");        
  for (int i = 0; i < strlen(msg); i++) Serial.print(msg[i]);
  Serial.println("]");
  
}


void receive_I2C(int howMany) // прием по шине I2C
{ 
  // прием последовательность байтов и печать для наглядности
  Serial.print("Read I2C [");
  while (Wire.available()>0) 
    { // loop through all but the last
     char c = Wire.read(); // receive byte as a character
     Serial.print(c);         // print the character
    }
  Serial.println("]");         // print the integer
}

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Paul_B, у меня складывается впечатление, что Вы пытаетесь по одному и тому же каналу общаться одновременно с разными устройствами.

Ответьте для начала на вопрос: через какие пины происходит общение с одним устройством, и через какие - с другим?

Paul_B
Offline
Зарегистрирован: 05.12.2016

Я уже все реализовал.

14 пин (можно любой) - передача по проводу и по радиоканалу (одновременная рассылка возможна)

3 (можно любой) - прием по проводу

2 (можно любой)- прием по радиоканалу.

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

Если интересно, могу привести коды реализаций.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Лично мне не интересно, написал исключительно из желания помочь. Но раз у Вас все работает - замечательно.

Paul_B
Offline
Зарегистрирован: 05.12.2016

Вот привожу пример, который можно использовать так же в качестве передачи структуры данных только при помощи библиотеки VirtualWire.h (т.е. без применения библитеки EasyTransferVirtualWire.h), что существенно экономит ресурсы ардуины (и основную память и память для переменных).

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

#include <MsTimer2.h>
#include <avr/wdt.h>
#include <VirtualWire.h>

#define R_TX 14              // пин для передатчика (одновременно по проводу и радиканалу)
#define R_RX 15              // пин для приемника по радиканалу
#define L_RX 3               // пин для приема по проводу
#define My_id 2              // уникальный идентификацинный номер этого устройства
byte Active_RX;              // активный пин для передачи
int All=0,Bad=0;
long MS_Timer;

struct SEND_DATA_STRUCTURE{   // структура данных для передачи. она должна быть одинаковой на все устройствах 
  byte device_id;             // уникальный номер отправителя
  byte destination_id;        // уникальный номер получателя
  byte packet_id;             // номер передаваемого пакета
  int com_data;               // передаваемые данные в виде целого числа
  char comand[3];             // передаваемые данные в виде символов 
  byte crc_id;                // контрольная сумма для дополнительного контроля.
};

SEND_DATA_STRUCTURE mydata;

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(14));
  
  //ET.begin(details(mydata));
  
  pinMode(R_TX,OUTPUT);
  pinMode(R_RX,INPUT);
  pinMode(L_RX,INPUT);
  
  vw_set_ptt_inverted(true); // для передатчика
  vw_set_tx_pin(R_TX);       // устанавливаем пин передатчика
  vw_set_rx_pin(R_RX);       // устанавливаем пин приемника
  Active_RX=R_RX;
  vw_setup(2000);            // скорость передачи данных в Kbps
  vw_rx_start();             // Start the receiver PLL running

  MsTimer2::set(100, MS_T);  // прерывания по таймеру, период 500 мс
  MsTimer2::start();              // разрешение прерывания

}

void loop() {
  
  if(MS_Timer%20==0)
    {
      if(Send_Data(3, "SFS", All)==-1) Bad++;
      Send_Data(1, "DST", All);
      All++;
      Serial.println("All="+String(All,DEC)+" Bad="+String(Bad,DEC));
     }  

}

int MS_T()
{
  MS_Timer++;
         
  if(MS_Timer%10==0)
    {
     wdt_reset(); 
     }   

}


int Send_Data(byte adr, String Comand, int Data)
{
  if(adr==3)                    // устройство с адресом 3 - на радиоканале, активируем его
  if(Active_RX!=R_RX)
    {
     vw_rx_stop();   
     vw_set_rx_pin(R_RX);       // устанавливаем пин приемника
     vw_setup(2000);            // скорость передачи данных в Kbps
     vw_rx_start();             // Start the receiver PLL running
     Active_RX=R_RX;
     delay(100);
    }
  if(adr==1)                    // устройство с адресом 2 - на проводе, активируем его
  if(Active_RX!=L_RX)
    {
     vw_rx_stop();   
     vw_set_rx_pin(L_RX);       // устанавливаем пин приемника
     vw_setup(6000);            // скорость передачи данных в Kbps
     vw_rx_start();             // Start the receiver PLL running
     Active_RX=L_RX;
     delay(100);
    }

  
  mydata.device_id = My_id;
  mydata.destination_id = adr;
  mydata.packet_id = random(255);
  Comand.toCharArray(mydata.comand, 4);
  mydata.com_data = Data;
  mydata.crc_id = Sum_CRC(mydata);
  Serial.println();
  Serial.print("Transmitting packet "+String(mydata.packet_id,DEC)); 
  Serial.println(" from "+String(mydata.device_id,DEC)+" to "+String(mydata.destination_id,DEC));   
  Serial.print(" comand: <"+String(mydata.comand[0])+String(mydata.comand[1])+String(mydata.comand[2])+">");
  Serial.print(" data: "+String(mydata.com_data,DEC));
  Serial.print(" CRC: "+String(mydata.crc_id,DEC));

  byte i=0;
  do
    {
     send_Struct();
     if(receive_Struct()) 
       {
        // проверяем уникальный идентификационный адрес (нам ли предназначается пакет) и контрольную сумму
        if(mydata.destination_id==My_id && mydata.crc_id==Sum_CRC(mydata))   
         {
          Serial.println();
          Serial.print("                 Receiving packet "+String(mydata.packet_id,DEC)); 
          Serial.println(" from "+String(mydata.device_id,DEC)+" to "+String(mydata.destination_id,DEC));   
          Serial.print("                 comand: <"+String(mydata.comand[0])+String(mydata.comand[1])+String(mydata.comand[2])+">");
          Serial.print(" data: "+String(mydata.com_data,DEC));
          Serial.print(" CRC: "+String(mydata.crc_id,DEC));
          return(0);
         }
       }
     Serial.println(" BAD SEND! i="+String(i,DEC)); 
     i++; 
    } while(i<4); 
  
  Serial.println(" FULL BAD SEND !!!!"); 
  return(-1);
  
}


void send_Struct() // передача по радиоканалу 
{
    char msg[27];
    int i;

// преобразуем строковую переменную в последовательность байт т.к. Wire отправляет байты     
  //  mydata.toCharArray(msg, sizeof(mydata));

    memcpy(msg, &mydata, sizeof(SEND_DATA_STRUCTURE));
    /*
    Serial.print("Send Radio <");   
     for (i = 0; i < sizeof(SEND_DATA_STRUCTURE); i++)
         Serial.print(msg[i]);
     Serial.println(">");
     */
    vw_send((byte *)msg, sizeof(SEND_DATA_STRUCTURE));
    vw_wait_tx();                     // Wait until the whole message is gone

// для наглядности печатаем отправляемую команду       

  
}


bool receive_Struct()    // прием по радиоканалу
{
 uint8_t i; 
 char buf[VW_MAX_MESSAGE_LEN];
 uint8_t buflen = VW_MAX_MESSAGE_LEN;

 vw_wait_rx_max(1000);
 if (vw_get_message(buf, &buflen))
    {
      /*
     Serial.print("Read Radio <");   
     for (i = 0; i < buflen; i++)
         Serial.print(buf[i]);
     Serial.println(">");
     */
     memcpy(&mydata, buf, sizeof(SEND_DATA_STRUCTURE));
     return(true);
    }
  return(false);  
}



byte Sum_CRC(SEND_DATA_STRUCTURE md)
{
  int i;
  int rez=0;

  rez=rez+md.packet_id;
  rez=rez+md.com_data;
  for(i=0;i<3;i++) rez+=md.comand[i]*(i+2);
  rez+=(rez>>8&0xFF);  
  return(rez&0xFF);
}

Код для приемника по радио и по проводу одинаков и отличается только настройкой скорости соединения, ну и должны отличаться My_id номер и при необходимости пины RX-TX

#include <MsTimer2.h>
#include <avr/wdt.h>
#include <VirtualWire.h>

#define R_TX 14             // пин для передатчика (одновременно по проводу и радиканалу)
#define R_RX 2              // пин для приемника по радиканалу
#define My_id 3             // уникальный идентификацинный номер этого устройства
int All=0;
long MS_Timer;


struct SEND_DATA_STRUCTURE{   // структура данных для передачи. она должна быть одинаковой на все устройствах 
  byte device_id;             // уникальный номер отправителя
  byte destination_id;        // уникальный номер получателя
  byte packet_id;             // номер передаваемого пакета
  int com_data;               // передаваемые данные в виде целого числа
  char comand[3];             // передаваемые данные в виде символов 
  byte crc_id;                // контрольная сумма для дополнительного контроля.
};


SEND_DATA_STRUCTURE mydata;

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(14));
  
  pinMode(R_TX,OUTPUT);
  pinMode(R_RX,INPUT);
  
  vw_set_ptt_inverted(true); // для передатчика
  vw_set_tx_pin(R_TX);       // устанавливаем пин передатчика
  vw_set_rx_pin(R_RX);       // устанавливаем пин приемника
  vw_setup(2000);            // скорость передачи данных в Kbps для радио
 // vw_setup(6000);            // скорость передачи данных в Kbps для провода

  vw_rx_start();             // Start the receiver PLL running
 
  MsTimer2::set(100, MS_T);  // прерывания по таймеру, период 500 мс
  MsTimer2::start();              // разрешение прерывания

}

void loop() {

  if(receive_Struct())
   {
    // проверяем уникальный идентификационный адрес (нам ли предназначается пакет) и контрольную сумму       
    if(mydata.destination_id==My_id && mydata.crc_id==Sum_CRC(mydata))   
     {
  Serial.println();
  Serial.print("Receiving packet "+String(mydata.packet_id,DEC)); 
  Serial.println(" from "+String(mydata.device_id,DEC)+" to "+String(mydata.destination_id,DEC));   
  Serial.print(" comand: <"+String(mydata.comand[0])+String(mydata.comand[1])+String(mydata.comand[2])+">");
  Serial.print(" data: "+String(mydata.com_data,DEC));
  Serial.print(" CRC: "+String(mydata.crc_id,DEC));
  
  mydata.device_id = My_id;
  mydata.destination_id = 2;
  mydata.packet_id = random(255);
  mydata.com_data = All;
  String Comand="RRR";
  Comand.toCharArray(mydata.comand, 4);
  mydata.crc_id = Sum_CRC(mydata);
  Serial.println();
  Serial.print("Transmitting packet "+String(mydata.packet_id,DEC)); 
  Serial.println(" from "+String(mydata.device_id,DEC)+" to "+String(mydata.destination_id,DEC));   
  Serial.print(" comand: <"+String(mydata.comand[0])+String(mydata.comand[1])+String(mydata.comand[2])+">");
  Serial.print(" data: "+String(mydata.com_data,DEC));
  Serial.print(" CRC: "+String(mydata.crc_id,DEC));
  delay(100);
  send_Struct();

All++;
    }
    } 

}

int MS_T()
{
  MS_Timer++;
 
         
  if(MS_Timer%10==0)
    {
     wdt_reset(); 
     }   

}

void send_Struct() // передача по радиоканалу 
{
    char msg[27];
    int i;

// преобразуем строковую переменную в последовательность байт т.к. Wire отправляет байты     
  //  mydata.toCharArray(msg, sizeof(mydata));

    memcpy(msg, &mydata, sizeof(SEND_DATA_STRUCTURE));
    /*
    Serial.print("Send Radio <");   
     for (i = 0; i < sizeof(SEND_DATA_STRUCTURE); i++)
         Serial.print(msg[i]);
     Serial.println(">");
     */
    vw_send((byte *)msg, sizeof(SEND_DATA_STRUCTURE));
    vw_wait_tx();                     // Wait until the whole message is gone

// для наглядности печатаем отправляемую команду       

  
}


bool receive_Struct()    // прием по радиоканалу
{
 uint8_t i; 
 char buf[VW_MAX_MESSAGE_LEN];
 uint8_t buflen = VW_MAX_MESSAGE_LEN;

 vw_wait_rx_max(1000);
 if (vw_get_message(buf, &buflen))
    {
      /*
     Serial.print("Read Radio <");   
     for (i = 0; i < buflen; i++)
         Serial.print(buf[i]);
     Serial.println(">");
     */
     memcpy(&mydata, buf, sizeof(SEND_DATA_STRUCTURE));
     return(true);
    }
  return(false);  
}



byte Sum_CRC(SEND_DATA_STRUCTURE md)
{
  int i;
  int rez=0;

  rez=rez+md.packet_id;
  rez=rez+md.com_data;
  for(i=0;i<3;i++) rez+=md.comand[i]*(i+2);
  rez+=(rez>>8&0xFF);  
  return(rez&0xFF);
}