miércoles, 30 de enero de 2013

Libreria Modbus Serial para Arduino (1/2)

En vista de que no encontré una implementación completa de la librería modbus para Arduino decidí hacer una librería que posea al menos todas las funciones mínimas necesarias para leer y escribir en una remota.

Ahora disponible en Github:
https://github.com/fernandezajp/ARDUModBus.git  

Todas la pruebas fueron realizadas utilizando el simulador ModSim el cual nos garantiza que funcionaría perfectamente un hardware real.

Las funciones marcadas en azul corresponden a las implementadas en esta librería


   - Función 1 Read Coil Status
   - Función 2 Read Input Status
   - Función 3 Read Holding Registers
   - Función 4 Read Input Registers
   - Función 5 Force Single Coil
   - Función 6 Preset Single Register
   - Función 7 Read Exception Status
   - Función 8 Diagnostics
   - Función 9 Program 484
   - Función 10 Poll 484
   - Función 11 Fetch Communication Event Counter
   - Función 12 Fetch Communication Event Log
   - Función 13 Program Controller
   - Función 14 Poll Controller
   - Función 15 Force Multiple Coils
   - Función 16 Preset Multiple Registers
   - Función 17 Report Slave ID
   - Función 18 Program 884/M84
   - Función 19 Reset Comm. Link
   - Función 20 Read General Reference
   - Función 21 Write General Reference
   - Función 22 Mask Write 4X Register
   - Función 23 Read/Write 4X Registers
   - Función 24 Read FIFO Queue

A continuación detallamos las tramas de cada función con un ejemplo



Funcion: Read Coil Status (FC=01)


Request: Esta trama realiza la petición del estado de los (discrete coils) del 20 al 56 del dispositivo esclavo con dirección 17.
11 01 0013 0025 0E10
11: Dirección del Esclavo (17 = 11 hex.)
01: Código de la Función (read Coil Status)
0013: Dirección del dato del primer coil para leer. (Coil 20 - 1 = 19 = 13 hex)
0025: Número de coils para leer. (del 20 al 56 =  37 = 25 hex) 
0E10: El CRC (cyclic redundancy check) para manejo de errores.
Response
11 01 05 CD6BB20E1B 45E6 
11: Dirección del esclavo (17 = 11 hex)
01: Código de la función (read Coil Status)
05: Número de data bytes (37 Coils / 8 bits por byte = 5 bytes)
CD: Coils 27 - 20 (1100 1101)
6B: Coils 35 - 28 (0110 1011)
B2: Coils 43 - 36 (1011 0010)
0E: Coils 51 - 44 (0000 1110)
1B: 3 bits no usados & Coils 56 - 52 (0001 1011)
45E6: El CRC (cyclic redundancy check).


Función: Input Status (FC=02)




Request: Esta trama realiza la petición del estado de los (discrete inputs) del 10197 al 10218 del dispositivo esclavo con dirección 17.
11 02 00C4 0016 BA08
11: Dirección del Esclavo (17 = 11 hex.)
02: Código de la Función (read Input Status).
00C4: Dirección de la primera entrada. (10197 - 10001 = 196 = C4 hex.)
0016: Número total de coils de la petición. (197 al 218 =  22 = 16 hex.)
BA08: El CRC (cyclic redundancy check) para manejo de errores.
Response
11 02 03 CD6B32 45C4
11: Dirección del Esclavo (17 = 11 hex.)
02: Código de la función (read Input Status)
03: El numero total de bytes (22 Inputs / 8 bits per byte = 3 bytes)
CD: Entradas Discretas 10204 -10197 (1010 1100)
6B: Entradas Discretas 10212 - 10205 (1101 1011)
32: 2 espacios vacíos & Entradas Discretas 10218 - 10213 (0011 0101)
45C4: El código CRC (cyclic redundancy check).



Función: Read Holding Registers (fc3)




Request: Esta trama realiza la petición del estado de la salida analógica holding registers desde 40108 a 40110 del dispositivo esclavo con dirección 17.
11 03 006B 0003 7611
11: Dirección del Esclavo (17 = 11 hex.)
03: Código de la función (read Analog Output Holding Registers)
006B: Dirección del Dato del primer registro requerido. (40108-40001 = 107 = 6B hex.)
0003: Número total de registros requeridos. (3 registros desde 40108 al 40110) 
7611: El CRC (cyclic redundancy check) manejo de errores.
Response
11 03 06 AE41 5652 4340 49AD
11: Dirección del Esclavo (17 = 11 hex)
03: Código de la función (read Analog Output Holding Registers)
06: Número de bytes (3 registros x 2 bytes por cada uno = 6 bytes)
AE41: Contenido del registro 40108
5652: Contenido del registro 40109
4340: Contenido del registro 40110
49AD: El CRC (cyclic redundancy check).



Función: Read Input Register (fc4)




Request: Esta trama realiza la petición del estado de la entrada analógica input registers #30009 del dispositivo esclavo con dirección 17.
11 04 0008 0001 B207
11: Dirección del Esclavo (17 = 11 hex.)
04: Código de la Función (read Analog Input Registers)
0008: Dirección de dato del primer registro requerido. (30009-30001 = 8)
0001: El numero de registros para leer. (leer 1 registro) 
B207: The CRC (cyclic redundancy check) for error checking.
Response
11 04 02 000A F8F4
11: Dirección del Esclavo (17 = 11 hex)
04: El Código de Función (read Analog Input Registers)
02: Numero de bytes de datos (1 registro x 2 bytes por registro = 2 bytes)
000A: Contenido del registro 30009
F8F4: El código CRC (cyclic redundancy check).



Función: Force Single Coil (fc5)




Request: Este comando escribe el registro del discrete coil # 173 a ON en el dispositivo esclavo con dirección 17.
11 05 00AC 00FF 4F08
11: Dirección del Esclavo (17 = 11 hex)
05: Código de la Función (Force Single Coil)
00AC: Dirección de Dato del coil. (# 173 - 1 = 172 = AC hex)
00FF: Estado a escribir ( 00FF = ON,  0000 = OFF ) 
4F08: El Código CRC (cyclic redundancy check) para manejo de errores.
Response
11 05 00AC 00FF 4F3B
11: Dirección del Esclavo (17 = 11 hex)
05: Código de la Función (Force Single Coil)
00AC: Dirección de Dato del coil. (coil# 173 - 1 = 172 = AC hex)
00FF: Estado actualizado ( 00FF = ON,  0000 = OFF ) 
4F3B: El Código CRC (cyclic redundancy check) para manejo de errores.



Función: Preset Single Register (fc6)




Request: Este comando escribe el contenido del analog output holding register # 40002
al dispositivo esclavo con direccion 17.
11 06 0001 0003 9A08
11: Dirección del Esclavo (17 = 11 hex)
06: Código de la Función (Preset Single Register)
0001: Dirección del registro de Dato. (# 40002 - 40001 = 1 )
0003: Valor a escribir.
9A08: El código CRC (cyclic redundancy check) para manejo de errores.
Response: La respuesta normal es un echo del request.
11 06 0001 0003 9A9B
11: Dirección del Esclavo (17 = 11 hex)
06: Código de la Función (Preset Single Register)
0001: Dirección del registro de Dato. (# 40002 - 40001 = 1 )
0003: Valor escrito.
9A9B: El código CRC (cyclic redundancy check) para manejo de errores.



Función: Force Multiple Coils (FC=15)




Request: Este comando escribe el contenido discreto de una serie de 10 coils desde  #20 al #29 en el esclavo con direccion 17.
11 0F 0013 000A 02 CB01 BF08
11: Dirección del Esclavo (17 = 11 hex.)
0F: Código de la Función (Force Multiple Coil, 15 = 0F hex.)
0013: Dirección del primer coil. (# 20 - 1 = 19 = 13 hex.)
000A: Número de coils para ser escrito (10 = 0A hex)
02: Numero de bytes de datos (10 Coils / 8 bits por byte = 2 bytes)
CB: Coils 27 - 20 (1100 1011
01: 6 espacios vacios & Coils 29 - 28 (0000 0001
BF08: El Código CRC (cyclic redundancy check) para manejo de errores.

Response
11 0F 0013 000A 2699
11: Dirección del Esclavo (17 = 11 hex)
0F: Código de la Función (Force Multiple Coil, 15 = 0F hex)
0013: Dirección del primer coil. (coil# 20 - 1 = 19 = 13 hex)
000A: Número de coils para ser escrito (10 = 0A hex)
2699: El Código CRC (cyclic redundancy check) para manejo de errores.



Función: Preset Multiple Registers (FC=16)




Request: Este comando escribe el contenido de 2 analog output holding registers # 40002 & 40003 en el esclavo con dirección 17.
11 10 0001 0002 04 000A 0102 C608
11: Dirección del Esclavo (17 = 11 hex)
10: Código de la función (Preset Multiple Registers 16 = 10 hex)
0001: Dirección del primer registro. (# 40002 - 40001 = 1 )
0002: Numero de registros para escribir.
04: Numero de bytes (2 registros x 2 bytes por cada registro = 4 bytes)
000A: Valor para escribir para el registro 40002
0102: Valor para escribir para el registro 40003
C608: El código CRC (cyclic redundancy check) para el manejo de errores.
Response
11 10 0001 0002 1298
11: Dirección del Esclavo (17 = 11 hex)
10: Código de la función (Preset Multiple Registers 16 = 10 hex)
0001: Dirección del primer registro. (# 40002 - 40001 = 1 )
0002: Número de bytes escritos.
1298: El Código CRC (cyclic redundancy check) para manejo de errores


Ver Parte 2 En la siguiente entrada esta un pequeño ejemplo de como se usa

http://fernandezajp.blogspot.com/2013/07/uso-de-la-libreria-modbusserial.html

13 comentarios:

  1. Muy bueno!!!!
    Pero como se conecta arduino?

    ResponderEliminar
  2. Tomas 2 pines del arduino uno RX y el TX, en mi caso particular tome el 4(RX) y el 5(TX) con la libreria SoftSerial de Arduino la conecte al un max3232 para convertirla a RS232 y listo funciona con la Remota

    ResponderEliminar
  3. Tengo algunas dudas.
    La librería solo se puede utilizar con serial por software.
    Podrias poner algun ejemplo de como se utiliza.

    Saludos y gracias.

    ResponderEliminar
  4. Ok perfecto voy a colocar un ejemplo desde cero, solo deme un chance estoy muy ocupado; antes de 15 dias podria publicarlo

    ResponderEliminar
  5. La explicación está muy bien, ¿podrías hacer el esfuerzo final de publicar un ejemplo práctico?.
    Saludos, estamos en contacto.

    ResponderEliminar
    Respuestas
    1. listo http://fernandezajp.blogspot.com/2013/07/uso-de-la-libreria-modbusserial.html

      Eliminar
  6. La libreria se ve buena, pero ni un ejemplo! como sabremos utilizarla! pueden colocar un ejemplo por lo menos? por favor

    ResponderEliminar
    Respuestas
    1. listo http://fernandezajp.blogspot.com/2013/07/uso-de-la-libreria-modbusserial.html

      Eliminar
  7. Pregunta, yo lo que quiero hacer es leer un medidor que usa modbus - rtu rs485, leerlo con el arduino y guardarlo en una sd con arduino..

    Veo que esto lo que hace es que el arduino lee via rs232 (la computadora) algunos parametros, eso se podria transformar a que en vez de poner la PC le conecto el medidor (A y B) y leo sus holding registers ???

    saludos y gracias de antemano!

    ResponderEliminar
    Respuestas
    1. Si lee via rs232 porque uso la PC para emular la remota sin embargo no hay ningun problema en usar un medidor real con rs485 solo necesitaria cambiar el conversor por ejemplo puede usar el https://www.sparkfun.com/products/10124; por otra parte debido a que el arduino tiene poca memoria yo lo complemento con una tarjeta micro sd, de hecho lo he trabajado así en un proyecto real solo hay que ser muy cuidadoso con el tamaño del programa ya que las librerias de manejo de sd consumen bastantes bytes.

      Eliminar
  8. Hola oie me podrias decir q programa usaste para generar el .h y el .cpp?

    ResponderEliminar
    Respuestas
    1. Nada especial la IDE estándar del Arduino

      Eliminar
    2. Se me paso decirte que si en la IDE de arduino marcas el boton que indica una flecha hacia abajo (esta ubicado en la parte superior derecha debajo de la lupa) le dices nueva pestaña, ahi creas el archivo .h y el .cpp

      Eliminar