Todavía falta codear mas funciones de MODBUS, versión 0.01
viernes, 25 de agosto de 2023
Tesys T LTMR + Gambas3 + Modbus + V0.01
' Gambas class file
Public DatoRegistro As String
Public DatoINT[256] As Integer
Public Sub Socket1_Closed()
PictureBox8.Picture = Picture.Load("led_verde_off.png")
End
Public Sub Socket1_Ready()
PictureBox8.Picture = Picture.Load("led_verde_on.png")
End
Public Function BIN_DEC(Binario As String, n As Integer) As Integer
Dim L, i, e, Entero As Integer
e = 0
For i = n To 0 Step -1
If Binario[i] = "1" Then
Entero = Entero + 2 ^ e
Endif
e = e + 1
Next
Return Entero
End
Public Function DEC_BIN(Decimal As Integer) As String
Dim i As Integer
Dim CadenaBit As String
For i = 0 To 15
If (Decimal % 2 == 1) Then
CadenaBit = CadenaBit & "1"
Else
CadenaBit = CadenaBit & "0"
End If
Decimal = Decimal / 2
Next
Return (Byte[].FromString(CadenaBit)).Reverse().ToString()
End
Function Leer_MDBUS_TCP(Registro As Integer) As String
Dim i, l As Integer
Dim Byte_LO As String
Dim Byte_HI As String
Escribir_MODBUS_TCP(0, 3, Registro, 1)
l = Len(DatoRegistro)
For i = 0 To l
DatoINT[i] = Asc(DatoRegistro[i])
Next
'For i = 0 To l
' Print i, DatoINT[i], DEC_BIN(DatoINT[i])
'Next
Byte_LO = Right$(DEC_BIN(DatoINT[10]), 8)
Byte_HI = Right$(DEC_BIN(DatoINT[9]), 8)
Return Byte_HI & Byte_LO
End
Public Sub Escribir_MODBUS_TCP(Direccion As Integer, CodigoFuncion As Integer, DireccionRegistro As Integer, Dato As Integer)
Dim TRAMA As New Integer[256]
Dim DATO_TX As String
Dim BIN, HI, LO As String
'Identificador de la transaccion
TRAMA[0] = 0
TRAMA[1] = 0
'Identificador del protocolo 0 para modbus
TRAMA[2] = 0
TRAMA[3] = 0
'Numero de bytes en esta trama
TRAMA[4] = 0
TRAMA[5] = 6
'Direccion del dispositivo
TRAMA[6] = Direccion
'Codigo de funcion
TRAMA[7] = CodigoFuncion
'Direccion registro
BIN = DEC_BIN(DireccionRegistro)
HI = Mid$(BIN, 1, 8)
LO = Mid$(BIN, 9, 16)
TRAMA[8] = BIN_DEC(HI, 7)
TRAMA[9] = BIN_DEC(LO, 7)
'Datos del registro
BIN = DEC_BIN(Dato)
HI = Mid$(BIN, 1, 8)
LO = Mid$(BIN, 9, 16)
TRAMA[10] = BIN_DEC(HI, 7)
TRAMA[11] = BIN_DEC(LO, 7)
DATO_TX = Chr$(TRAMA[0]) & Chr$(TRAMA[1]) & Chr$(TRAMA[2]) & Chr$(TRAMA[3]) & Chr$(TRAMA[4]) & Chr$(TRAMA[5]) & Chr$(TRAMA[6]) & Chr$(TRAMA[7]) & Chr$(TRAMA[8]) & Chr$(TRAMA[9]) & Chr$(TRAMA[10]) & Chr$(TRAMA[11])
If (Socket1.Status = Net.Connected) Then
Write #Socket1, DATO_TX, Len(DATO_TX)
Endif
End
Public Sub Cerrar_Click()
Escribir_MODBUS_TCP(0, 6, 704, 1)
End
Public Sub Socket1_Error()
Select Case Socket1.Status
Case Net.CannotCreateSocket
Message.Error("El sistema no permite crear un socket")
Case Net.HostNotFound
Message.Error("Host no encontrado")
Case Net.ConnectionRefused
Message.Error("No es posible conectar. La solicitud fue rechazada")
Case Net.CannotRead
Message.Error("Error leyendo datos")
Case Net.CannotWrite
Message.Error("Error escribiendo datos")
End Select
End
Public Sub Abrir_Click()
Escribir_MODBUS_TCP(0, 6, 704, 0)
End
Public Sub Conectar_Click()
Socket1.Host = TextBox1.Text
Socket1.Port = Val(TextBox2.Text)
Socket1.Connect()
End
Public Sub Timer1_Timer()
Dim BITs As String
Dim Entero As Integer
If (Socket1.Status = Net.Connected) Then
BITs = Leer_MDBUS_TCP(459)
Print BITs
If BITs[3] = "1" Then
PictureBox3.Picture = Picture.Load("contactor_close.png")
Else If BITs[3] = "0" Then
PictureBox3.Picture = Picture.Load("contactor_open.png")
Endif
If BITs[2] = "1" Or BITs[14] = "1" Then
PictureBox2.Picture = Picture.Load("Interruptor_close.png")
Else If BITs[2] = "0" Or BITs[14] = "0" Then
PictureBox2.Picture = Picture.Load("Interruptor_open.svg.png")
Endif
Endif
End
Public Sub O2_Click()
Escribir_MODBUS_TCP(0, 6, 704, 2)
End
Public Sub Reset_Click()
Escribir_MODBUS_TCP(0, 6, 704, 8)
End
Public Sub Socket1_Read()
Read #Socket1, DatoRegistro, Lof(Socket1)
End
Public Sub Form_Open()
Timer1.Enabled = True
End
martes, 8 de agosto de 2023
Tesys T LTMR + pymodbus + Tkinter
Observen que al darle al boton ON 0 cambiamos de estado la salida O1 del Tesys T, de esta manera podemos probar nuestro LTMR en forma remota. Recuerden el I6 en estado alto para remoto.
Tesys T LTMR + pymodbus + Tkinter
from Tkinter import * import os import MySQLdb from pymodbus.client.sync import ModbusTcpClient #------------------------------------------------------- #------------------------------------------------------- def decbin(numero): cadenabin = "" for i in range(1,17): resultado = numero / 2 resto = numero % 2 if resto == 0: cadenabin = cadenabin + "0" else: cadenabin = cadenabin + "1" numero=resultado return cadenabin def FUNC_OFF_a(): cliente.write_register(704, 0b0000000000000000) def FUNC_ON_a(): cliente.write_register(704, 0b0000000000000001) def FUNC_WRITE(): dato = entrada.get() print dato dato = int(dato) cliente.write_register(652,dato) def FUNC_ON_b(): cliente.write_register(704, 0b0000000000000010) def FUNC_Reset(): cliente.write_register(704, 0b0000000000001000) def FUNC_Kill(): print ("Cuidado !") cliente.write_register(705, 0b0000000000011111) def FUNC_Estado(): estado = cliente.read_holding_registers(455,1) datos = estado.registers[0] print("-------------------------------------") print ("Registro 455") #print datos print decbin(datos) if (datos & 1): print ("Sistema listo") if (datos & 2): print ("Sistema activado") if (datos & 4): print ("Sistema fallo") if (datos & 8): print ("Sistema advertencia") if (datos & 16): print ("Sistema disparo") if (datos & 32): print ("Reinicio de fallo autorizado") if (datos & 64): print ("Controlador potencia\n") print("-------------------------------------") estado = cliente.read_holding_registers(457,1) datos = estado.registers[0] print ("Registro 457") #print datos print decbin(datos) if (datos & 1): print ("E1 Start") if (datos & 2): print ("E2 Close O2") if (datos & 4): print ("E3 Free") if (datos & 8): print ("E4 Stop O1 O2") if (datos & 16): print ("E5 Reset") if (datos & 32): print ("E6 L/R") # VENT_Estados = Tk() # VENT_Estados.title("LTMR Tesys T - Estados -") # VENT_Estados.minsize(300,200) # texto = Label(VENT_Estados, text="Estado LTMR") # texto.pack() #------------------------------------------------------- cliente = ModbusTcpClient('192.168.4.169','502') cliente.connect() #------------------------------------------------------- # MAIN LOOP VENTANA = Tk() VENTANA.title("LTMR Tesys T") VENTANA.minsize(250,200) texto = Label(VENTANA, text="Comandos LTMR") texto.pack() ON_Img = PhotoImage(file="ON.png") imagen = ON_Img.subsample(10,10) ON_a = Button(VENTANA, text="ON 0", width=8, height=1, command=FUNC_ON_a, bg="green") ON_a.pack() OFF_a = Button(VENTANA, text="OFF 0", width=8, height=1, command=FUNC_OFF_a) OFF_a.pack() ON_b = Button(VENTANA, text="ON 1", width=8, height=1, command=FUNC_ON_b, bg="green") ON_b.pack() #--------------------------------------------------------------------------- entrada = StringVar() corriente = Entry(VENTANA, width=10, textvariable=entrada) corriente.pack() OFF_b = Button(VENTANA, text="WRITE", width=8, height=1, command=FUNC_WRITE) OFF_b.pack() #--------------------------------------------------------------------------- RESET = Button(VENTANA, text="Reset", width=8, height=1, command=FUNC_Reset) RESET.pack() ESTADO = Button(VENTANA, text="Estado", width=8, height=1, command=FUNC_Estado) ESTADO.pack() KILL = Button(VENTANA, text="Kill", width=8, height=1, bg="red", command=FUNC_Kill) KILL.pack() VENTANA.mainloop() cliente.close()
jueves, 14 de julio de 2022
lunes, 8 de noviembre de 2021
Linux - error con avrdude con libusb
El problema surgio al ejecutar avrdude -v
avrdude: symbol lookup error: /lib/x86_64-linux-gnu/libhidapi-libusb.so.0: undefined symbol: libusb_handle_events_completed
solucionamos de la siguiente manera, en la consola
export LD_LIBRARY_PATH="/lib/x86_64-linux-gnu/"
sábado, 7 de agosto de 2021
domingo, 7 de febrero de 2021
PLC M340 - Problemas con el FBD ADD - suma numeros reales
El inconveniente surgió cuando al corregir el valor del contador, el mismo sufría un desplazamiento, se atrasaba o se adelantaba.
Tenemos un caudalimetro de gas, el cual produce un pulso cada tantas vueltas indicando un cambio en el primer decimal.
Observamos que justo en la foto esta por cambiar el primer decimal y a la vez el caudalimetro produciría un pulso, el cual va un pin de entrada de una ER.
VOL_CONS_CALENTADOR = VOL_CONS_CALENTADOR + 0,1 por cada pulso.
Al simular observamos lo siguiente:
Vemos que al simular un par de pulsos la suma paso a tener varios decimales, en la siguiente imagen vamos a poder apreciar el desplazamiento que ocurre.
La solución fue la siguiente, tomando en cuenta de no modificar el tipo de dato esperado en el scada.
AUX = AUX + 1.0 por cada pulso.
VOL_CONS_CALENTADOR = AUX / 10.0
En la simulación observamos que los decimales extras ya no estan "presentes", al dar 23 pulsos.
lunes, 25 de mayo de 2020
PLC M580 en modo STOP PLCDiagCom
lunes, 18 de mayo de 2020
Gambas3 cliente MODBUS RTU - Fase en desarrollo
' Gambas class file Public ADU[254] As Integer Public Nregistros As Integer Public Nbytes As Integer Public BYTES[1024] As Integer ' Conectar al puerto serie Public Sub Button2_Click() SerialPort1.PortName = TextBox1.Text SerialPort1.Speed = TextBox2.Text SerialPort1.Open() TextBox6.text = "Puerto : " & SerialPort1.PortName & " Configuracion : " & SerialPort1.Speed & "," & SerialPort1.Parity & "," & SerialPort1.DataBits & "," & SerialPort1.StopBits Button1.Enabled = True Button4.Enabled = True Button2.Enabled = False End ' Desconectar del puerto serie Public Sub Button4_Click() SerialPort1.Close() TextArea1.text = TextArea1.text & SerialPort1.Status Button4.Enabled = False Button2.Enabled = True End ' Salir de la aplicacion Public Sub Button3_Click() SerialPort1.Close() Quit End Public Sub Button5_Click() TextArea3.Clear() TextArea1.Clear() End ' Envio de la consulta modbus Public Sub Button1_Click() Dim DireccionHI As Integer Dim DireccionLO As Integer Dim DatoHI As Integer Dim DatoLO As Integer Dim ID As Integer Dim Funcion As Integer Dim CRCLO, CRCHI, i As Integer Dim CRC As String Nbytes = 0 TextArea2.text = TextArea2.text & "\n" 'ID ADU[0] = TextBox3.text 'Funcion ADU[1] = ComboBox1.Index + 1 'Direccion HI ADU[2] = 0 'Direccion LO ADU[3] = SpinBox1.Text 'Numero de registros/DATO HI If ((ComboBox1.Index + 1) = 5) Or ((ComboBox1.Index + 1) = 6) Then ADU[4] = TextBox5.Text Else ADU[4] = 0 Endif 'Numero de registros/DATO LO If ((ComboBox1.Index + 1) = 5) Or ((ComboBox1.Index + 1) = 6) Then ADU[5] = TextBox4.Text Else ADU[5] = SpinBox2.Text Endif Nregistros = SpinBox2.Text CRC = Hex(CRC16(5)) If Len(CRC) < 4 Then ADU[6] = HEX_DEC(Right$(CRC, 2)) ADU[7] = HEX_DEC(Left$(CRC, 1)) Else ADU[6] = HEX_DEC(Right$(CRC, 2)) ADU[7] = HEX_DEC(Left$(CRC, 2)) Endif For i = 0 To 1 TextArea1.Text = TextArea1.text & i & ":" & ADU[i] & " " Next TextArea1.Text = TextArea1.text & "\n" For i = 2 To 7 TextArea3.Text = TextArea3.text & i & ":" & ADU[i] & " " Next TextArea3.Text = TextArea3.text & "\n" For i = 0 To 7 Write #SerialPort1, Chr$(ADU[i]) Next End Function CRC16(n As Integer) As Integer Dim i, pos As Integer Dim CRC As Integer CRC = 65535 For pos = 0 To n CRC = CRC Xor ADU[pos] For i = 0 To 7 If ((CRC And 1) <> 0) Then CRC = Lsr(CRC, 1) CRC = CRC Xor 40961 Else CRC = Lsr(CRC, 1) Endif Next Next Return CRC End Function HEX_DEC(aux As String) As Integer Dim a, b, c, l As Integer Dim d As String c = 0 l = Len(aux) For a = 1 To l d = Mid$(aux, a, 1) Select Case d Case "A" b = 10 Case "B" b = 11 Case "C" b = 12 Case "D" b = 13 Case "E" b = 14 Case "F" b = 15 Case Else b = CInt(d) End Select c = c + (b * 16 ^ (l - a)) Next Return c End 'Recepcion de datos seriales Public Sub SerialPort1_Read() Dim DATO_BYTE As String Read #SerialPort1, DATO_BYTE, 1 TextArea2.text = TextArea2.text & Nbytes & ":" & Hex(Asc(DATO_BYTE)) & " " Nbytes = Nbytes + 1 End Public Sub Button6_Click() TextArea2.Clear() End Public Sub Form_Open() Nbytes = 0 End Public Sub Button7_Click() TextArea2.text = TextArea2.text & "\n" End
miércoles, 6 de mayo de 2020
App Inventor Arduino MLX90614 - Prueba
#include <Wire.h>; #include <Adafruit_MLX90614.h>; Adafruit_MLX90614 mlx = Adafruit_MLX90614(); String inputString = ""; bool stringComplete = false; //----------------------------------------------- // CONFIGURACION //----------------------------------------------- void setup() { inputString.reserve(32); Serial.begin(9600); mlx.begin(); } //----------------------------------------------- // MAIN //----------------------------------------------- void loop() { if (stringComplete) { if(inputString.substring(0,2)=="MT"){ Serial.print(mlx.readAmbientTempC()); Serial.print("/"); Serial.print(mlx.readObjectTempC()); } inputString = ""; stringComplete = false; } } //----------------------------------------------- void serialEvent() { while (Serial.available()) { char inChar = (char)Serial.read(); inputString += inChar; if (inChar == '\n') { stringComplete = true; } } } //-----------------------------------------------
lunes, 23 de marzo de 2020
Sistema de observacion de seguridad
Link de descarga:
sos.apk
lunes, 22 de julio de 2019
Planilla de recorrida Wartsila 18V50 SG v0.1
Planilla de recorrida Lectura del fuelle
sábado, 8 de diciembre de 2018
viernes, 7 de diciembre de 2018
pymodbus TCP cliente mysql tabla - ejemplo
Crear primero la BD llamada MODBUS_SCADA
CREATE TABLE ReadCoils (
idReadCoils INT NOT NULL AUTO_INCREMENT,
CO1 CHARACTER,
CO2 CHARACTER,
CO3 CHARACTER,
CO4 CHARACTER,
CO5 CHARACTER,
CO6 CHARACTER,
CO7 CHARACTER,
CO8 CHARACTER,
PRIMARY KEY (idReadCoils)
) ENGINE=InnoDB;
CREATE TABLE ReadDiscreteInput (
idReadDiscreteInput INT NOT NULL AUTO_INCREMENT,
DI1 CHARACTER,
DI2 CHARACTER,
DI3 CHARACTER,
DI4 CHARACTER,
DI5 CHARACTER,
DI6 CHARACTER,
DI7 CHARACTER,
DI8 CHARACTER,
PRIMARY KEY (idReadDiscreteInput)
) ENGINE=InnoDB;
CREATE TABLE ReadHoldingRegisters (
idReadHoldingRegisters INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
HR1 INT,
HR2 INT,
HR3 INT,
HR4 INT,
HR5 INT,
HR6 INT,
HR7 INT,
HR8 INT
) ENGINE=InnoDB;
CREATE TABLE ReadInputRegisters (
idReadInputRegisters INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
IR1 INT,
IR2 INT,
IR3 INT,
IR4 INT,
IR5 INT,
IR6 INT,
IR7 INT,
IR8 INT
) ENGINE=InnoDB;
Generated by GNU Enscript 1.6.5.90.
pymodbus TCP cliente mysql - ejemplo
import os
import MySQLdb
from pymodbus.client.sync import ModbusTcpClient
cliente = ModbusTcpClient('127.0.0.1','5020')
#---------------------------------------------------------------------------#
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
Dispositivo = 1
#---------------------------------------------------------------------------#
def CONSULTA_SQL(COMANDO, DISPOSITIVO, a, b, c, d, e, f, g, h):
coneccion = MySQLdb.connect("localhost","root","holanena69","MODBUS_SCADA")
BD = coneccion.cursor()
if COMANDO == 1:
BD.execute("""INSERT INTO ReadCoils (CO1, CO2, CO3, CO4, CO5, CO6, CO7, CO8) VALUES (%c, %c, %c, %c, %c, %c, %c, %c)""",(a, b, c, d, e, f, g, h))
elif COMANDO == 2:
BD.execute("""INSERT INTO ReadDiscreteInput (DI1, DI2, DI3, DI4, DI5, DI6, DI7, DI8) VALUES (%c, %c, %c, %c, %c, %c, %c, %c)""",(a, b, c, d, e, f, g, h))
elif COMANDO == 3:
BD.execute("""INSERT INTO ReadHoldingRegisters (HR1, HR2, HR3, HR4, HR5, HR6, HR7, HR8) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)""",(a, b, c, d, e, f, g, h))
elif COMANDO == 4:
BD.execute("""INSERT INTO ReadInputRegisters (IR1, IR2, IR3, IR4, IR5, IR6, IR7, IR8) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)""",(a, b, c, d, e, f, g, h))
coneccion.commit()
BD.close()
coneccion.close()
#---------------------------------------------------------------------------#
os.system('clear')
print "Read Coils"
request = cliente.read_coils(0x0,0x8,unit=Dispositivo)
print request.bits[0]
print request.bits[1]
print request.bits[2]
print request.bits[3]
print request.bits[4]
print request.bits[5]
print request.bits[6]
print request.bits[7]
CONSULTA_SQL(1,0,request.bits[0], request.bits[1], request.bits[2], request.bits[3], request.bits[4], request.bits[5], request.bits[6], request.bits[7])
print "Read Discrete Input"
request = cliente.read_discrete_inputs(0x0,0x8,unit=Dispositivo)
print request.bits[0]
print request.bits[1]
print request.bits[2]
print request.bits[3]
print request.bits[4]
print request.bits[5]
print request.bits[6]
print request.bits[7]
CONSULTA_SQL(2,0,request.bits[0], request.bits[1], request.bits[2], request.bits[3], request.bits[4], request.bits[5], request.bits[6], request.bits[7])
print "Read Holding Registers"
request = cliente.read_holding_registers(0x0,0x7,unit=Dispositivo)
print request.registers
print type(request.registers[0])
CONSULTA_SQL(3,0,request.registers[0], request.registers[1], request.registers[2], request.registers[3], request.registers[4], request.registers[5], request.registers[6], 9)
print "Read Input Registers"
request = cliente.read_input_registers(0x0,0x7,unit=Dispositivo)
print request.registers
CONSULTA_SQL(4,0,request.registers[0], request.registers[1], request.registers[2], request.registers[3], request.registers[4], request.registers[5], request.registers[6], 9)
cliente.close()
Generated by GNU Enscript 1.6.5.90.
























