Uso de la placa IoT-02 como dispositivo ModBus-RTU esclavo
Salta a la navegació
Salta a la cerca
Puesta en marcha
Código en Python para la lectura ModBus RTU (en GitHub) de la placa IoT-02 programada con un código ModBus RTU maestro (en GitHub).
Código en Python
Ejecución:
./mb_IoT_00_windows.py COM3 4800
o
./mb_IoT_00.py /dev/ttyUSB1 4800
Puerto y velocidad como argumento
class ModBus(): def __init__(self, parent=None): self.tipus = 0 if len( sys.argv ) == 2 : szPort = sys.argv[1] nBauds = 115200 else : if len( sys.argv ) == 3 : szPort = sys.argv[1] nBauds = int(sys.argv[2]) else : szPort = "/dev/ttyUSB0" nBauds = 4800 port = szPort baudrate = nBauds print("Baudrate: %d at %s"%(baudrate,port)) self.ser = 0 self.t = 0 try: self.ser = serial.Serial( port, baudrate, timeout=0, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_TWO, bytesize=serial.EIGHTBITS ) self.nSegonsTimer = 0.2 self.t = Timer(self.nSegonsTimer,self.temporitzador) self.t.start() k = KeyGetter() self.bLoop = True while self.bLoop == True: if k.kbhit(): cKey = repr(k.getch(False)) self.processaTecla(cKey[1]) sleep(0.1) self.bye()
Órdenes ModBus de escritura
def writeCommand(self,command): hCRC = hexCRC(command) addedCRC="%c%c"%(hCRC>>8,hCRC&0xFF) command += addedCRC for cmd_byte in command: hex_byte = ("{0:02X}".format(ord(cmd_byte))) print (hex_byte,end=) self.ser.write(bytearray.fromhex(hex_byte)) print("")
Órdenes ModBus de lectura
def lecturaMB(self,q): # print("%s" % q) if q == 'relaySet': print("{\nSending: Relay SET") stMB = "%c%c%c%c%c%c"%(0x07,0x05,0x00,0x04,0xFF,0x00) self.writeCommand(stMB) if q == 'relayReset': print("{\nSending: Relay RESET") stMB = "%c%c%c%c%c%c"%(0x07,0x05,0x00,0x04,0x00,0x00) self.writeCommand(stMB) if q == 'input': print("{\nSending: Reading 4 coils") stMB = "%c%c%c%c%c%c"%(0x07,0x02,0x00,0x00,0x00,0x04) self.writeCommand(stMB) if q == 'temperature': print("{\nSending: Reading temperature") stMB = "%c%c%c%c%c%c"%(0x07,0x03,0x00,0x00,0x00,0x01) self.writeCommand(stMB)
Lectura de la respuesta ModBus del dispositivo
Lectura del puerto serie cada 200ms ( self.nSegonsTimer = 0.2 ):
def temporitzador(self): data = self.ser.read(1) n = self.ser.inWaiting() if n: n = 1 + n data = data + self.ser.read(n) if len(data): self.processa(data,n) print("} ----")
Función principal
if __name__ == '__main__': print("s: Relay SET, r: Relay RESET, i: Read inputs, t: temperature, h: relative humidity, p: pressure, a: altitude, v: VOC and q: quit") mb = ModBus()
Código del ESP32 en el IDE de Arduino
IoT-02_11_modbus_bme280.ino en GitHub
#include "IoT-02_modbus.h" HardwareSerial modbusData(2); #define MODBUS_BAUD_RATE 4800
Parámetros ModBus en IoT-02_modbus.h
#define MODULE_ADDRESS 0x07 #define COIL_RELAY_ADDRESS 0x0004 #define COIL_INPUTS_ADDRESS 0x0000 #define HOLDING_REGISTER_TEMEPRATURE_ADDRESS 0x0000 #define HOLDING_REGISTER_REL_HUMIDITY_ADDRESS 0x0001 #define HOLDING_REGISTER_PRESSURE_ADDRESS 0x0002 #define HOLDING_REGISTER_ALTITUDE_ADDRESS 0x0003 #define HOLDING_REGISTER_VOC_ADDRESS 0x0004
setup()
void setup() { Wire.begin(I2C_SDA, I2C_SCL); vSetupIO(); vSetupScreen(); vSetupModBus(MODBUS_BAUD_RATE); Serial.begin(115200); Serial.println(__FILE__); vSetupBME280(); }
Función vModBusReading() llamada en loop()
void vModBusReading() { int i, nCmpt = 0; unsigned int uiCRC; byte uiCrcL, uiCrcH; unsigned char ucSt[N_MAX]; while (modbusData.available() > 0) { ucSt[nCmpt] = (unsigned char)modbusData.read(); nCmpt++; delay(2); } if (nCmpt) { Serial.print("He leído estos "); Serial.print(nCmpt); Serial.println(" bytes: "); for (i = 0; i < nCmpt; i++) { Serial.print(ucSt[i], HEX); Serial.print(" "); } Serial.println(); uiCRC = uiModRTU_CRC(ucSt, nCmpt - 2);' if ((byte)(uiCRC >> 8) == ucSt[nCmpt - 1] && (byte)(uiCRC & 0xFF) == ucSt[nCmpt - 2]) { Serial.println("Trama con CRC correcto"); vProcessa(ucSt, nCmpt); } else { Serial.println("Trama con CRC incorrecto"); } } nCmpt = 0; }