Pymate-RS485-basic

From pymate.io wiki
Revision as of 15:36, 29 May 2026 by Dodomi (talk | contribs) (→‎Unable to communicate over RS485)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search


The RS485 bus can be reached on A+, B- terminals.

Pymate-Core-RS485.jpg

This is an HALF-DUPLEX RS485 implementation using only 2 wires.

Accessing the RS485 bus

The RS485 bus is available through the Board.rs485 property from pymate.board library.

The property returns the UART object to communicates over the RS485 bus and the tx_mode pin to switch between RX (receiving) and TX (emitting) on the RS485 bus.


from pymate.board import Board
brd = Board()
rs485,tx_mode = brd.rs485(baudrate=9600)

Switch on the tx_mode pin before emitting data on the bus then switch tx_mode off (receiving) immediately after to get ready for receiving the response.

Data emission and reception uses the micropython UART class as described in the MicroPython machine.UART documentation.

Practical example

The following example shows how to grab the data from a RS485 Wind Direction device.

The Wind Direction is a Modbus device. So the example script below will implements the raw Modbus request (without Modbus library) and decipher the Modbus response.

That example demonstrate RS485 direct access.

Pymate-RS485-basic-00.png

The master send the request to read register 0x0000 on slave 0x02. The function code 0x03 = 'read holding register'.

Pymate-RS485-basic-01.png

From that request we do expect the following response from the device.

The data contains the angular position in degrees * 10 the value is encoded as an uint16.

Pymate-RS485-basic-02.png

The angle can be converted to wind direction thanks to simple rule:

Pymate-RS485-basic-03.png

Code

The example is articulated around the:

  • rs485 instance creation with rs485, tx_mode = brd.rs485
  • send_request : emitting the request to the device over RS485 with tx_mode.on() then rs485.write() followed by tx_mode.off()
  • read_response : receiving response over RS485 with rs485.readinto()

Remark: The two data bytes of the response are transformed to uint16 (Unsigned 16bit Integer) with the struct.unpack().

from pymate.board import Board
import time, struct

DIR_TO_TEXT = ['North', 'Northeast by North', 'Northeast', 'Northeast by east', 'East',
            'Southeast by east', 'Southeast', 'Southeast by south', 'South', 'Southwest by south',
            'Southwest', 'Southwest by west', 'West', 'Northwest by west', 'Northwest', 'Northwest by north' ]

def dir_as_text( value ):
    if 0<=value<=len(DIR_TO_TEXT):
        return DIR_TO_TEXT[value]
    return '???'


def send_request( rs485, tx_mode ):
    tx_mode.on()
    request_msg = [0x02,0x03,0x00,0x00,0x00,0x01,0x84,0x39]
    winddir_request = bytearray( request_msg )
    rs485.write( winddir_request )
    tx_mode.off()


def read_response(rs485,  tx_mode ):
    # Response in 7 bytes
    buf = bytearray( 7 )
    rs485.readinto( buf )

    # Decode the response
    # 0 & 1 are the slave addr + function code
    if not(  (buf[0]==0x02) and (buf[1]==0x03) ):
        raise Exception( 'Invalid Slave/function' )
    if buf[2] != 0x02:
        raise Exception( 'Invalid response length' )
    # bytes 3 & 4 are the data. With value in degree * 10.
    # bytes 5 & 6 are CRC (not checked here)
    # Decode unit16
    value = struct.unpack('>H', buf[3:5])[0]
    degree = value/10
    orientation = int(degree/22.5) # from 0 to 15   
    
    # Returns the direction-value and direction-label
    return degree, orientation, dir_as_text( orientation )
    

# === Main Program ===
brd = Board()
rs485,tx_mode = brd.rs485(baudrate=9600)
while True:
    send_request( rs485, tx_mode )
    time.sleep_ms( 100 ) # give sometime for the buffer to get data, Tune it as needed
    try:
        degree,value,label = read_response( rs485, tx_mode )
        print( "Direction:",value,'=', label, "| Degree:", degree )
    except Exception as err:
        print( 'Error decoding response' )
        print( '[ERROR]', err )
    time.sleep_ms( 1000 )

Once running, the script will return the following results

Direction: 4 = East | Degree: 100.2
Direction: 4 = East | Degree: 100.2
Direction: 4 = East | Degree: 100.2
Direction: 5 = Southeast by east | Degree: 129.6
Direction: 6 = Southeast | Degree: 135.2
Direction: 1 = Northeast by North | Degree: 43.2
Direction: 5 = Southeast by east | Degree: 119.8
Direction: 6 = Southeast | Degree: 153.7
Direction: 7 = Southeast by south | Degree: 174.8
Direction: 14 = Northwest | Degree: 333.7
Direction: 4 = East | Degree: 110.5
Direction: 8 = South | Degree: 199.5
Direction: 10 = Southwest | Degree: 242.7
Direction: 11 = Southwest by west | Degree: 264.8
Direction: 11 = Southwest by west | Degree: 268.4
Direction: 12 = West | Degree: 270.0

RS485 Errors

Unable to communicate over RS485

Sometime, it is necessary to give a little push to the RS485 bus to improve communication signal.

When the 120 Ω terminator resistor is not enough to a communication, you can add a 1 KΩ Pull-Up Resistor from A+ to 5V as well as a 1 KΩ pull-Down resistor to GND.

Here an example based on Power-Meter.

Pymate-Modbus-basic-20.png


PymateIO all right reserved © 2026 - Written by MCHobby for PymateIO