Pymate-RS485-basic: Difference between revisions
| Line 44: | Line 44: | ||
[[File:Pymate-RS485-basic-03.png]] | [[File:Pymate-RS485-basic-03.png]] | ||
== Code == | |||
<syntaxhighlight lang="python" line start="1">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 ): | |||
""" Send the MODBUS request to requires Wind Direction """ | |||
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 ): | |||
""" Read response data from RS485, extract direction, convert it to text. | |||
Returns the rotation angle (float), direction (byte) and direction label (string). """ | |||
# Response in 7 bytes | |||
buf = bytearray( 7 ) | |||
rs485.readinto( buf | |||
) | |||
# print( 'Buffer: ', hex(buf[0]), hex(buf[1]), hex(buf[2]), hex(buf[3]), hex(buf[4]), hex(buf[5]), hex(buf[6]) ) | |||
# 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 | |||
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 )</syntaxhighlight> | |||
{{PYMATE-TRAILER}} | {{PYMATE-TRAILER}} | ||
Revision as of 18:36, 24 May 2026
The RS485 bus can be reached on A+, B- terminals.
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.
The master send the request to read register 0x0000 on slave 0x02. The function code 0x03 = 'read holding register'.
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.
The angle can be converted to wind direction thanks to simple rule:
Code
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 ):
""" Send the MODBUS request to requires Wind Direction """
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 ):
""" Read response data from RS485, extract direction, convert it to text.
Returns the rotation angle (float), direction (byte) and direction label (string). """
# Response in 7 bytes
buf = bytearray( 7 )
rs485.readinto( buf
)
# print( 'Buffer: ', hex(buf[0]), hex(buf[1]), hex(buf[2]), hex(buf[3]), hex(buf[4]), hex(buf[5]), hex(buf[6]) )
# 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
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 )PymateIO all right reserved © 2026 - Written by MCHobby for PymateIO



