使用Minimalmodbus清除PZEM 016能量计数器遇非法数据值错误
问题:Peacefair AC PZEM 016电能监测仪能量计数器清除失败,报错“Slave reported Illegal Data Value”
我正在尝试给Peacefair AC PZEM 016电能监测仪清除能量计数器,现有脚本可以正常读取寄存器数值,但用minimalmodbus库执行清除操作时一直报错,错误信息是Slave reported Illegal Data Value。设备文档里的“重置能量”功能在2.5章节,但操作始终无法成功。
以下是相关Python代码:
import minimalmodbus import datetime import time import serial import sys import os import threading from crccheck.crc import Crc16 mb_address = 1 clear_energy_command = 0x42 powark_sensor = minimalmodbus.Instrument('/dev/ttyUSB0',mb_address) powark_sensor.serial.baudrate = 9600 powark_sensor.serial.bytesize = 8 powark_sensor.serial.parity = minimalmodbus.serial.PARITY_NONE powark_sensor.serial.stopbits = 1 powark_sensor.serial.timeout = 0.5 powark_sensor.mode = minimalmodbus.MODE_RTU file_path = "/home/josiahferguson/Documents/powark/mb_powark_data.txt" powark_sensor.clear_buffers_before_each_transaction = True powark_sensor.close_port_after_each_call = True print("") print("Requesting Data From Powark...") print("") #single_data = powark.sensor.read_register(1, 1, 3, False) #print(f"Single register data = {single_data}") #function to read powark data def read_sensor_data(): data = powark_sensor.read_registers(0, 10, 4) volts = data[0] / 10 ampslow = int(data[1]) / 1000 ampshigh = int(data[2]) / 1000 wattslow = int(data[3]) / 10 wattshigh = int(data[4]) / 10 watthourslow = int(data[5]) watthourshigh = int(data[6]) hertz = int(data[7]) / 10 powerfactor = int(data[8]) / 100 alarm = data[9] processed_data = { "volts": volts, "ampslow": ampslow, "ampshigh": ampshigh, "wattslow": wattslow, "wattshigh": wattshigh, "watthourslow": watthourslow, "watthourshigh": watthourshigh, "hertz": hertz, "powerfactor": powerfactor, "alarm": alarm, } return processed_data powark_sensor_data = read_sensor_data() #function to write sensor data to file def write_data_to_file(powark_sensor_data, file_path): with open (file_path, "a") as file: timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()) file.write(f"{timestamp}: {powark_sensor_data}\n") def low_byte(value): return value & 0xFF def high_byte(value): return (value >> 8) & 0xFF powark_sensor.write_long(mb_address, 0x42, False, 2) # ~ powark_sensor.serial.open() # ~ time.sleep(1) # ~ # Calculate the CRC-16 using the CRC library # ~ crc = Crc16.calc(bytearray([mb_address, clear_energy_command])) # ~ # Send the slave address, reset command, and CRC-16 # ~ powark_sensor.serial.write(bytearray([mb_address, clear_energy_command, low_byte(crc), high_byte(crc)])) # ~ # Wait for the energy monitor to process the command # ~ time.sleep(0.26) # ~ response = powark_sensor.serial.read(4) # The expected response length is 4 bytes # Check if the response is correct or an error reply # ~ if len(response) == 0: # ~ print("No Response Received") # ~ print("") # ~ elif response[0] == mb_address and response[1] == clear_energy_command: # ~ print("Energy Reset") # ~ print("") # ~ elif response[0] == mb_address and response[1] == 0xC2: # ~ print("Error resetting energy. Abnormal code:", response[2]) # ~ print("") # ~ else: # ~ print("Unexpected response:", response) # ~ print("") #fucntion to clear the energy data from the powark sensor def clear_energy_used(port, mb_adrress): try: powark_sensor.write_register(clear_energy_command, 6) print("Energy data cleared successfully.") except Exception as e: print(f"Error clearing energy data: {e}") #function to display sensor values to the console def print_powark_values(): print(f"Voltage: {powark_sensor_data['volts']} Volts") print("-------------------------") print(f"Current: {powark_sensor_data['ampslow']} Amps") print("-------------------------") #converts Watts to Kilowatts if the value exceeds 999.99 if powark_sensor_data['wattslow'] >= 1000: print(f"Charging Rate: {powark_sensor_data['wattslow']/1000} Kilowatts") else: print(f"Charging Rate: {powark_sensor_data['wattslow']} Watts") print("-------------------------") #converts energy (watt hours) to Kilowatts if the value exceeds 999.99 if powark_sensor_data['watthourslow'] >= 1000: print(f"Energy Added: {powark_sensor_data['watthourslow']/1000} Kilowatts") else: print(f"Energy Added: {powark_sensor_data['watthourslow']} Watts") print("-------------------------") print(f"Frequency: {powark_sensor_data['hertz']} Hz") print("") print(f"{powark_sensor_data['powerfactor']} Powerfactor") print("") print(f"{powark_sensor_data['alarm']}") print("") print_powark_values() print("Writing Data to mb_powark_data.txt File...") write_data_to_file(powark_sensor_data, file_path) print("") print("Now Closing Serial Port") powark_sensor.serial.close() print("") # #user input handling to start logging data to the file entered_value = input('Would you like to start a session?: y or n ') print("") if entered_value == 'y': time.sleep(1) print("Your charging session has started!") print("") max_iterations = int(input("How many iterations would you like this to run?: ")) print("") iteration_count = 0 while iteration_count <= max_iterations: # Read sensor data powark_sensor_data = read_sensor_data() # write_data_to_file(powark_sensor_data, file_path) write_data_to_file(powark_sensor_data, file_path) #print values to console print_powark_values() time.sleep(1) # Close the serial port powark_sensor.serial.close() iteration_count += 1 if iteration_count >= max_iterations: print("") print("Ports now closed") print("") #print("Clearing Data") #clear_energy_used('/dev/ttyUSB0', mb_address) print("Thanks for using Powark!") break # Wait for the specified delay before the next iteration else: print("Ports now closed") print("Thanks for using Powark!")
问题分析与解决方法
根据PZEM 016的Modbus协议规范,能量重置需要使用功能码0x42执行特殊写入操作,你的代码存在参数混淆的问题,具体修正如下:
1. 修正清除函数
替换原有的clear_energy_used函数,使用正确的Modbus参数:
# 修正后的能量清除函数 def clear_energy_used(): try: # 功能码0x42,写入寄存器地址0x0000,固定值0x0000 powark_sensor.write_register(registeraddress=0x0000, value=0x0000, functioncode=0x42) print("能量计数器已成功清除") except Exception as e: print(f"清除失败:{e}")
2. 错误原因说明
- 原代码中
write_long(mb_address, 0x42, False, 2)参数完全错误,write_long的参数顺序是寄存器地址、数值、字节序、功能码,不能把从站地址和功能码乱填。 clear_energy_used函数里的write_register(clear_energy_command, 6)错误地将功能码0x42当成了寄存器地址,这是触发“Illegal Data Value”错误的核心原因。
3. 调用示例
在会话结束后取消注释并调用修正后的函数:
if iteration_count >= max_iterations: print("") print("Ports now closed") print("") print("正在清除能量数据...") clear_energy_used() print("Thanks for using Powark!") break
额外注意事项
- 执行清除操作前,确保设备通信正常(可以先读取一次数据验证)。
- 操作后建议等待0.5秒再读取能量值,确认清除效果。
内容的提问来源于stack exchange,提问作者moosetinkerer
相关产品推荐
相关产品推荐

