comunicar dos arduinos con RS485

Hola a todos, ante todo, espero que éste sea el foro adecuado (antes estaba en documentación, ¡perdón!) e indicar que hace poco menos de un mes que he empezado con arduino, soy electronico, he programado con basic y access, y ahora necesito una "instalacion" con arduino. He buscado y rebuscado durante tres dias con google, he buscado aqui, he visto donde tirais de las orejas a los que prefieren preguntar antes que buscar, soy moderador en un foro de informatica y otro de electronica, y es para matar a muchos, así que os entiendo perfectamente si no quereis ayudarme.
vereis, no hay tu tia de que vea como funciona el codigo de comunicación, como digo, he rebuscado algun ejemplo tonto o muy tonto de encender/apagar un led de un uno a otro uno. del foro de arduino en inglés he visto e intentado usar lo que adjunto, ¡REPITO! NO es mio, es de un problema del que pregunta, que al final dice que le falat flush() despues de una linea que no existe, o bien, que el codigo no está completo y se debe cambiar tx por rx, y al no especificarlo pues no lo sé. He puesto un 0 y/o 1 segun es maestro o esclavo, pero nada funciona.
solo me gustaria como o donde hallar un ejemplo de codigo que funcione, en el foro de inglés veo qe dejan poner links externos, he intentado sin exito lo de esta página https://arduino-info.wikispaces.com/SoftwareSerialRS485Example , he descargado multitud industrial de tutos y ejemplos, y no hay manera de ver como conseguirlo. he instalado librerias cuando se han solicitado. Conectado lo eletrico ya está, con un ejemplo de un pulaador y un led "remoto" tengo bastante para poder seguir investigando y buscando. Muchas gracias por leer hasta aqui, y muuy agradecido si podeis aunque sea, enseñarme a pescar.
saludos

ejemplo_rs485.txt (1.14 KB)

Bueno efect2000, para ser moderador creo que has hecho los deberes por la mitad, porque no creo que hayas leído las normas del foro. Veo enlaces sin tags y tu código no esta posteado como debe.

Aún asi, no se niega nunca la ayuda.

//*** WIRING ***//

/*
ARDUINO 1   -->   RS485(1)  
   RX     RO (1)       
   TX     DI (4)
    3     DE-RE (2-3)
   13     (LED)

ARDUINO 2   -->   RS485(2)     
   RX     RO (1)       
   TX     DI (4)
    3     DE-RE (2-3)
   13     (LED)

RS485(1)    -->   RS485(2)
  VCC             VCC
    A        A
    B        B
  GND      GND
*/


//********************CODE********************************
_____________________________________________________________

#define MODE 0      //0 - EMITER    1 - RECEIVER

#define LED_PIN 13  
#define EN_PIN 3

void setup(){

	pinMode(LED_PIN, OUTPUT); 
	pinMode(EN_PIN, OUTPUT); 

	if (!MODE) 
	    digitalWrite(EN_PIN, HIGH); 
	else 
		digitalWrite(EN_PIN, LOW);
	Serial.begin(9600);
}

void loop(){
 
  if (!MODE){		 				//** EMITER **//
    Serial.write("A");
    digitalWrite(LED_PIN,LOW);
    delay(1000);

    Serial.write("B");
    digitalWrite(LED_PIN,HIGH);
    delay(1000);
 }  else {							//** RECEIVER **//
    if ( Serial.read() == 'A' ) 
        digitalWrite(LED_PIN,LOW); 
 	else 
    	if ( Serial.read() == 'B' ) 
        	digitalWrite(LED_PIN,HIGH);
  	}
}

Trabajar con 485 requiere de que tu interfaz de la que no has dicho nada este bien hecha. No basta con tener un MAX485 de ambos lados y las conexiones como has descripto.
Tambien muchas veces para garantizar el correcto funcionamiento hay que usar un par de resistencias que fijan los valores A y B a VCC y GND para mejorar la respuesta diferencial.

Dinos si usas modulos 485 de los que se compran en Ebay por ejemplo?

SI es asi lo que no me gusta del código son los delay, pero supongo que aun con ellos debería todo funcionar.

Voy a buscarte información y te pasaré algo que hace dias le resolví a un colega colombiano que queria comunicarse con un sensor de nivel de combustible que entregaba la información por 485.
Despues de alguna lucha pude resolverlo pero llevo su tiempo. Y en su caso tenía los módulos 485 que te comento.
Como estos

Supongo que como citas esta página los tendrás.
Asi que veamos tu código, que ya has dicho que no es tuyo.

Este ejemplo usa SoftwareSerial para poder usar el Monitor Serie mientras se comunica con el otro arduino
Ya que el UNO no tiene mas que un puerto serie.
Pero sigue el ejemplo de SoftwareSerialRS485Example

Tambien puedes usar la libreria de Nick Gammon

Acá estan los ejemplos, Nick Gammon es un Gurú de modo que 1009% de que todo lo que el diga es asi y funciona.

Muchas gracias por la respuesta, sincera y realmente, ayer antes de postear estaba "cansado" de este tema y de leer, llevaba tres dias (martes, jueves y viernes) leyendo y releyendo tutoriales, buscando y probando ejemplos, haciendo pruebas) por lo que no leí a fondo las normas, y en los foros que modero no se usa lo que comentas de tags, son de otra ",marca" y en electronica hay esquemas, por lo que tampoco posteamos codigo, pero te doy mi palabra que las leeré antes de volver a comentar los progresos (este no cuenta xD)

Efectivamente, las plaquitas con como las del ejemplo, compradas en ebay a una empresa española que lo que vende lo usa en sus proyectos, y el montaje es como el del ejemplo, la unica diferencia es que los puentes A y B no están con la regleta, sino a traves del protoboard, medí con el tester y me pareció comprobar que era lo mismo, por lo menos con una distancia de 10cm de cable para las pruebas.
Agradezco tu ayuda, en cuanto pueda inicio la lectura y las pruebas.
las resistencias finales de linea o de carga (o creo que para compensar impedancias), supongo que las llevará ya incluidas, en algún sitio de los muchos que he leido, alguien ha tenido problemas debido al valor de éstas, que en vez de 120ohmios han tenido que cambiarlas por 220, 390 o algo así, pero no creo (solo creo) necesario con esta distancia pensar que el problema pueda estar aqui.
no sé si mañana o ya el lunes volveré a la carga con lo que has facilitado, info que agradezco enormemente. En los codigos "mios" no uso delays. Podria montar los circuitos electronicos sencillos, llevo más de 35 años rodeado con temas electronicos, pero hoy en dia excepto para "jugar" o la satisfacción de "lo he hecho yo", no sale a cuenta hacerselo uno mismo (me he cansado), solo hago proyectos con tecnologia de finales del siglo 20 para aplicaciones específicas a mi medida y gusto, pero si algo ya existe y vale 4 duros, no sale a cuenta hacerlo, y se supone que ofreece más garantias de funcionamiento
saludos y gracias, ya comentaré.

si estas próximo no hace falta usar la resistencia de 120 o lo que fuere. Yo no la he necesitado.
Lo primero que haría yo sería esto.

  1. busco la librería SoftwareSerial y defino un par de pines para comunicarse a no mas de 9600 bps con el otro MAX485.
  2. En el nodo esclavo que es quien debe interpretar el mensaje, podré entonces VER que esta leyendo usando Serial.print(dato); ya que ahora no tengo utilizados los pines 0 y 1 para la comunicación.

Ahi podrás ver QUE ESTA OCURRIENDO.
Me confundí y la librería de la que te hablaba era MODBUS asi que no es exactamente lo que tu estas usando.

Veamos que dicen tus pruebas.

Saludos
Al igual que surbyte no uso la resistencias. Es mas cuando la coloco me falla la comunicación.

Muchas gracias a todos por haberse interesado. Estas páginas ya las habia visto y leido, las inglesas también, el problema es que soy muy burro y hasta que no lo asimile no avanzaré. en el ejemplo del gurú he puesto como velocidad en ambos 9600. Tengo el arduino M(aestro) alimentado con el usb que programo, así como las dos interfaces con una salida y comprobado que tengo 5 voltios, el otro lo alimento por usb con otro ordenador, en ambos tengo el read en pin2, DI al pin3, las dos del medio juntas y en el pin4, una en el uno M y el otro igual en el S(lave). Las masas las tengo unidas. Aqui no tengo potenciómetro y no sé si puede ser el motivo de que no me funcione, lo que he hecho para suplirlo es poner el pin A0 del M a masa a traves de una R de 10k y con un pulsador y un divisor le cambio (de golpe) a 3,50voltios, si es debido a esto indicadlo por favor, y podeis dejar de leer, ya que hasta mañana no podré seguir (lo coja de casa).

si tema potenciómetro no es la causa:
¿puede ayudarme un osciloscopio? dispongo de uno, pero en casa también, imagino que debo ver impulsos en A y/o B cuando transmita/reciba.

he puesto los codigos, el maestro en el M y el del esclavo en el S, los que hay debajo de


It is your responsibility to turn on the "write enable" pin before and after doing a "send


1:)no entiendo qué quiere decir con que soy el responsable de habilitar el write, ¿debo añadir código? o ¿ya está habilitado con lo que tengo, pines del medio unidos al 4 del arduino?

2:)al mover el potenciometro (hoy pulsador), ¿qué debe hacer? entiendo que dice que la luz se deberia atenuar, pero con una salida digital no se puede hacer esto, y lo unico que hace es parpadear el led 13 del M y el del slave siempre fijo, el tx/rx no se encienden en ninguno, pero si cambio en el M la velocidad y le pongo 28800, el led 13 del M queda fijo, al poner e el S tambien 28800 vuelve a parpadear, pero diferente. ¿significa esto que sí está comunicandose?

3:)sobre este ejemplo, en el codigo pone

}//--(end main loop )---

/*-----( Declare User-written Functions )-----*/

//NONE
//*********( THE END )***********

significa que faltan instrucciones y por eso no hace "nada".
adjunto foto del montaje
por ahora no se calienta nada de las plaquitas, gracias por las respuestas

edito: no sé como poner la foto como hevisto en otros posts, lo tengo subido en un host, pero no sale, ya he probado lo de img, pero sigue sin salir. Gracias y perdón.

Hola, he encontrado esta página donde hay un ejemplo que aunque es unidireccional, de momento sirve para comprobar que las plaquitas funcionan y el montaje está bien. Ahora a partir de ahí a ver qué saco.
pongo los códigos, pero los agradecimientos para el autor, que nosoy yo.

master

int enablePin = 2;  // use pin 2 for enable pin 

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // setup enable pin for server (always high)
  pinMode(enablePin, OUTPUT);
  
  delay(10);
  digitalWrite(enablePin, HIGH);
}

void loop() {
  // send message to slave ("A") with different value
  for (int i = 0; i < 5; i++) {
    switch (i) {
      case 0 : Serial.println("A1000"); break;
      case 1 : Serial.println("A0100"); break;
      case 2 : Serial.println("A0010"); break;
      case 3 : Serial.println("A0001"); break;
    }
    delay(500);
  }
}

slave

int enablePin = 2; // ebanble pin for slave

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // setup enable pin for slave (always low)
  pinMode(enablePin, OUTPUT);
  delay(10);
  digitalWrite(enablePin, LOW);
  // set digital pin 8 - 11 for output
  for (int i = 8; i < 12; i++) {
    pinMode(i, OUTPUT);
  }
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    // make sure this message for slave "A"
    if (inputString.charAt(0) == 'A') {  
      for (int i = 1; i < 5 ; i++) {
        if (inputString.charAt(i) == '1')
          digitalWrite(7 + i, HIGH);
        else
          digitalWrite(7 + i, LOW);
      }
    } 
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read(); 
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    } 
  }
}

saludos y gracias por la atención prestada, no darlo como solucionado aún, por favor, ya que necesito que el master me reciba informacion, aparte de que ahora las salidas son ciclicas y no es lo que yo necesito.

Uhh mi amigo, veo que estas muy perdido y probando 200 sketch por segundo no vas a encontrar la respuesta.
Todos los códigos funcionan asi que debes centrarte en uno y lucharlo hasta hacerlo funcionar.
Si quieres te ofrezco mi ayuda por remoto.
Yo seguiria con el ejemplo y no cambiaría de sketch.

Veamos entonces Conectalos exactamente como dice la página.
Usa los códigos del mismo modo.

Te enviaré un privado y vemos como sigue la cosa.

Perdido no estoy, estoy perdidísimo. Esto del ejemplo que mencionas y fue de los primeros que probé y tomé como muestra, ¿qué debe hacer?

en el de ahora por lo menos toqueteando en el maestro voy manipulando los relés, cambio el orden, se activan dos, etc. y así pretendo averiguar qué hace cada linea. de código. La meta inicial es con interruptores accionar relés remotos y luego un contacto me envíe al master que lo ha "conseguido".
con todo en una placa ya lo tengo (a partir de un ejemplo con pulsadores lo fui desgranando hasta conseguirlo), "solo" me falta transmitir las órdenes a un esclavo que debe estar a 350mts.

es que ningún ejemplo de los que veo hace minimamente lo que quiero, con access lo tuve más facil xD.

gracias

Ahh bueno si el segundo ejemplo funciona trabajemos por ahi. Y yo te ayudo expilcandolo.

int enablePin = 2;  // use pin 2 for enable pin 

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // setup enable pin for server (always high)
  pinMode(enablePin, OUTPUT);
  
  delay(10);
  digitalWrite(enablePin, HIGH);
}

void loop() {
  // send message to slave ("A") with different value
  for (int i = 0; i < 5; i++) {
    switch (i) {
      case 0 : Serial.println("A1000"); break;
      case 1 : Serial.println("A0100"); break;
      case 2 : Serial.println("A0010"); break;
      case 3 : Serial.println("A0001"); break;
    }
    delay(500);
  }

Manda 4 mensajes pero falta un quinto porque va de 0,1,2,3,4 o sea 4 < 5. Falta uno.
Previamente configuró el pin ENABLE como HIGH por eso es unidireccional
Solo basta que lo pongas en el loop.

El esclavo

int enablePin = 2; // ebanble pin for slave

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // setup enable pin for slave (always low)
  pinMode(enablePin, OUTPUT);
  delay(10);
  digitalWrite(enablePin, LOW);
  // set digital pin 8 - 11 for output
  for (int i = 8; i < 12; i++) {
    pinMode(i, OUTPUT);
  }
}

Hasta acá define el pin 2 para habilitar el MAX como maestro/esclavo
Tmb dos variables, un string y otra tipo bool o sea si o no (1 o 0)
El Setup configura el Serial a 9600 bps
setea el pin Enable como salida
retardo de 10 mseg
setea los pines del 8 al 11 como salidas digitales.

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    // make sure this message for slave "A"
    if (inputString.charAt(0) == 'A') {  
      for (int i = 1; i < 5 ; i++) {
        if (inputString.charAt(i) == '1')
          digitalWrite(7 + i, HIGH);
        else
          digitalWrite(7 + i, LOW);
      }
    } 
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

El Loop.
Comienza conque hara algo si StringComplete esta en 1 o TRUE que es lo mismo.

A tu codigo le falta el SerialEvent que es quien lee los datos y los pone en InputString y cuando hay algo cambia el valor de StringComplete de False a True para que se pueda procesar en el loop.

void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read(); 
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    } 
  }
}

Por ultimo dentro de loop una vez que tenemos una detección de comando, llegamos a esto

for (int i = 1; i < 5 ; i++) {
        if (inputString.charAt(i) == '1')
          digitalWrite(7 + i, HIGH);
        else
          digitalWrite(7 + i, LOW);
      }

Esta parte del código barre los strings enviados como caracteres '0' o '1' y cuando es 1 pone en HIGH el pin 8 al 11 que corresponda.

max_saeta:
Saludos
Al igual que surbyte no uso la resistencias. Es mas cuando la coloco me falla la comunicación.

La resistencia es si las distancia es corta 1m 2m. Si es mas si se necesita para balancear la linea

Buenas, he conseguido con un interruptor activar 1 relé en la placa remota, dos tambien pero no en condiciones.

en principio lo que no sé es como desde el master decirle al esclavo como activar una salida.

el original dice

Serial.println("A1000");

las dudas: el"A1000" es que envia en codigo binario? esto corresponderia a al 8, y solo hay 4 relés, en hex tampoco me parece qe sea 4, o no es "nada" de eso?
lo que yo necesito es, por ejemplo y explicado en palabras:


si interruptor 1 activado (o desactivado)
esclavo digitalwrite salida1 low
else
esclavo digitalwrite salida1 high

lo que me funciona, que está supermal es:

if (estado_interruptor == HIGH)
      {
      Serial.println("A1000");
      }
        else
      {
       Serial.println("A0000");
      }

gracias

El primer código solo envia datos seriados.
Ahora que ya resolviste la duda de si funciona o no, veamos como mejorarlo para haga lo que necesitas que haga.

las dudas: el"A1000" es que envia en codigo binario? esto corresponderia a al 8, y solo hay 4 relés, en hex tampoco me parece qe sea 4, o no es "nada" de eso?
lo que yo necesito es, por ejemplo y explicado en palabras:

"A1000" no es binario, ni siquiera "1000" es binario. Luce como tal pero estrictamente son una cadena de caracteres con un prefijo "A" para evitar comandos que no son.

Asi que tu versión del envío de comandos usando el interruptor esta bien, siempre y cuando te asegures que el interruptor este en HIGH o LOW, porque los pulsadores suelen rebotar.

Hola, la A me imaginaba que era para decirle al esclavo que era el modula "A", por otro lado, 1000, por lo menos cuando los dinosaurios, era 8, 111 equivalia al 7 en decimal, 1001 el 9, 1010 el 10, 1011 el 11 y así sucesivamente
saludos

Si 1000 es 8 no te lo discuto pero "A1000" es una cadena de caracteres
si quieres enviar 8 envias simplemente 0x08

Serial.print(0x08); y no Serial.print("A1000");

Hay una gran diferencia.
En un caso como recibo el dato se lo mando a la salida y en el otro debo interpretarla.
Ya se que es semántica pero esto es programación y todos debemos ser precisos.

Disculpas por resucitar el viejo post.... pero tengo una duda sobre este codigo (en realidad tengo muchas dudas pues soy nuevo en arduino).

Estoy intentando conectar dos arduinos a una distancia de 100 metros, uno de ellos debe de pilotar un servomotor (se me cae la señal pwm a pesar de meterle un driver 298n), para saltarme la limitacion de metros que actualmente tengo.

He usado este codigo para aprender la union rs485 (No probé con los 100 metros de cable, solo con 10cm) y ya he entendido el ejemplo y modificado a mi gusto, pero..... tengo una gran duda, se supone que con rs485 se pueden alcanzar grandes distancias de 1000metros o algo mas usando cable trenzado y que aporta corrección de errores, pero esta corrección de errores es a nivel de hardware o software???

Es decir, usando este ejemplo y una gran tirada de cable, en caso de producirse errores, como se comportaria ?? o para que se puedan corregir estos errores es necesario usar algun tipo de libreria (modbus o simple modbus "algo así"), que ya habilite este tipo de corrección??

Gracias por anticipado, saludos

Hola, al final un colega electronico me hizo lo más importante, vamos, el 99% del codigo ya que me fue imposible conseguir absolutamente nada, por lo que no quiero ponerlo aqui, ya que no lo cnsidero mio. En mi caso, con 450 metros de cable, blindado y con un extremo del blindaje a tierra, funciona sin problemas

Me alegro de tu exito en el proyecto efect2000 y gracias por responder, pero no necesito el codigo, necesitaria confirmar que este rs485 es independiente del codigo, es decir, si uso un codigo que transmita mediante un shield arduino rs485 y en el otro extremo hay otro shield rs485, me puedo olvidar de verificar lo que recibo??? ya los shield de por si hacen la correccion necesaria? o es infalible por definición este rs485? siempre respetando las distancias maximas (en mi caso muy por debajo de especificacion) y usando las recomendaciones de cableado existentes.

tanto no puedo ayudarte, proque no lo sé, lo que sí sé es que a veces, por suerte encima de la mesa y con un par de metros de cable, no funcionaba bien del todo con alguna de las plaquitas, por lo que,al igual que puso el que lo hizo un delay de 10ms, yo se lo puse antes de que cortara la transmision, y ya no falló

digitalWrite(pin_control, LOW); // activa transmision de datos
 delay(5);

codigo que me hizo el compañero

delay(10);//con según qué modulitos no enviaba de forma correcta
digitalWrite(pin_control, HIGH);  // desactiva transmision de datos

en mi caso, tuve que poner un transistor inversor (npn) para activar/desactivar, ya que con todos los modulos arduino, así como con todas las plaquitas, el pin de control del rs485 se quedada a valor de unos 3 voltios, como si dentro del arduino, del pin 2 en este caso, no tirara a masa del todo, pero con todos los megas me pasaba, y si cambaiba de pin también. Como no descubrimos qué pasaba, decidí ponerle el transistor y dejaba de transmitis cuando no debia

El código para 485 no tiene grandes misterios. Si quieres un código robusto usa MODBUS que es un protocolo de comunicaciones sobre RS485 con CRC, rechaza paquetes que llegan mal y los reenvía. Claro que tiene toda una estructura para enviar paquetes pero es fácil de aprender.
Se usa en la industria en ambientes muy ruidosos.
Acá no se pide ayuda y luego se la niega cuando se tiene la oportunidad de brindarla. Para mi mala la actitud.
helius, busca en Google : Arduino MODBUS
Aca un par de enlaces Simple Modbus, Modbus tutorial for Arduino, Modbus Master-Slave Library