MODBUS RS485

  • 16 Respuestas
  • 2985 Vistas

vitor14

  • Novato
  • *
  • Mensajes: 8
MODBUS RS485
« : agosto 13, 2014, 16:58:30 pm »
Hola! Queria saber como conectar desde el TTL hacia el max485, para poder usar el modbus.
Saludos!

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1722
  • Soporte Técnico
Re: MODBUS RS485
« Respuesta #1 : agosto 13, 2014, 17:58:12 pm »
Buenas tardes Victor,

En la foto que te adjunto, esta como deberías conectar desde el puerto de expansión HP2
del PLC a tu MAX-485.

Procura utilizar algún conector adecuado desde el puerto a tu placa, para evitar cortos.

Recorda que debes declarar la interfaz RS-485 que utilizas desde StxLadder, como explica la nota de aplicación AN026 pagina 5.

Lo mismo cuando inicialices el puerto en Pawn, utiliza la constante MB_RTU_INTERFACE_RS485 para
que el software entienda el tipo de interfaz RS485.

Ejemplo:

MbRtuClInit(9600, SERIAL_8E1, 10, MB_RTU_INTERFACE_RS485)

Quedamos a disposición.

« Última Modificación: agosto 13, 2014, 18:02:43 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

vitor14

  • Novato
  • *
  • Mensajes: 8
Re: MODBUS RS485
« Respuesta #2 : agosto 19, 2014, 19:06:11 pm »
Hola:
Pongo lo siguiente:

Código: [Seleccionar]
if(MbWaitResponse == 0)
{
// Enviar peticion para leer "Holding Registers".
if(error =MbRtuClSendReadHoldingReg(247, 1000, 1) < 0)
{
// Error en transmision.
LcdPrintf(0,1, "ERROR... %d", error)
DelayMS(5000)
}
}
 else
{
 WaitResponse = 1
  LcdPrintf(0,1, "Esperando respuesta... ")
 DelayMS(5000)
}

Pero me da error 1.
Que puede ser?

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1722
  • Soporte Técnico
Re: MODBUS RS485
« Respuesta #3 : agosto 19, 2014, 20:13:17 pm »
Según la documentación de la función, si retorna "-1", es porque se envío el comando ModBus, pero
la librería esta ocupada esperando la respuesta de una transacción MosBus previa.

Debes estar llamando dos o mas veces seguidas la función (o hay una transacción en curso realizada por otra funcion).

Por otro lado, me parece que tendría mas sentido el código como lo reescribo a continuación, ademas presta atención donde pongo las llaves { } y como compruebo el error en el if con paréntesis en (error = func()) < 0 ya que primero asignas valor a variable y luego comprobas si es menor a 0:


if(MbWaitResponse == 0)
{
   // Enviar peticion para leer "Holding Registers".
   if((error = MbRtuClSendReadHoldingReg(247, 1000, 1)) < 0)
   {
      // Error en transmision.
      LcdPrintf(0,1, "ERROR... %d", error)
      DelayMS(5000)
   }
   else
   {
      WaitResponse = 1
      LcdPrintf(0,1, "Esperando respuesta... ")
      DelayMS(5000)
   }
}

Quedamos a disposición.
« Última Modificación: agosto 19, 2014, 20:57:49 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

vitor14

  • Novato
  • *
  • Mensajes: 8
Re: MODBUS RS485
« Respuesta #4 : agosto 28, 2014, 12:23:05 pm »
Hola, ya pude solucionar el tema de la comunicación, tenia mal las masas.
Ahora que responde el equipo me responde -7, que según su manual es: "Error, se recibió un código ModBus de excepción."
Que puedo hacer?

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1722
  • Soporte Técnico
Re: MODBUS RS485
« Respuesta #5 : agosto 28, 2014, 12:48:57 pm »
Eso significa que estas enviando un comando (función) o dirección o valor de datos ilegal al esclavo ModBus RTU.

Fíjate obtener el código de excepción que devuelve con:

LcdPrintf(0,1, "Exception: %03d", MbRtuClGetExceptionCode())   

Y compara dicho valor con la tabla 2, pagina 4 de la nota AN026 para orientarte.

Ejecuta la función después de que la transacción retorna.

Avísame como te va.

 
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

vitor14

  • Novato
  • *
  • Mensajes: 8
Re: MODBUS RS485
« Respuesta #6 : agosto 28, 2014, 13:20:38 pm »
Me da error 002 (dirección invalida).
Tengo el datasheet del sensor y es correcta la dirección, tambien probe con otras pero me da el mismo error:

if(MbRtuClSendReadHoldingReg(247, 1000, 1) < 0)


Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1722
  • Soporte Técnico
Re: MODBUS RS485
« Respuesta #7 : agosto 28, 2014, 18:06:13 pm »
Es para el sensor de GAS que me pasaste antes?.

Inicializas bien los parámetros de comunicación? por lo que entiendo es:

MbRtuClInit(19200, SERIAL_8E1, 10, MB_RTU_INTERFACE_RS485)

Lo tenes configurado al sensor de GAS para utilizar 19200 bps, paridad even, 8 bits datos y 1 stop bit ?.

Por lo que leo en las demás direcciones utilizan una dirección base que cargas en el registro 1000, que tiene
un valor por defecto de 40000.

Proba hacer una lectura en el registro 40001, por ejemplo:

if(MbRtuClSendReadHoldingReg(247, 40001, 1) < 0)

También, decime que valor te devuelve esta función (llámala después de que recibís la respuesta del sensor):

LcdPrintf(0,1, "Func: 0x%X", MbRtuClGetFuncCode())

Quiero ver si se corresponde con la función enviada.
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

vitor14

  • Novato
  • *
  • Mensajes: 8
Re: MODBUS RS485
« Respuesta #8 : agosto 28, 2014, 18:23:30 pm »
Ya pude resolver hace un ratito lo de leer, lo que no puedo solucionar es escribir.
Paso el codigo:

Código: [Seleccionar]
// -------------------------------------------------------------------------
// Funcion: PlcMain ()
// Funcion principal.
// -------------------------------------------------------------------------

// Crear variable que indica si esperamos una respuesta del Servidor.
new WaitResponse = 0
// Variable para almacenar datos.
new RxData[4]
// Crear variable para almacenar estado.
new MbStat



PlcMain()
{
 // Inicializar display.
 LcdClear()
 LcdPrintf(0,1, "ModBus RTU")
 
 // Inicializar Cliente ModBus RTU.
 MbRtuClInit(19200, SERIAL_8E1, 10, MB_RTU_INTERFACE_RS485)
 // Activar evento "OnMbRtuClientRx" para determinar respuesta
 // del servidor.
 
 if(MbRtuClSetRxEvent() < 0)
 {
 LcdClear()
 LcdPrintf(0,1, "Error, Evento")
 DelayS(5)
 }
 for(;;) 
{
DelayS(5)
if( MbRtuClSendWriteSingle (247, 40140, 11) < 0 )
{
 // Error.
}

}
}



// -------------------------------------------------------------------------
// Funcion: @OnMbRtuClientRx()
// Procesa una respuesta del servidor ModBus RTU (escritura/lectura).
// -------------------------------------------------------------------------
@OnMbRtuClientRx()
{
 new MbStat
 
 // Obtener Estado de Libreria.
 MbStat = MbRtuClGetLibStatus()
 
 // Mostrar Estado de Libreria.
 LcdPrintf(0,0, "Stat = %03d", MbStat)
 LcdPrintf(0,1, "Exception: %03d", MbRtuClGetExceptionCode())   
 
 // Leer registros recibidos si no hay error.
 if(MbStat == 0)
 {
 // Leer Registros.
 MbRtuClGetRxReg(RxData, 0, 4, 1)
 
 // Mostrar valores de registros en LCD.
 LcdPrintf(0,1, "%04d %04d %04d", RxData[0], RxData[1], RxData[2])
 
 // Respuesta recibida, no esperar más.
 WaitResponse = 0
 }
}

Me responde error 7 excepción 001, (libreria ocupada).

Y despues de un ratito me pone:
PLC RETURN CODE C:7 R:500

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1722
  • Soporte Técnico
Re: MODBUS RS485
« Respuesta #9 : agosto 28, 2014, 19:11:28 pm »
Si, te da ese error porque la función esta mal escrita tal como figura en la nota de aplicación AN026 (error nuestro).

Debes reemplazar:

if( MbRtuClSendWriteSingle (247, 40140, 11) < 0 )

Por:

if( MbRtuClSendWriteReg(247, 40140, 11) < 0 )

Ya vamos a actualizar la AN026 en estos días con estas correcciones.

Por otro lado, en tu código, la variable "new MbStat" esta definida dos veces, borra la que tiene alcance global.

Te adjunto un proyecto Pawn con lo que queres realizar escrito de una forma mas
prolija, fíjate si te funciona o que errores te devuelve, y avísanos.
« Última Modificación: agosto 28, 2014, 21:27:09 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1722
  • Soporte Técnico
Re: MODBUS RS485
« Respuesta #10 : agosto 29, 2014, 12:44:59 pm »
Ya fue actualizada y corregida la nota de aplicación AN026, revisión 02.
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

vitor14

  • Novato
  • *
  • Mensajes: 8
Re: MODBUS RS485
« Respuesta #11 : septiembre 05, 2014, 15:39:32 pm »
Ya funciona todo ok.

Solo una cosa, como puedo activar este tipo de coils? se puede?


Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1722
  • Soporte Técnico
Re: MODBUS RS485
« Respuesta #12 : septiembre 05, 2014, 16:17:24 pm »
Si podes, pero es confuso porque dice "Coils".

Normalmente si dice coils, cada direccion deberia representar un bit, y se deberia poder modificar
con la funcion MbRtuClSendWriteCoil().

Sin embargo, viendo la tabla, lo toma como un Word, que es de 16-bits. En otras palabras,
un registro normal.

Entonces, para modificar un solo bit, primero debes leer el registro con MbRtuClSendReadHoldingReg(),
alterar el valor del bit deseado dentro del PLC, y luego sobre-escribir el valor del registro
con el nuevo valor utilizando la funcion MbRtuClSendWriteReg().

La operación de lectura debes realizarla antes, ya que debes conservar el valor de los otros bits del registro.

Entonces, primero debes leer el registro:

// Enviar peticion para leer 1 "Holding Registers".

MbRtuClSendReadHoldingReg(247, 302, 1)

// Esperas la respueta.

// Suponiendo que el valor del registro se encuentra en la variable "Registro",
// podes alterar el valor del bit con las funciones BitSet() y BitClr(),
// ver manual de programacion Pawn, pagina 151.

// Si queres poner en "1" el bit 2 de la variable "Registro" haces:

BitSet(Registro, 2)

// Finalmente, debes enviar el nuevo valor del registro en otra transacción  de escritura usando:

MbRtuClSendWriteReg(247, 302, Registro)


Ese es el procedimiento, recorda comprobar errores en cada transacción,
y hacerlo mas prolijo. Podes crear una función Pawn que englobe todo esto, así
te queda mas modular.

Entonces, se integro correctamente la interfaz RS485 ?.


« Última Modificación: septiembre 05, 2014, 16:20:43 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

vitor14

  • Novato
  • *
  • Mensajes: 8
Re: MODBUS RS485
« Respuesta #13 : septiembre 05, 2014, 16:45:38 pm »
Buenisimo, super claro.

Si funciona a la perfección el modbus con los equipos por 485 con un max485.

Una ultima pregunta, estoy haciendo una lectura que indica el nivel de gas, en el manual aparece como Single Precision Float, el tema es que cuando lo quiero mostrar, en decimal lo muestra, pero cuando lo muestro como float, siempre me pone 0.00, en decimal inclusive cuando le cambio el valor del sensor poniendole monoxido de carbono varia, pero en float queda siempre en 0.

Código: [Seleccionar]
leerModbus(direccionGas1,2)
...

 new Var = Float: RxDataF[0]
   // Mostrar valores de registros en LCD.
LcdPrintf(0,1, "%f", Var)

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 1722
  • Soporte Técnico
Re: MODBUS RS485
« Respuesta #14 : septiembre 05, 2014, 17:59:12 pm »
En el manual se refiere a "Single Precision Float", por lo tanto debe hablar de una palabra de 32-bits,
o lo que es lo mismo, a dos registros de 16-bits que debes leer consecutivamente para formar el valor final en float.

No especifica que direccion tiene los 16-bits mas altos de la palabra.

Pero supongamos que queres leer "Gas Level - Sensor 1", en dirección Base+207.

El float, debería estar almacenado en las direcciones de registros como sigue:

Base+207 = 16-bits mas significativos.
Base+208 = 16-bits menos significativos.

Entonces, debes leer ambos registros (supongamos que ya recibiste ambos valores vía ModBus y los tenes en las variables RegistroH y RegistroL):

// En Pawn (en rojo los valores ya recibidos)
new RegistroH = Base+207
new RegistroL = Base+208


new RawValue
new Float: FloatValue = 0


// Convertir a 32-bits (unir ambos registros para formar el float de 32-bits).
// Notar en segunda linea como realizo una operación SHIFT y luego un OR bit-a-bit.
RawValue = RegistroL
RawValue |= (RegistroH << 16)


// Almacenar en float haciendo un cast (para que se interprete correctamente).
FloatValue = Float: RawValue

// Finalmente, imprimir:
LcdPrintf(0,1, "%f", FloatValue)


Proba esta forma, si no funciona, proba recuperando al reves los valores, es decir en RegistroH = Base+208 y en RegistroL = Base+207.

No esta muy claro en la hoja de datos cuales son los dos bytes mas significativos del "Single Precision Float".







« Última Modificación: septiembre 05, 2014, 18:12:11 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com