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/05/19 06:34] (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 ===== | ||
| <code python> | <code python> | ||
| - | import struct | ||
| - | import time | ||
| import _thread | import _thread | ||
| from cubloc import * | from cubloc import * | ||
| + | from machine import * | ||
| + | import os | ||
| + | from time import sleep | ||
| - | # Coils 0-3 -> digital outputs on GP14, GP16, GP18, GP20 | + | machine = os.uname().machine |
| - | # Discrete inputs 0-2 <- digital inputs | + | print(machine) |
| - | # Input registers 0-2 <- ADC readings | + | |
| - | # Holding register 0 -> setpoint value written by the Modbus master | + | |
| - | OUTPUT_PINS = (25, 16, 18, 20) | + | if " |
| - | INPUT_PINS | + | |
| - | ADC_CHANS | + | INPUT_PINS |
| + | ADC_CHANS | ||
| + | else: | ||
| + | OUTPUT_PINS = (25, 16, 17, 18) | ||
| + | INPUT_PINS | ||
| + | ADC_CHANS | ||
| - | # Allocate Modbus memory regions | + | OUTPUT_COUNT |
| - | coils = bytearray(1) # 8 coils (1 byte, bits 0-3 used) | + | INPUT_COUNT |
| - | discrete_inputs | + | ADC_COUNT |
| - | input_regs | + | ADC_BYTES |
| - | holding_regs | + | |
| - | mem_lock | + | |
| - | # Configure | + | # Initialize the physical |
| for pin in OUTPUT_PINS: | for pin in OUTPUT_PINS: | ||
| Output(pin) | Output(pin) | ||
| Low(pin) | Low(pin) | ||
| + | |||
| for pin in INPUT_PINS: | for pin in INPUT_PINS: | ||
| - | Input(pin) | + | Input(pin, 1) |
| - | # Open UART0 at 460800 baud, 8N1 | + | # Configure and start the Modbus RTU slave process |
| - | OpenCom(0, 460800, 3, 1024, 1024) | + | UART_CHANNEL = 0 |
| + | BAUD_RATE = 460800 | ||
| + | PROTOCOL = 3 # 8N1 | ||
| + | BUFFER_SIZE = 64 | ||
| + | SLAVE_ADDRESS = 1 | ||
| - | # Start Modbus | + | # Configure the Modbus memory |
| - | SetModbus(0, 1, coils, discrete_inputs, | + | coils = bytearray(1) |
| + | discrete_inputs = bytearray(2) | ||
| + | input_regs | ||
| + | holding_regs | ||
| + | mem_lock | ||
| + | adc_shadow | ||
| + | setpoint | ||
| + | |||
| + | # Start the Modbus slave | ||
| + | print(" | ||
| + | SetModbus( | ||
| + | UART_CHANNEL, | ||
| + | BAUD_RATE, | ||
| + | PROTOCOL, | ||
| + | BUFFER_SIZE, | ||
| + | BUFFER_SIZE, | ||
| + | SLAVE_ADDRESS, | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | ) | ||
| - | # Main loop: mirror | + | # Run in an infinite |
| + | print(" | ||
| while True: | while True: | ||
| - | # Read coil byte without locking | + | # Read the coil memory |
| + | mem_lock.acquire() | ||
| coils_byte = coils[0] | coils_byte = coils[0] | ||
| + | mem_lock.release() | ||
| - | # Drive output pins from coil bits (master writes coils 0-3) | + | # Drive digital outputs |
| - | | + | i = 0 |
| - | | + | |
| - | High(pin) | + | |
| - | | + | |
| - | Low(pin) | + | |
| - | # Capture | + | # Read digital inputs |
| din_byte = 0 | din_byte = 0 | ||
| - | | + | i = 0 |
| - | if In(pin): | + | while i < INPUT_COUNT: |
| - | din_byte |= (1 << i) | + | if In(INPUT_PINS[i]): |
| + | din_byte |= 1 << i | ||
| + | i += 1 | ||
| - | # Capture ADC readings (prepare values | + | # Transfer digital inputs |
| - | adc_vals = [ADIn(ch) for ch in ADC_CHANS] | + | |
| - | + | ||
| - | # Now write the prepared Modbus | + | |
| mem_lock.acquire() | mem_lock.acquire() | ||
| - | | + | discrete_inputs[0] = din_byte |
| - | | + | mem_lock.release() |
| - | for i, val in enumerate(adc_vals): | + | |
| - | struct.pack_into('> | + | |
| - | | + | |
| - | | + | |
| - | # Read setpoint value from holding register | + | # Read analog inputs |
| - | | + | i = 0 |
| + | | ||
| + | while i < ADC_COUNT: | ||
| + | val = ADIn(ADC_CHANS[i]) | ||
| - | | + | adc_shadow[j] |
| - | </ | + | |
| - | ===== Related APIs ===== | + | i += 1 |
| + | j += 2 | ||
| - | * [[logicpython: | + | # 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() | ||
| + | </ | ||