Go Down

Topic: RS485 (Read 22 times) previous topic - next topic

Igor R

Esta correcto  ;)

Igor R

Hola,

He ampliado el ejemplo, poniendo 3 arduinos (2 diecimila y un mega).
Uno de ellos actua como maestro, mandando orden de encendido/apagado de led conectado al pin 13 de los esclavos. Dicha orden se efectua por medio de 2 pulsadores conectados al maestro (uno por cada esclavo).

Aqui podeis ver una foto del montaje:






Y el video del funcionamiento:

[media]http://www.youtube.com/watch?v=S9FSQaToVZ4[/media]



Saludos  ;)


Igor R.

Igor R


CODIGO ARDUINO MAESTRO:

Code: [Select]

//----------------------------------
//RS 485
//By Igor Real
//24-06-09
//----------------------------------


byte            data[12];
unsigned long   previous_time;
unsigned long   previous_time2;
byte            times_repeat=5;
byte            times_repeat2=5;

byte            state=0;
byte            state2=0;

#define  pinCONTROL    02
#define  myaddress     01
 

void setup() {

  pinMode(13,OUTPUT);
  pinMode(pinCONTROL,OUTPUT);
  digitalWrite(13,HIGH);
  digitalWrite(12,LOW);
  pinMode(8,INPUT);
  pinMode(9,INPUT);
  digitalWrite(pinCONTROL,LOW);
  Serial.begin(9600);
  Serial.println("Empezamos");
  state=0;
  state2=0;
}

void loop()
{

 if (digitalRead(8)==state){
   state=!state;
   times_repeat=0;  
 }
 if (digitalRead(9)==state2){
   state2=!state2;
   times_repeat2=0;  
 }

 
 
 
 if (times_repeat<4){
   Serial.flush();  
   //(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4)
   if (digitalRead(8)==HIGH){  
     sendMSG(48,49,68,48,48,32,48,48,48,49);
   }else {
     sendMSG(48,49,68,48,48,32,48,48,48,48);
   }
   times_repeat=times_repeat+1;
 
   previous_time=millis();
   while (((millis()-previous_time)<500) && (Serial.available()!=15)){
     ;;
   }
 
   if (Serial.available()>=15){
     if (receiveMSG()==1){
       Serial.println("Trama correcta");
       if (data[0]==48 && data[1]==49 && data[2]==6){
         //ACK  
         times_repeat=5;
         Serial.println("ACK recibido");
       }
     }
    }
  }  
 
 

 if (times_repeat2<4){
   Serial.flush();  
   //(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4)
   if (digitalRead(9)==HIGH){  
     sendMSG(48,50,68,48,48,32,48,48,48,49);
   }else {
     sendMSG(48,50,68,48,48,32,48,48,48,48);
   }
   times_repeat2=times_repeat2+1;
 
   previous_time2=millis();
   while (((millis()-previous_time2)<500) && (Serial.available()!=15)){
   ;;
   }
 
   if (Serial.available()>=15){
     if (receiveMSG()==1){
       //Serial.println("Trama correcta");
       if (data[0]==48 && data[1]==50 && data[2]==6){
         //ACK  
         times_repeat2=5;
         //Serial.println("ACK recibido");
       }
     }
   }
 }
 
 
 
}


//------------------------
//FUNCIONES
//------------------------

byte receiveMSG(){

 byte  byte_receive;
 byte  state=0;
 byte  cont1=1;
 byte  trace_OK=0;

 unsigned int checksum;
 unsigned int checksum_trace;
 
 
 
 while (Serial.available() > 0){
   
    byte_receive=Serial.read();
    if (byte_receive==00){
      state=1;
      checksum_trace=0;
      checksum=0;
      trace_OK=0;
      cont1=1;
    }else if (state==1 && cont1<=12){
      data[cont1-1]=byte_receive;
      checksum=checksum+byte_receive;
      cont1=cont1+1;
    }else if (state==1 && cont1==13){
      checksum_trace=byte_receive<<8;
      cont1=cont1+1;
    }else if (state==1 && cont1==14){
      checksum_trace=checksum_trace+byte_receive;
      cont1=cont1+1;
      state=0;
      if (checksum_trace==checksum){
          trace_OK=1;
      }else{
        trace_OK=0;
      }
      break;
    }
 }
 return trace_OK;

}



void sendMSG(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
 
 unsigned int checksum_ACK;
 checksum_ACK=address1+address2+5+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
 
 UCSR0A=UCSR0A |(1 << TXC0);
 
 digitalWrite(pinCONTROL,HIGH);
 delay(1);

 Serial.print(0,BYTE);
 Serial.print(address1,BYTE);
 Serial.print(address2,BYTE);
 Serial.print(5,BYTE);
 Serial.print(data_type,BYTE);
 Serial.print(code1,BYTE);
 Serial.print(code2,BYTE);
 Serial.print(Sign,BYTE);
 Serial.print(data1,BYTE);
 Serial.print(data2,BYTE);
 Serial.print(data3,BYTE);
 Serial.print(data4,BYTE);  
 Serial.print(3,BYTE);
 Serial.print(((checksum_ACK>>8)&255),BYTE);
 Serial.print(((checksum_ACK)& 255),BYTE);
 while (!(UCSR0A & (1 << TXC0)));
 digitalWrite(pinCONTROL,LOW);

 
 
}



void sendACK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
 
 unsigned int checksum_ACK;
 checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
 
 UCSR0A=UCSR0A |(1 << TXC0);
 
 digitalWrite(pinCONTROL,HIGH);
 delay(1);

 Serial.print(0,BYTE);
 Serial.print(address1,BYTE);
 Serial.print(address2,BYTE);
 Serial.print(6,BYTE);
 Serial.print(data_type,BYTE);
 Serial.print(code1,BYTE);
 Serial.print(code2,BYTE);
 Serial.print(Sign,BYTE);
 Serial.print(data1,BYTE);
 Serial.print(data2,BYTE);
 Serial.print(data3,BYTE);
 Serial.print(data4,BYTE);  
 Serial.print(3,BYTE);
 Serial.print(((checksum_ACK>>8)&255),BYTE);
 Serial.print(((checksum_ACK)&255),BYTE);
 while (!(UCSR0A & (1 << TXC0)));
 digitalWrite(pinCONTROL,LOW);
 
 
}

void sendNAK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
 
 unsigned int checksum_ACK;
 checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
 
 UCSR0A=UCSR0A |(1 << TXC0);
 
 digitalWrite(pinCONTROL,HIGH);
 delay(1);

 Serial.print(0,BYTE);
 Serial.print(address1,BYTE);
 Serial.print(address2,BYTE);
 Serial.print(15,BYTE);
 Serial.print(data_type,BYTE);
 Serial.print(code1,BYTE);
 Serial.print(code2,BYTE);
 Serial.print(Sign,BYTE);
 Serial.print(data1,BYTE);
 Serial.print(data2,BYTE);
 Serial.print(data3,BYTE);
 Serial.print(data4,BYTE);  
 Serial.print(3,BYTE);
 Serial.print(((checksum_ACK>>8)&255),BYTE);
 Serial.print(((checksum_ACK)&255),BYTE);
 while (!(UCSR0A & (1 << TXC0)));
 digitalWrite(pinCONTROL,LOW);
 
 
}



byte hex2num(byte x){

 byte result;
 
 if (x>=48 && x<=57){
   result=x-48;  
 }else if (x>=65 && x<=70){
   switch(x){
     case 65:
       result=10;
       break;
     case 66:
       result=11;
       break;
     case 67:
       result=12;
       break;
     case 68:
       result=13;
       break;
     case 69:
       result=14;
       break;
     case 70:
       result=15;
       break;    
   }  
 }
 return result;  
}




Igor R

CÓDIGO ARDUINOS ESCLAVOS:
(hay que cambiar la dirección en myaddress a 01 y 02,dependiendo del esclavo)

Code: [Select]

//----------------------------------
//RS 485
//By Igor Real
//24-06-09
//----------------------------------


byte  data[12];
byte  address;
byte  function;
byte  function_code;
unsigned int data_received;
byte  byte_receive;
byte  state=0;
byte  cont1=1;
byte  trace_OK=0;
unsigned int checksum;
unsigned int checksum_trace;

#define  pinCONTROL    02
#define  myaddress     02
 

void setup() {

  pinMode(13,OUTPUT);
  pinMode(pinCONTROL,OUTPUT);
  digitalWrite(2,LOW);
  Serial.begin(9600);
  Serial.println("Empezamos");

}

void loop()
{

  while (Serial.available() > 0){
   
    byte_receive=Serial.read();
    if (byte_receive==00){
      //Serial.println("Se ha recibido byte Start");
      state=1;
      checksum_trace=0;
      checksum=0;
      trace_OK=0;
      address=0;
      data_received=0;
      cont1=1;
    }else if (state==1 && cont1<=12){
      data[cont1-1]=byte_receive;
      checksum=checksum+byte_receive;
      cont1=cont1+1;
    }else if (state==1 && cont1==13){
      checksum_trace=byte_receive<<8;
      cont1=cont1+1;
      //Serial.print("Primer Byte Checksum");      
      //Serial.print(checksum_trace,HEX);
    }else if (state==1 && cont1==14){
      checksum_trace=checksum_trace+byte_receive;
      cont1=cont1+1;
      state=0;
      //Serial.println(byte_receive,HEX);
      //Serial.println("Recibida trama");
      //Serial.print("Checksum Trace= ");
      //Serial.println(checksum_trace,HEX);
      //Serial.print("Checksum= ");
      //Serial.println(checksum,HEX);
      //Serial.println(checksum,DEC);
      //Serial.println("Trama= ");
      //Serial.print(data[0]);
      //Serial.print(data[1]);
      //Serial.print(data[2]);
      //Serial.print(data[3]);
      //Serial.print(data[4]);
      //Serial.print(data[5]);
      //Serial.print(data[6]);
      //Serial.print(data[7]);
      //Serial.print(data[8]);
      //Serial.print(data[9]);
      //Serial.print(data[10]);
      //Serial.println(data[11]);      

      if (checksum_trace==checksum){
        trace_OK=1;
       
        address=(hex2num(data[0])<<4)+(hex2num(data[1]));
        function=data[3];
        function_code=(hex2num(data[4])<<4)+(hex2num(data[5]));
        data_received=(hex2num(data[7])<<12)+(hex2num(data[8])<<8)+(hex2num(data[9])<<4)+(hex2num(data[10]));
       
        //Serial.println("TRAZA CORRECTA");
        //Serial.println(address,DEC);
        //Serial.println(data_received);
        if (address==myaddress){
          if ((function=='D') && (function_code==0) && data[2]==5){
            if (data_received==1){
              digitalWrite(13,HIGH);
              //Serial.println(data_received,DEC);
              sendACK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
            }else if (data_received==0){
              digitalWrite(13,LOW);
              sendACK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
            }
          }
        }
      }else{
        //Serial.println("TRAZA INCORRECTA");  
        sendNAK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
      }
    }

 }
 
}


//------------------------
//FUNCIONES
//------------------------

byte receiveMSG(){

 byte  byte_receive;
 byte  state=0;
 byte  cont1=1;
 byte  trace_OK=0;

 unsigned int checksum;
 unsigned int checksum_trace;
 

 
 
 while (Serial.available() > 0){
   
    byte_receive=Serial.read();
    if (byte_receive==00){
      state=1;
      checksum_trace=0;
      checksum=0;
      trace_OK=0;
      cont1=1;
    }else if (state==1 && cont1<=12){
      data[cont1-1]=byte_receive;
      checksum=checksum+byte_receive;
      cont1=cont1+1;
    }else if (state==1 && cont1==13){
      checksum_trace=byte_receive<<8;
      cont1=cont1+1;
    }else if (state==1 && cont1==14){
      checksum_trace=checksum_trace+byte_receive;
      cont1=cont1+1;
      state=0;
      if (checksum_trace==checksum){
          trace_OK=1;
      }else{
        trace_OK=0;
      }
      break;
    }
 }
 return trace_OK;

}



void sendMSG(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
 
 unsigned int checksum_ACK;
 checksum_ACK=address1+address2+5+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
 
 UCSR0A=UCSR0A |(1 << TXC0);
 
 digitalWrite(pinCONTROL,HIGH);
 delay(1);

 Serial.print(0,BYTE);
 Serial.print(address1,BYTE);
 Serial.print(address2,BYTE);
 Serial.print(5,BYTE);
 Serial.print(data_type,BYTE);
 Serial.print(code1,BYTE);
 Serial.print(code2,BYTE);
 Serial.print(Sign,BYTE);
 Serial.print(data1,BYTE);
 Serial.print(data2,BYTE);
 Serial.print(data3,BYTE);
 Serial.print(data4,BYTE);  
 Serial.print(3,BYTE);
 Serial.print(((checksum_ACK>>8)&255),BYTE);
 Serial.print(((checksum_ACK)& 255),BYTE);
 while (!(UCSR0A & (1 << TXC0)));
 digitalWrite(pinCONTROL,LOW);

 
 
}



void sendACK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
 
 unsigned int checksum_ACK;
 checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
 
 UCSR0A=UCSR0A |(1 << TXC0);
 
 digitalWrite(pinCONTROL,HIGH);
 delay(1);

 Serial.print(0,BYTE);
 Serial.print(address1,BYTE);
 Serial.print(address2,BYTE);
 Serial.print(6,BYTE);
 Serial.print(data_type,BYTE);
 Serial.print(code1,BYTE);
 Serial.print(code2,BYTE);
 Serial.print(Sign,BYTE);
 Serial.print(data1,BYTE);
 Serial.print(data2,BYTE);
 Serial.print(data3,BYTE);
 Serial.print(data4,BYTE);  
 Serial.print(3,BYTE);
 Serial.print(((checksum_ACK>>8)&255),BYTE);
 Serial.print(((checksum_ACK)&255),BYTE);
 while (!(UCSR0A & (1 << TXC0)));
 digitalWrite(pinCONTROL,LOW);
 
 
}

void sendNAK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
 
 unsigned int checksum_ACK;
 checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
 
 UCSR0A=UCSR0A |(1 << TXC0);
 
 digitalWrite(pinCONTROL,HIGH);
 delay(1);

 Serial.print(0,BYTE);
 Serial.print(address1,BYTE);
 Serial.print(address2,BYTE);
 Serial.print(15,BYTE);
 Serial.print(data_type,BYTE);
 Serial.print(code1,BYTE);
 Serial.print(code2,BYTE);
 Serial.print(Sign,BYTE);
 Serial.print(data1,BYTE);
 Serial.print(data2,BYTE);
 Serial.print(data3,BYTE);
 Serial.print(data4,BYTE);  
 Serial.print(3,BYTE);
 Serial.print(((checksum_ACK>>8)&255),BYTE);
 Serial.print(((checksum_ACK)&255),BYTE);
 while (!(UCSR0A & (1 << TXC0)));
 digitalWrite(pinCONTROL,LOW);
 
 
}



byte hex2num(byte x){

 byte result;
 
 if (x>=48 && x<=57){
   result=x-48;  
 }else if (x>=65 && x<=70){
   switch(x){
     case 65:
       result=10;
       break;
     case 66:
       result=11;
       break;
     case 67:
       result=12;
       break;
     case 68:
       result=13;
       break;
     case 69:
       result=14;
       break;
     case 70:
       result=15;
       break;    
   }  
 }
 return result;  
}






Cristal

Igor,

Tengo otra duda:

Porque utilizas en

void sendMSG(......)
checksum_ACK=address1+address2+5+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
...+5....+3 en esta linea y

void sendACK(....)
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
...+6......+3 en esta outra?

Igor R

La diferencia es el byte 4:
- Si es una petición, vale ENQ=0x05h
- Si es respuesta ACK=0x06h
- Si es respuesta NACK=0x15h


Aristides Z.

Igor, estoy más que satisfecho con lo que estás posteando. Tengo una serie de preguntas y quisiera saber además si te puedo consultar por MSN. Soy ing. electrónico pero hasta ahora increiblemente nunca trabajé con RS485. Ahora debo hacerlo, ya he leído mucho sobre el protocolo. Además lo de Fuji que posteaste. Hace un mes comencé sobre algo básico programado en CCS para comunicar 2 pics. Tomé un protocolo muy rudimentario que hallé en un foro y lo arreglé un poco. El problema fue que cuando intenté cambiar de uC ya no funiona. En fin, me parece mucho más práctico tu protocolo y hasta contiene CheckSum, cosa que no había puesto aún en el mío.
Voy al grano, quisiera saber si con estas dos librerías (Master y Slave) que has colocado ya puedo lograr una comunicación eficiente entre un PIC y 2 o más esclavos. Mi proyecto es este: todopic.com.ar/foros/index.php?topic=25602.0 Como podrás ver es bastante ambicioso pero hasta ahora no logré hacer lo que quería que era comunicar con RS485 a todos los nodos. Podrías ayudarme a salir adelante? Muchas gracias.

Igor R

#22
Jun 25, 2009, 04:58 pm Last Edit: Jun 25, 2009, 05:04 pm by igorreal Reason: 1
Hola,

Bueno, en la universidad no se estudia muchas cosas a parte del RS485....

Tampoco yo tengo mucha experiencia... Hace mucho tiempo hice un software de control para PC por medio de RS485 de un variador vectorial de Frenic y me he basado en esto.

El RS485 no tiene mucho misterio, es como una comunicación serie normal. Lo unico que es half duplex, y que el transceiver debe ponerse en Tx ó Rx a la hora de envio/recepción.

Lo que es más díficil es realizar un protocolo. Que ahí dependiendo de tu aplicación lo puedes complicar más o menos.... Este es curioso porque me parece más o menos sencillo, y puedes implementar multitud de funciones. La intención es hacer algo "universal". Da igual la aplicación que lo puedes usar.
Ya sabes, todo el rollo de capas OSI,...El RS485 sólo habla de nivel físico.

Pudes coger ideas en: (en Argentina coger significa otra cosa diferente a España...ja,ja,ja)

http://www.arduino.cc/playground/Main/InterfacingWithHardware#Communication

El Modbus puedes usarlo sobre RS 485 (http://es.wikipedia.org/wiki/Modbus)



Salu2




Igor R.







Aristides Z.

Si, es perfecto y justamente lo que quiero hacer con tu ayuda. Ya que hacer algo universal con buenos comentarios para que sea fácil de entender sería genial. Ahora, te consulto: has trabajado con CCS y Pic? Si te parece me gustaría me dieras el ok para usar tus librerías como base para traducirlas a CCS y que sean usables para PIC ya que estas son para ATMEL. Y por cierto, lo que está posteado es lo definitivo?

Gracias.

P.D. No te hagas problema con lo de cojer, tengo mi cuñado español, un excelente amigo español, y en breve un sobrino español!!!

Igor R

Eres libre de utilizar lo que quieras...

He trabajado algo con CCS,aunque lo tengo un poco oxidado...

Si es definitiva o no, es díficil de decir, porque no tengo claro que todo funcione al 100%...Seguro que faltan cosas de pulir... Pero bueno, seguro que te das cuenta si empiezas a trabajar con ello!!  ;)

Lo bueno que siempre puedes poner el PC como un esclavo/maestro para monitorizar las tramas del bus y chequear que todo va bien. Hay que tener en cuenta que el chip 75176 es muy barato...Te puedes hacer un adapatador USB <--> RS485 muy sencillo utilizando el chip de FTDI. Y ya viene con un pin (TXDEN) que cambia a ON cuando transmites algo y cambia automaticamente a OFF cuando el buffer del dispositivo esta vacio.
O siempre puedes utilizar un MAX232+75176 y el pin RTS para control de envio o recepcion.





Saludos



Igor R.


Igor R

#26
Jun 26, 2009, 12:53 am Last Edit: Jun 26, 2009, 12:57 am by igorreal Reason: 1
Una recomendacion de como conectar una topologia de bus, puede ser algo asi:



En cada Arduino o dispositivo de la red, se cablea con una Y soldada en la cual salen dos conectores de la misma familia. Debe tener la longitud más corta posible.
Cada conector tiene Alimentación, Señal A, Señal B y Masa.

De esta forma, si se quiere ir ampliando la red con dispositivos, bastará con ir intercalandolos ó poniendolos a final. Ya que cada dispositivo tiene macho y hembra, por lo que encaja perfecto.
Se puede preparar un par de conectores, con una resistencia terminadora puesta en los terminales correspondientes a la Señal A y Señal B del bus RS485 para cerrar los extremos (siempre quedará un par de conectores libres).

Ya de paso, llevas alimentación y todo será más fácil en futuras ampliaciones...
El cable de Señal A y B debe ser trenzado.

Es una idea!!  ;)


Igor R.

Randomi

Esto es justo lo que estaba buscando. ¡Gracias!
Aunque no comprendo completamente para que funcion tiene el resistor y porque es exactamente 120 ohm, filtro de ruido?

Igor R

Puedes verlo en : http://www.maxim-ic.com/appnotes.cfm/an_pk/763

Es el mismo concepto físico que puedes ver en las antenas, las ondas estacionarias... O por ejemplo,cuando con una linterna apuntas a un lago, que haces un cambio de medio(impedancia) y parte de la luz traspasa el agua y parte sufre reflexión. Esto mismo ocurre en el cableado cuando llega al extremo, se encuentra un cambio de impedancia (si no hay nada), y parte de la onda es reflejada.

En el link, puedes ver unas formas de onda con el osciloscopio cuando no esta bien terminado el bus.


Saludos



Igor R.

Igor R

Hola,

Un link más para trastear con protocolos basados en rs485:
- SAE J1708=> Automoción, se ha sustituido por CAN bus. Pero sirve para aprender...  http://ww1.microchip.com/downloads/en/AppNotes/01230A.pdf

;)

Go Up