Arduino Modbus RTU传输JSON:Python端uint16_t与字符串互转求助
Got it, let's break this down for you. I see you're doing a fun (if unorthodox) workaround shoving JSON into Modbus registers—let's get that data conversion sorted out properly.
1. Converting uint16_t Register Data Back to JSON String (Python)
Your Arduino code packs two ASCII characters from the JSON string into each uint16_t register using word(json[i], json[i+1]), which treats the first character as the high byte and the second as the low byte (big-endian order). To reverse this in Python:
# Your received register data from minimalmodbus received_regs = [31522, 26980, 30754, 14897, 13363, 12332, 8814, 30305, 27765, 25890, 14896, 11298, 29558, 24940, 30053, 8762, 8749, 13624, 11824, 12322] def regs_to_json(register_data): json_chars = [] for reg in register_data: # Convert each uint16_t to 2 bytes in big-endian order byte_pair = reg.to_bytes(2, byteorder='big') # Decode each byte to its ASCII character and collect json_chars.append(byte_pair[0].decode('ascii')) json_chars.append(byte_pair[1].decode('ascii')) # Join characters and strip any trailing null bytes (from unused registers) return ''.join(json_chars).rstrip('\x00') # Test the conversion original_json = regs_to_json(received_regs) print(original_json) # Output should be: {"idx":1430,"nvalue":0,"svalue":"-58.00"}
2. Converting a Python String to uint16_t Array for Modbus Transmission
To send a JSON string (or any string) from Python to your Arduino via Modbus, we reverse the packing process: take two characters at a time, convert each to their ASCII value, then combine them into a uint16_t (high byte first):
def json_to_regs(json_string): register_array = [] # Pad string with a null byte if length is odd (to make pairs) if len(json_string) % 2 != 0: json_string += '\x00' # Process characters in pairs for i in range(0, len(json_string), 2): # Get ASCII values of the two characters high_byte = ord(json_string[i]) low_byte = ord(json_string[i+1]) # Combine into a uint16_t (shift high byte left by 8 bits, OR with low byte) register_val = (high_byte << 8) | low_byte register_array.append(register_val) return register_array # Test the conversion with your original JSON test_json = '{"idx":1430,"nvalue":0,"svalue":"-58.00"}' converted_regs = json_to_regs(test_json) print(converted_regs) # Output should match the first 19 values of your received register data (since 38 chars = 19 registers)
Key Notes to Keep in Mind
- Byte Order Matters: Always use big-endian (
byteorder='big') when converting—this matches how Arduino'sword()function packs the characters. Using little-endian will give you garbage text. - Unused Registers: Your Arduino exposes 100 registers, so Python may read trailing null values. The
rstrip('\x00')in the first function cleans these up so your JSON is valid. - String Length Limits: Each register holds 2 characters, so your JSON can't be longer than 200 characters (for 100 registers). If you need longer strings, you'll have to split them across multiple read/write operations.
- Modbus Best Practice: As you noted, this isn't how Modbus was designed. For production use, consider using standard register mappings or a protocol built for string/JSON data (like MQTT) instead.
内容的提问来源于stack exchange,提问作者martin

