====== SetModbus ====== Configure UART settings and start the LogicPython Modbus RTU slave process. ===== Syntax ===== from cubloc import SetModbus SetModbus(channel: int, baudRate: int, protocol: int, recvSize: int, sendSize: int, slaveAddress: int, coils: object, discreteInputs: object, inputRegisters: object, holdingRegisters: object, memoryLock: object, returnInterval: int = 0) ===== Parameters ===== * **channel**: Serial ''channel'' number. ''Channel'' 0 maps to UART0 (GP0/GP1) and ''channel'' 1 maps to UART1 (GP4/GP5). * **baudRate**: Serial baud rate (2400 to 921600). * **protocol**: Encoded bit field for data bits, parity, and stop bits. See the tables below. * **recvSize**: Receive buffer size in bytes (1 to 4096). * **sendSize**: Send buffer size in bytes (1 to 4096). * **slaveAddress**: Modbus unit ID (1 to 247). * **coils**: Writable bit-packed coil buffer (8 ''coils'' per byte). * **discreteInputs**: Writable bit-packed discrete-input buffer (8 inputs per byte). * **inputRegisters**: Writable input-register byte buffer (2 bytes per register). * **holdingRegisters**: Writable holding-register byte buffer (2 bytes per register). * **memoryLock**: lock object to synchronize Modbus memory access between the user program and the Modbus RTU slave process. * **returnInterval**: Delay in microseconds before replying to a Modbus query from the Modbus master (default 0). ''protocol'' bit layout: ^ Field ^ Bits ^ Meaning ^ | Data bits | 1..0 | 00=5 bits, 01=6 bits, 10=7 bits, 11=8 bits | | Stop bits | 2 | 0=1 stop bit, 1=2 stop bits | | Parity | 4..3 | 00=None, 10=Even, 11=Odd (01 is reserved and raises ''ValueError'') | Common ''protocol'' values: ^ protocol ^ Frame format ^ | 3 | 8N1 | | 11 | 8E1 | | 19 | 8O1 | | 7 | 8N2 | ===== Exceptions ===== * [[https://docs.micropython.org/en/latest/library/builtins.html#TypeError|TypeError]]: An argument has an invalid type. * [[https://docs.micropython.org/en/latest/library/builtins.html#ValueError|ValueError]]: ''baudRate'', ''protocol'', ''recvSize'', ''sendSize'', or ''slaveAddress'' is outside the supported range. * [[https://docs.micropython.org/en/latest/library/builtins.html#RuntimeError|RuntimeError]]: Modbus startup failed. ===== Example ===== import _thread from cubloc import * from machine import * import os from time import sleep machine = os.uname().machine print(machine) if "LP126T" in machine: OUTPUT_PINS = (3, 16, 17, 18, 19) INPUT_PINS = (32, 33, 34, 35, 36, 37, 38, 39) ADC_CHANS = (40, 41, 42, 43, 44, 45) else: OUTPUT_PINS = (25, 16, 17, 18) INPUT_PINS = (19, 20, 21) ADC_CHANS = (26, 27, 28) OUTPUT_COUNT = len(OUTPUT_PINS) INPUT_COUNT = len(INPUT_PINS) ADC_COUNT = len(ADC_CHANS) ADC_BYTES = ADC_COUNT << 1 # Initialize the physical IO for pin in OUTPUT_PINS: Output(pin) Low(pin) for pin in INPUT_PINS: Input(pin, 1) # Configure and start the Modbus RTU slave process UART_CHANNEL = 0 BAUD_RATE = 460800 PROTOCOL = 3 # 8N1 BUFFER_SIZE = 64 SLAVE_ADDRESS = 1 # Configure the Modbus memory coils = bytearray(1) discrete_inputs = bytearray(2) input_regs = bytearray(16) holding_regs = bytearray(16) mem_lock = _thread.allocate_lock() adc_shadow = bytearray(ADC_BYTES) setpoint = 0 # Start the Modbus slave print("Starting Modbus") SetModbus( UART_CHANNEL, BAUD_RATE, PROTOCOL, BUFFER_SIZE, BUFFER_SIZE, SLAVE_ADDRESS, coils, discrete_inputs, input_regs, holding_regs, mem_lock ) # Run in an infinite loop synchronizing Modbus memory with the physical IO print("Starting the main loop") while True: # Read the coil memory mem_lock.acquire() coils_byte = coils[0] mem_lock.release() # Drive digital outputs from the coil memory i = 0 while i < OUTPUT_COUNT: Out(OUTPUT_PINS[i], (coils_byte >> i) & 1) i += 1 # Read digital inputs din_byte = 0 i = 0 while i < INPUT_COUNT: if In(INPUT_PINS[i]): din_byte |= 1 << i i += 1 # Transfer digital inputs to discrete input memory mem_lock.acquire() discrete_inputs[0] = din_byte mem_lock.release() # Read analog inputs i = 0 j = 0 while i < ADC_COUNT: val = ADIn(ADC_CHANS[i]) adc_shadow[j] = (val >> 8) & 0xFF adc_shadow[j + 1] = val & 0xFF i += 1 j += 2 # Transfer analog inputs to input register memory mem_lock.acquire() i = 0 while i < ADC_BYTES: input_regs[i] = adc_shadow[i] i += 1 mem_lock.release() # Transfer holding register memory to the setpoint variable mem_lock.acquire() setpoint = (holding_regs[0] << 8) | holding_regs[1] mem_lock.release()