Proyecto de comunicación serie con Arduino UNO

Hola a todos !

Estoy trabajando en un proyecto de comunicación serie con arduino uno. He estado revisando los posts que hay sobre este tema pero ninguna refleja exactamente mi problema.

Se trata de un sistema que consta de una máquina a la que se encuentra conectados varios dispositivos de tal forma que la máquina envía órdenes a los dispositivos y éstos le comunican una respuesta a dicha orden.

Dicha comunicación se trata de una comunicación half duplex y asíncrona a 9600 baudios, 1bit de start, 8 bits de datos, sin paridad y 1 bit de stop.

Ejemplo:

Orden -> 002 001 001 228 001 023 Respuesta -> 001 000 002 000 253

La orden que transmite la máquina y la posterior respuesta del dispositivo se transmiten por un solo cable, primero la máquina manda la orden completa y a continuación el dispositivo hace lo mismo con la respuesta.

La idea del proyecto es utilizar el Arduino UNO para que simule a los dispositivos, es decir que reciba las órdenes de la máquina y sea capaz de enviar una respuesta a dicha orden.

Hasta ahora he conseguido programar con el IDE de Arduino un programa que lee las órdenes provenientes de la máquina:

#include 

SoftwareSerial mySerial(2, 3); // RX, TX

void setup()  
{
  Serial.begin(9600);
  mySerial.begin(9600); //Iniciamos puerto
  
}

void loop() // run over and over
{

  if(mySerial.available()>0)
  {
     int c = mySerial.read();
     Serial.println(c);
  }  
    
}

Resumiendo conecto el cable de la máquina al arduino al pin digital 2 que he definido como RX mediante la librería SoftwareSerial y el programa es capaz de leer las órdenes perfectamente.El problema viene a la hora de enviar dichas órdenes por el mismo cable.Al intentar conectar el pin digital 3 (definido como TX) al cable que viene de la máquina para transmitir la orden, la comunicación se para y no se leen ni transmiten órdenes.

No sé si habrá algún conflicto al conectar TX, hay algún fallo en la programación..La verdad es que no sé muy bien cómo seguir enfocando el proyecto y por eso estará muy agradecido a que alguien me arrojara algo de luz en este tema.

Muchas gracias y saludos!

PD: Adjunto 2 imágenes para intentar aclarar un poco más el problema.

20150729_124553cambio.jpg|300x225

20150729_124533cambio1.jpg|600x450

si buscas en google "arduino half duplex" encontraras modificaciones de la libreria SoftwareSerial para tu proposito,es cuestion de estudiar los ejemplos que traigan las librerias para saber como funcionan.por ejemplo: https://github.com/nickstedman/SoftwareSerialWithHalfDuplex

Saludos. a.- Estas uniendo dos pines del arduino directamente? b.- Estas usando una comunicacion RS232 directamente al arduino sin utilizar MAX232 o similar? c.- El equipo o maquina usa comandos MODBUS?

Hola !! Muchas gracias por las respuestas.

En primer lugar voy a respoder a jose : La verdad es que desconocía completamente la modificación de la librería SoftwareSerial y agradezco mucho tu aportación. Hasta ahora lo que he podido comprobar es que dicha librería funciona cargando un código en dos dispositivos arduinos distintos que posteriormente se conectarían a través de un cable consiguiendo la comunicación half duplex que queremos. Mi sistema es algo distinto ya que lo que tengo es una CPU que envía datos a traves de un cable y pretendo que el arduino responda a dichos datos. Supongo que todo será cuestión de trabajar con esta librería.

Ahora intentaré contestar a max_saeta:

a. Hasta ahora si estaba uniendo los pines 2 y 3 del arduino (que he configurado con la libreria SoftwareSerial como Rx y Tx) pero creo que la idea de unir directamente los pines no funciona porque no consigo transmitir la respuesta del arduino por Tx.

b. Sí, la idea inicial era conectar directamente el cable que viene de la CPU con los datos al arduino y que éste fuera capaz de transmitir una respuesta a dicha CPU a través del mismo cable. De hecho el arduino lee los datos que llegan de la CPU sin problemas, el problema llega a la hora de trasmitir la respuesta a la CPU.

c. No es exactamente MODBUS, es un protocolo que se llama ccTalk, pero he trabajado con MODBUS y el funcionamiento es similar.

Saludos !!

Sí, la idea inicial era conectar directamente el cable que viene de la CPU con los datos al arduino y que éste fuera capaz de transmitir una respuesta a dicha CPU a través del mismo cable. De hecho el arduino lee los datos que llegan de la CPU sin problemas, el problema llega a la hora de trasmitir la respuesta a la CPU.

Como bien te dijo max_saeta no puedes conectar Arduino y una PC sin una interfaz 232 apropiada p.ej usando un max232 o un max202. Eso no va a funcionar jamás.

Porque dices recien en tu post#3 que es un protocolo similar al modbus que se lllama ccTalk, deberías haberlo comentado en el post#1 al presentar debidamente tu problema? No se si es relevante para tu solución ahora pero toda la información debe exponerse para tener un contexto lo mas completo posible.

Si lees las normas del foro, dicen claramente que se debe exponer debidamente la inquietud.

Finalmente, el código que presentas en tu post#1 no es el código que estas usando no? Porque eso lo encuentras como ejemplo del SoftwareSerial.

Que más puedes aportar para entender mejor todo tu problema?

Hola !!

Muchas gracias por contestar.

Intentaré explicar un poco más en detalle el problema en cuestión.

  • La CPU que transmite los datos no es la CPU de un ordenador portátil o de sobremesa, como comento en el pos #1, la CPU que transmite los datos es una máquina a la que no puedo modificarle software ni hardware. SImplemente la máquina tramsmite unos datos u órdenes mediante protocolo cctalk (half duplex y asíncrona a 9600 baudios, 1bit de start, 8 bits de datos, sin paridad y 1 bit de stop) y espera una respuesta.

  • La idea que tenía inicialmente es que podría programar el puerto serie del arduino para que recibiera las órdenes por el pin Rx y pudiera transmitir la respuesta por Tx, pero me encuentro con el problema que he comentado de que la orden y la respuesta deben ir por el mismo cable.

Entonces, ¿ Es necesaria una interfaz RS232 para la comunicación que pretendo hacer? ¿No basta con usar la interfaz serie del arduino con la librería SoftwareSerial adaptada para half duplex?

Muchas gracias !!

Bueno pero que características tiene la salida del ordenador? Tu dices que has podido leer sin problemas? Lo has visto en un osciloscopio, son niveles TTL o RS232 mas alla que sea algo diferente. Yo ya entendí que todo va y viene por un solo hilo. Asi que MAX232 no tiene sentido. Tiene sentido tal vez un max232 configurado de otro modo pero hay que estudiarlo. No sabemos que envia/recibe ese ordenador de MESA. Tu si?

Que tal esta interfaz ccTalk to PC?

Luego discutimos su adapatación a Arduino.

Esta me gusta mas, y esta resuelta

It uses the protocol in various apparatuses working with the reception / delivery of money to connect the controller to the devices receiving / dispensing money. This vending machines, gaming, payment terminals. This is not the only report from them, but one of the standard. However, nothing prevents its use in other applications, for example for polling the keyboard, an LCD display, etc. (Such options specification even provided). Allows you to connect to one bus a lot of devices, simple to implement. Detailed specifications are on site http://www.cctalk.org/ 4 pdf-files, and with examples of implementations for popular devices (coin acceptor, bill acceptor). In this post I will talk about some of the main points that are not clear at first reading the specification.

To transfer using two wires (signal and ground). Next - a regular UART. Reception and transmission lines are combined into one (as in the 1-wire and similar single-wire serial asynchronous interface). The converter circuit (of the specification):

Active state on the bus - 0. In the absence of transfer - 1 logic level "0" - is from 0V 1V. "1" - from 3.5V to 5V. While some may Soup pull the tire to its power (as it is up to 24V) and it would have worked too. Speed ​​standard 9600 baud, 8 data bits, no parity, and flow control. At the network layer protocol is a simple master slave. All devices on the bus has its own unique address. Standard addresses are set in accordance with specification for each device type. For example, a coin acceptor have an address 2. Normally, all devices must be setup to select the address in case you need to hang several identical devices on the same bus (either through a program on a PC or setting a jumper). Master bus is always the same and address 1. A device (slave) can send data only in response to a request from the master thus the entire network is controlled by the master. As in the Modbus or USB. In response to a request for master slave responds with either a confirmation or response to the sending of the data (if the data were requested). General specification allows multiple devices to a single address and distinguish them by delays, but it's crutches to support primitive devices without changing addresses. In normal operation, the master periodically polls all the Slaves (every 100-200ms). For a team notes- coin-operated read new events (inserted coins, bills). While the slave receives any requests from the master (this can be simple poll), he knows that the master is alive and can accept coins / bills. Once a slave ceases to accept requests from the master for some time (a few seconds, all in different ways), he decides that the master is dead, and no longer accept coins / bills (or other types of some its own logic, which does not allow a device to interact with the user ). For example, the first swallow kupyurniki bill, send information about it and are in response to the following command: accept or return. If the master fell off after ingestion bills and answer what to do has not been received, then a few seconds later it returns kupyurnik. Since all devices sold protection against unpleasant situations to the user, such as this:

If there are several Slaves and a survey carried out in one cycle, it is necessary to watch that no one blocked this cycle. For example, if the survey apparatus A delay occurs a timeout poll the device B, the device B decides that the master is dead, and will need to re-initialize it ustroytsvo when the master comes to survey B. For typical devices ccTalk (monetniki, kupyurniki, hoppers) standardized all the team and the whole process of working with them, so do not need to deal with the peculiarities of a particular manufacturer. While the features may be, but not significantly so that we can change in a running machine monetnik to another producer and everything should continue to work. Features initialization and interrogation of certain types of devices are described in detail in the specification or may fall into the datasheet for the device. The software implementation of the protocol can be found ready, or almost ready. However, the simplicity of the protocol makes it possible to implement it in any language quickly enough. I used Python and took as a basis for this project: https://bitbucket.org/schryer/cctalk . I had to fix a handful of bugs and to add a lot of code to support all the necessary devices. The most annoying bug (or the author's intention - as he used feature USB2UART converter) - is a software flow control enabled. Because he had a terrible glitches, such as strict on the 16th report on the introduction of a coin lost 1 byte and everything stopped working. Did xonxoff = False to initialize the serial port. Also useful sniffer: https://github.com/Baldanos/ccTools . Also on the python. That's all I wanted to briefly tell you about the protocol. Turned out he was better than I imagined when I started working with him. At least the number of problems was less than expected at the beginning. - Update = = - Something strange is going on with the site and load specifications. In any case, I duplicate spec version 4.7: Part 1 , Part 2 , Part 3 , Part 4

Acá una buena referencia con Arduino Teensy

Muchas gracias por la respuesta surbyte.

A la interfaz "ccTalk to PC" que me comentas en el link ya le había echado un vistazo. De hecho incluso me he puesto en contacto con la persona que la elaboró y le he comentado mi proyecto. El me propuso que montara la interfaz rs232 para conectar el ccTalk data al PC directamente.

Cuando le comenté que mi idea era usar Arduino me contestó lo siguiente:

El bus cctalk que "sale-entra" de la cpu de la máquina seguro que es a 0-5v. Y casi seguro: 9600 baudios, 1 bit de start, 8 bits de datos, sin paridad, y 1 bit de stop. Esta es la comunicación serie que también he visto siempre con un arduino. Así que hacer la conexión y el montaje cpu-arduino que tienes en mente, me parece perfectamente factible. Directamene pines 0 y 1(Rx y Tx) unidos al cctalk data. El arduino estará leeyendo Rx constantemente a la espera de alguna trama por cctalk data. Cuando reciba algo tendrá que contestar por Tx que irá también al cctalk data. Aquí observa que el Rx del arduino también leerá lo que emite Rx (puesto que están puenteados). Ten en cuenta ese "eco" para la programación... Hacer alguna trama simple parece relativamente fácil. Luego ya depende de la habilidad del programador... Pero programar el arduino (compilación, pruebas y errores) me parece bastante lío e incómodo, engorroso y confuso, si no se domina mucho lo que se está haciendo.

Por eso busco ayuda en este foro, para ayudarme con la programación en arduino. Hasta ahora he conseguido ha sido:

  • De la CPU de la máquina que lanza las órdenes sale un cable con los datos ccTalk como ya he comentado. Pues este cable lo conecto al pin 2 del arduino (RX) y con este código :
#include 

SoftwareSerial mySerial(2, 3); // RX, TX

void setup()  
{
  Serial.begin(9600);
  mySerial.begin(9600); //Iniciamos puerto
  
}

void loop() // run over and over
{
  int datos,origen,cabecera,destino;
  if(mySerial.available()>0)
  {
     int c = mySerial.read();
     if (c == 4)
     {
       int destino = c;
       Serial.print("Destino: ");
       Serial.println(destino);
       int suma = c;
       while (suma < 256)
       {
          c = mySerial.read();
          suma = suma + c;
          switch (c){
            case 0:{
              int datos = c;
              Serial.print("Datos: ");
              Serial.println(datos);
              }
              break;
            case 1:{
              int origen = c;
              Serial.print("Origen: ");
              Serial.println(origen);
              }
              break;
            case 236:{
              int cabecera = c;
              Serial.print("Cabecera: ");
              Serial.println(cabecera);
              }
              break;
            case 163:{
              int cabecera = c;
              Serial.print("Cabecera: ");
              Serial.println(cabecera);
              }
              break;
          }
       }
      if (suma == 256)
        {
          if( cabecera==236 )
            {
              mySerial.write((int) 1);
              mySerial.write((int) 1);
              mySerial.write((int) 4);
              mySerial.write((byte) 0);
              mySerial.write((byte) 0);
              mySerial.write((int) 250);
              Serial.println("Hola");
            }
        } 
     }
     if (c == 2)
     {
       int destino = c;
       Serial.print("Destino: ");
       Serial.println(destino);
       int suma = c;
       while (suma < 256)
       {
          c = mySerial.read();
          suma = suma + c;
          switch (c){  
            case 1:{
              if (suma == 3)
                {
                  int datos = c;
                  Serial.print("Datos: ");
                  Serial.println(datos);
                }
              else if (suma == 4)
                {
                  int origen = c;
                  Serial.print("Origen: ");
                  Serial.println(origen);
                }
               else if (suma == 233)
                {
                  int dato = c;
                  Serial.print("Dato: ");
                  Serial.println(dato);
                }  
            }
              break;
            case 228:{
              int cabecera = c;
              Serial.print("Cabecera: ");
              Serial.println(cabecera);
              }
              break;
            case 0:{
              int dato = c;
              Serial.print("Dato: ");
              Serial.println(dato);
              }
              break;
          }
       }    
     }  
  }

}

Puedo ver en el monitor serial del IDE arduino lo siguiente :

|500x423

Un mensaje ccTalk se compone de los siguientes datos:

[Destino][NºDatos][Origen][Cabecera][Dato1]...[Checksum] por lo que se comprueba perfectamente que con esta conexión el arduino recibe correctamente los datos por Rx. El problema viene al intentar escribir la respuesta por Tx.

Si el Arduino recibiera por Rx el siguiente mensaje : 4 0 1 236 15. La respuesta por Tx debería ser 1 1 4 0 0 250, que es lo que intento hacer cuando envío el comando "mySerial.write" pero el sistema no funciona.

No sé si el problema es de pregramación en el arduino, si el problema viene al intentar unir Rx con Tx y no saber manejar el "eco" de la señal o si tengo que montar la interfaz RS232 obligatoriamente.

Espero que esto aclare algunas dudas y pueda sacar adelante el proyecto y no ir dando palos de ciego..

Muchas gracias !!