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 02:46] – [Related APIs] 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 39: | Line 62: | ||
| <code python> | <code python> | ||
| import struct | import struct | ||
| + | import time | ||
| import _thread | import _thread | ||
| - | from cubloc import | + | from cubloc import |
| - | # Coils 0-3 -> digital outputs on GP14, GP16, GP18, GP20 | + | OUTPUT_PINS = (25, 16, 18, 20) |
| - | # Discrete inputs 0-2 <- digital inputs | + | |
| - | # Input registers 0-2 <- ADC readings | + | |
| - | # Holding register 0 -> setpoint value written by the Modbus master | + | |
| - | + | ||
| - | OUTPUT_PINS = (14, 16, 18, 20) | + | |
| INPUT_PINS | INPUT_PINS | ||
| 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 65: | Line 76: | ||
| Input(pin) | Input(pin) | ||
| - | # Open UART1 (GP4 = TX, GP5 = RX) at 9600 baud, 8N1 | + | # Configure and start the Modbus RTU slave process |
| - | OpenCom(1, 9600, 0) | + | UART_CHANNEL |
| + | BAUD_RATE | ||
| + | PROTOCOL = 3 # 8N1 | ||
| + | BUFFER_SIZE = 64 | ||
| + | SLAVE_ADDRESS = 1 | ||
| - | # Start Modbus RTU slave, address | + | coils = bytearray(1) |
| - | SetModbus(1, 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 coils snapshot under lock |
| - | | + | |
| - | for i, pin in enumerate(OUTPUT_PINS): | + | try: |
| - | | + | |
| - | | + | |
| - | else: | + | |
| - | Low(pin) | + | |
| - | | + | |
| - | din_byte = 0 | + | for i, pin in enumerate(OUTPUT_PINS): |
| - | for i, pin in enumerate(INPUT_PINS): | + | |
| - | if In(pin): | + | High(pin) |
| - | din_byte |= (1 << i) | + | else: |
| + | Low(pin) | ||
| + | |||
| + | # Sample physical inputs outside the lock | ||
| + | | ||
| + | for i, pin in enumerate(INPUT_PINS): | ||
| + | if In(pin): | ||
| + | din_byte |= (1 << i) | ||
| + | |||
| + | adc_vals = [ADIn(ch) for ch in ADC_CHANS] | ||
| + | |||
| + | # Publish a coherent snapshot and read setpoint atomically | ||
| + | mem_lock.acquire() | ||
| + | try: | ||
| discrete_inputs[0] = din_byte | discrete_inputs[0] = din_byte | ||
| - | | + | for i, val in enumerate(adc_vals): |
| - | | + | struct.pack_into('> |
| - | struct.pack_into('> | + | |
| - | # Read setpoint value from holding register 0 (master writes) | ||
| setpoint = struct.unpack_from('> | setpoint = struct.unpack_from('> | ||
| + | finally: | ||
| + | mem_lock.release() | ||
| - | | + | |
| </ | </ | ||
| - | |||
| - | ===== Related APIs ===== | ||
| - | |||
| - | * [[logicpython: | ||