recepcion de trama de datos hexadecimal por puerto serial

Buenas tardes a todos, de antemano gracias por sus aportes y ayuda a todos en este foro.

Como en muchos casos llega alguien a este foro que comprende poco de programación, es mi caso :(.

Tengo un proyecto en el cual tengo un dispositivo esclavo que le solicita información a varios sensores y la reenvía al maestro (mi PC) mediante un gateway conectado a la pc por ip o rs485 (cualquiera de los dos).

Todos estos dispositivos vienen diseñados y configurados de fabrica y funcionan muy bien solos.

Lo que yo quisiera hacer es poder colocar un Arduino UNO junto con los sensores para activar un relé.

El dispositivo que controla los sensores utiliza el siguiente frame para solicitar la información 01 04 0006 0002 0090

Donde entiendo que:

01 ->ID DEL SENSOR ESCLAVO.

04 ->Function Code o la función a realizar (read input register) en el caso de los sensores. Con el arduino quisiera usar la función 06 o la 05, aun no lo tengo claro. Seria para activar un relé con una salida digital del mismo.

0006 -> el registro en el cual se encuentra la información (esto en el caso de los sensores, en el arduino como puedo saber cual registro debo utilizar por ejemplo para la salida digital 5?).

0002 -> la longitud de los datos a leer

0090 -> CRC16 o checksum

Al arduino yo le daría la dirección número 6 entonces creo que mi trama quedaria algo asi 06 06 xxxx xxxx CRC16

Las X son porque aun no tengo claro como saber que registro debo modificar ni la longitud que este tendría (o si en este caso al ser funcion de escritura no debo colocar la longitud), por ejemplo si quisiera activar la salida digital 05.

Por otro lado, en el arduino UNO yo estaria recibiendo un string en ascii porque entiendo que asi funciona el puerto serial, como podria leer la trama de bytes completa para poder realizar las operaciones necesarias (trama de bytes hexadecimales)?

De antemano muchas gracias por la ayuda que me puedan brindar.

Eso es MODBUS que tiene un formato establecido para pedir datos.

Hay librerías para ello solo buscando en Google: Arduino Modbus Master o Slave, especifica que buscas.

Hola si, gracias. He podido comunicarme utilizando el siguiente código que consegui en la web:

 Modbus slave simple example

    Control and Read Arduino I/Os using Modbus serial connection.

    This sketch show how to use the callback vector for reading and
    controleing Arduino I/Os.

    * Controls digital output pins as modbus coils.
    * Reads digital inputs state as discreet inputs.
    * Reads analog inputs as input registers.

    The circuit: ( see: ./extras/ModbusSetch.pdf )
    * An Arduino.
    * 2 x LEDs, with 220 ohm resistors in series.
    * A switch connected to a digital input pin.
    * A potentiometer connected to an analog input pin.
    * A RS485 module (Optional) connected to RX/TX and a digital control pin.

    Created 8 12 2015
    By Yaacov Zamir

    https://github.com/yaacov/ArduinoModbusSlave

*/

#include <ModbusSlave.h>

/* slave id = 1, rs485 control-pin = 8, baud = 9600
 */
#define SLAVE_ID 1
#define CTRL_PIN 8
#define BAUDRATE 9600

/**
 *  Modbus object declaration
 */
Modbus slave(SLAVE_ID, CTRL_PIN);

void setup() {
    /* set some pins for output
     */
    pinMode(10, INPUT);
    pinMode(11, OUTPUT);
    pinMode(12, OUTPUT);
    pinMode(13, OUTPUT);

    /* register handler functions
     * into the modbus slave callback vector.
     */
    slave.cbVector[CB_WRITE_COILS] = writeDigitalOut;
    slave.cbVector[CB_READ_DISCRETE_INPUTS] = readDigitalIn;
    slave.cbVector[CB_READ_INPUT_REGISTERS] = readAnalogIn;

    // set Serial and slave at baud 9600.
    Serial.begin( BAUDRATE );
    slave.begin( BAUDRATE );
}

void loop() {
    /* listen for modbus commands con serial port
     *
     * on a request, handle the request.
     * if the request has a user handler function registered in cbVector
     * call the user handler function.
     */
    slave.poll();
}

/**
 * Handle Force Single Coil (FC=05) and Force Multiple Coils (FC=15)
 * set digital output pins (coils).
 */
uint8_t writeDigitalOut(uint8_t fc, uint16_t address, uint16_t length) {
    // set digital pin state(s).
    for (int i = 0; i < length; i++) {
        digitalWrite(address +i, slave.readCoilFromBuffer(i));
    }

    return STATUS_OK;
}

/**
 * Handel Read Input Status (FC=02)
 * write back the values from digital in pins (input status).
 *
 * handler functions must return void and take:
 *      uint8_t  fc - function code
 *      uint16_t address - first register/coil address
 *      uint16_t length/status - length of data / coil status
 */
uint8_t readDigitalIn(uint8_t fc, uint16_t address, uint16_t length) {
    // read digital input
    for (int i = 0; i < length; i++) {
        slave.writeCoilToBuffer(i, digitalRead(address + i));
    }

    return STATUS_OK;
}

/**
 * Handel Read Input Registers (FC=04)
 * write back the values from analog in pins (input registers).
 */
uint8_t readAnalogIn(uint8_t fc, uint16_t address, uint16_t length) {
    // read analog input
    for (int i = 0; i < length; i++) {
        slave.writeRegisterToBuffer(i, analogRead(address + i));
    }

    return STATUS_OK;
}

Puedo leer los registros de entrada (FC: 02) utilizando el siguiente frame de datos:

01 02 00 00 00 0E +CRC16

Ahora lo que quisiera hacer activar los leds que estan en el puerto 11 y 12 del arduino uno pero no me funciona y quizas sea porque no estoy utilizando los registros adecuados.

01 05 00 0B FF 00 +CRC16 para activar pin 11

como puedo saber a cuales registro debo dirigirme para activar esas salidas?

Listo, tenia un problema en la conexión pero ya lo solucioné. Todo funciona bien con ese código por si alguien mas nuevo en esto se topa con este topic y quiere probar. Es un excelente código para empezar, sirve para un programar un arduino como esclavo.