This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| logicpython:cubloc_api:setmodbus [2026/04/10 07:11] – [Example] mfranklin | logicpython:cubloc_api:setmodbus [2026/04/14 05:10] (current) – [Example] mfranklin | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== SetModbus ====== | ====== SetModbus ====== | ||
| - | Start the LogicPython Modbus RTU slave worker using a pre-opened UART '' | + | Configure UART settings and start the LogicPython Modbus RTU slave process. |
| ===== Syntax ===== | ===== Syntax ===== | ||
| Line 8: | Line 8: | ||
| from cubloc import SetModbus | from cubloc import SetModbus | ||
| - | SetModbus(channel: | + | SetModbus(channel: int, |
| + | baudRate: int, | ||
| + | protocol: int, | ||
| + | recvSize: int, | ||
| + | sendSize: int, | ||
| slaveAddress: | slaveAddress: | ||
| coils: object, | coils: object, | ||
| Line 20: | Line 24: | ||
| ===== Parameters ===== | ===== Parameters ===== | ||
| - | | + | |
| - | * **slaveAddress**: | + | * **baudRate**: |
| - | * **coils**: Writable bit-packed coil buffer (8 '' | + | * **protocol**: |
| - | * **discreteInputs**: | + | * **recvSize**: |
| - | * **inputRegisters**: | + | * **sendSize**: |
| - | * **holdingRegisters**: | + | |
| - | * **memoryLock**: | + | * **coils**: Writable bit-packed coil buffer (8 '' |
| - | * **returnInterval**: | + | * **discreteInputs**: |
| + | * **inputRegisters**: | ||
| + | * **holdingRegisters**: | ||
| + | * **memoryLock**: | ||
| + | * **returnInterval**: | ||
| + | |||
| + | '' | ||
| + | |||
| + | ^ 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 '' | ||
| + | |||
| + | Common '' | ||
| + | |||
| + | ^ protocol ^ Frame format ^ | ||
| + | | 3 | 8N1 | | ||
| + | | 11 | 8E1 | | ||
| + | | 19 | 8O1 | | ||
| + | | 7 | 8N2 | | ||
| ===== Exceptions ===== | ===== Exceptions ===== | ||
| - | | + | |
| - | * [[https:// | + | * [[https:// |
| - | * [[https:// | + | * [[https:// |
| ===== Example ===== | ===== Example ===== | ||
| Line 42: | Line 65: | ||
| import _thread | import _thread | ||
| from cubloc import * | from cubloc import * | ||
| - | |||
| - | # Coils 0-3 -> digital outputs on GP14, GP16, GP18, GP20 | ||
| - | # Discrete inputs 0-2 <- digital inputs | ||
| - | # Input registers 0-2 <- ADC readings | ||
| - | # Holding register 0 -> setpoint value written by the Modbus master | ||
| OUTPUT_PINS = (25, 16, 18, 20) | OUTPUT_PINS = (25, 16, 18, 20) | ||
| Line 52: | Line 70: | ||
| ADC_CHANS | ADC_CHANS | ||
| - | # Allocate Modbus memory regions | ||
| - | coils = bytearray(1) | ||
| - | discrete_inputs = bytearray(1) | ||
| - | input_regs | ||
| - | holding_regs | ||
| - | mem_lock | ||
| - | |||
| - | # Configure physical I/O | ||
| for pin in OUTPUT_PINS: | for pin in OUTPUT_PINS: | ||
| Output(pin) | Output(pin) | ||
| Line 66: | Line 76: | ||
| Input(pin) | Input(pin) | ||
| - | # Open UART0 at 460800 baud, 8N1 | + | # Configure and start the Modbus RTU slave process |
| - | OpenCom(0, 460800, | + | UART_CHANNEL = 0 |
| + | BAUD_RATE = 115200 | ||
| + | PROTOCOL = 3 # 8N1 | ||
| + | BUFFER_SIZE = 64 | ||
| + | SLAVE_ADDRESS = 1 | ||
| - | # Start Modbus RTU slave, address | + | coils = bytearray(1) |
| - | SetModbus(0, 1, coils, discrete_inputs, | + | discrete_inputs = bytearray(1) |
| + | input_regs | ||
| + | holding_regs | ||
| + | mem_lock | ||
| + | |||
| + | SetModbus(UART_CHANNEL, | ||
| + | BAUD_RATE, | ||
| + | PROTOCOL, | ||
| + | BUFFER_SIZE, | ||
| + | BUFFER_SIZE, | ||
| + | SLAVE_ADDRESS, | ||
| + | | ||
| - | # Main loop: mirror Modbus memory to/from physical I/O every 10 ms | ||
| while True: | while True: | ||
| - | # Read coil byte without locking (master may update | + | # Read coils snapshot under lock |
| - | coils_byte = coils[0] | + | mem_lock.acquire() |
| + | | ||
| + | | ||
| + | finally: | ||
| + | mem_lock.release() | ||
| - | # Drive output pins from coil bits (master writes coils 0-3) | + | # Drive outputs |
| for i, pin in enumerate(OUTPUT_PINS): | for i, pin in enumerate(OUTPUT_PINS): | ||
| if coils_byte & (1 << i): | if coils_byte & (1 << i): | ||
| Line 84: | Line 112: | ||
| Low(pin) | Low(pin) | ||
| - | # Capture digital | + | # Sample physical |
| din_byte = 0 | din_byte = 0 | ||
| for i, pin in enumerate(INPUT_PINS): | for i, pin in enumerate(INPUT_PINS): | ||
| Line 90: | Line 118: | ||
| din_byte |= (1 << i) | din_byte |= (1 << i) | ||
| - | # Capture ADC readings (prepare values to write into input_regs) | ||
| adc_vals = [ADIn(ch) for ch in ADC_CHANS] | adc_vals = [ADIn(ch) for ch in ADC_CHANS] | ||
| - | # Now write the prepared Modbus memory updates under lock only while writing | + | # Publish a coherent snapshot and read setpoint atomically |
| mem_lock.acquire() | mem_lock.acquire() | ||
| try: | try: | ||
| discrete_inputs[0] = din_byte | discrete_inputs[0] = din_byte | ||
| + | |||
| for i, val in enumerate(adc_vals): | for i, val in enumerate(adc_vals): | ||
| struct.pack_into('> | struct.pack_into('> | ||
| + | |||
| + | setpoint = struct.unpack_from('> | ||
| finally: | finally: | ||
| mem_lock.release() | mem_lock.release() | ||
| - | |||
| - | # Read setpoint value from holding register 0 (master may write it) without locking | ||
| - | setpoint = struct.unpack_from('> | ||
| time.sleep(0.010) | time.sleep(0.010) | ||
| </ | </ | ||
| - | |||
| - | ===== Related APIs ===== | ||
| - | |||
| - | * [[logicpython: | ||