Segunda Patita


Y bueno se va la 2da patita de 3, hoy les comentare la forma mas básica creo  de implementar el Modbus RTU  en una tarjeta Raspberrie Pico  (RP de aqui en adelante), en la entrega anterior les comente de mi sistema de desarrollo incluso mostré una foto de este, en esta ocasión la idea es mostrara un esclavo muy básico que responda a la funcion3 del Modbus que es Leer los Holding Register del RP, lo primero que implemente es un parser en este para analizar que esta llegando por la port serial asociado al RS485 y después la 2 parte despachar la respuesta al comando o  ModbusRTU.py / Tx/Rx => PIN 1 y PIN 2 en raspberry pico Modbus en esta parte se complica la cosa porque la respuesta debe contar al final con un CRC16 para que el Modbus Poll pueda verificar la integridad de la trama enviada  y la 3 parte y final es enviar la trama completa al Modbus Poll.

Bueno a continuación le muestro el código que cree usando micropyhon en Thonny, tiene bastantes comentarios para que lo puedan implementar si así lo desean.


# ModbusRTU.py / Tx/Rx => PIN 1 y PIN 2 en raspberry pico
# 17-01-2020 funcionando el Modo HR en modo RTU para el modbus se pueden leer 10 registros .

import os
from machine import UART
import machine
from time import sleep

# crea el CRC y lo agrega al en las ultimas 2 posiciones del arreglo
def calc(data : bytearray, n):
    crc_table=    [0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040]

    crc_hi=0xFF
    crc_lo=0xFF

    for i in range(n+1):
        a=data[i]
        index=crc_lo ^ a
        crc_val=crc_table[index]
        crc_temp=crc_val//256
        crc_val_low=crc_val-(crc_temp*256)
        crc_lo=crc_val_low ^ crc_hi
        crc_hi=crc_temp

    crc=crc_hi*256 +crc_lo
    data[n+1]=crc_lo
    data[n+2]=crc_hi
    return(data)

# Parser analiza lo que llega por la port serial para ver si es una trama Modbus Valida
def lee_trama_mb(addr_mb):
    paso = 1
    while paso < 10 :
        if uart.any():  
            b = uart.read()
            if paso == 1 :    # paso 1 leemos la direccion
                addr = b[0]
                paso = paso + 1
            if paso == 2:   # leemos la funcion
                funcion = b[1]
                paso = paso + 1
            if paso == 3:   # leemos la direccion de origen msb
                addr_msb = b[2]
                paso = paso + 1
            if paso == 4:   # leemos la direccion de origen Lsb
                addr_lsb = b[3]
                paso = paso + 1
            if paso == 5:   # leemos nro de registros msb
                nreg_msb = b[4]
                paso = paso + 1
            if paso == 6:   # leemos nro de registros Lsb 
                nreg_lsb = b[5]
                paso = paso + 1
            if paso == 7:   # leemos codigo de chequeo CRC lo 
                crc_lo = b[6]
                paso = paso + 1         
            if paso == 8:   # leemos codigo de chequeo CRC hi  
                crc_hi = b[7]
                paso = paso + 1
            if paso == 9:   # trama recivida generar respuesta dependieendo de la funcion  
                addr_reg = (addr_msb << 8) + addr_lsb
                nreg = (nreg_msb << 8) + nreg_lsb
                trama = bytearray(30)
                if funcion == 0x03: # Corresponde a Holding Register y parten con 4000
                     trama[0] = addr       # direccion del esclavo que responde
                     trama[1] = funcion    # funcion a la que responde
                     trama[2] = nreg*2       # numero de bytes de datos a transmitir
                     for i in range(nreg * 2):
                         trama[3+i] = hr_tabla[i]
                     # calcular el CRC
                     trama = calc(trama,3+i)
                     uart.write(trama)    
                paso = 10
    return(funcion, addr, nreg )

# Punto de partida
print('Modbus RTU V0.1')
uart = machine.UART(0, 9600)
print(uart)

contador = 0
hr_tabla=[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]

# loop Principal
while True:
    print(contador)
    lee_trama_mb(1)
    hr_tabla[0]=contador
    contador = contador + 1

Bueno y esta fue la 2da patita el código esta mostrado les comento que funciona como les dije lo probé con Modbus Poll y  Kepserver V6.0.

En la próxima entrega a ampliare un poco mas el parser para soportar la función 6 de Modbus 

Si desean mayor conocimiento del Protocolo Modbus en el Modbus Poll en la sección de ayuda existe una  descripción muy completa incluso con tramas de ejemplo.

Y nos veremos pronto en la Tercera patita y Ultima Gracias.


   

Comentarios

Entradas populares de este blog

Raspberry Pico (modbus rtu)