Обычно достаточно просто включить R_Tig на 1 цикл ПЛК, можно вместо триггера использовать таймер ТР, на 100-300 мс, если вам не нужно проверять записанное.
И таймер и триггер сами сбросят переменную.
Вид для печати
не совсем понимаю как это сделать, устройств у меня 10 штук , у каждого свой сетевой адрес и у каждого свои 2 регистраВложение 81739
или вот так?Вложение 81740
МихаилГл kondor3000 Да спасибо все получилось. Единственное теперь нужно , как то значения преобразовать , в моем скрипте на пк было 2 преобразования. Где мы разбирали 2 регистра по байтам, вычисляли позицию запятой и знак числа и преобразовывали биты в десятичное число и вставляли точку куда нужно
def display_concentration(registers):
if len(registers) < 2:
print("Недостаточно данных для отображения концентрации")
return
byte1 = (registers[0] >> 8) & 0xFF # Старший байт первого регистра
byte2 = registers[0] & 0xFF # Младший байт первого регистра
byte3 = (registers[1] >> 8) & 0xFF # Старший байт второго регистра
byte4 = registers[1] & 0xFF # Младший байт второго регистра
sign_bit = (byte1 >> 7) & 0x01 # Определяем знак (бит 7 в первом байте)
comma_position = byte1 & 0x07 # Определяем позицию запятой (биты 0-2 в первом байте)
sign = '-' if sign_bit else '+'
integer_part = byte2 * 10000 + byte3 * 10 + (byte4 >> 4) # Вычисление целой части
decimal_part = (byte4 & 0x0F) * 100 # Десятичная часть
value = integer_part + decimal_part / 10000 # Собираем число
value = -value if sign_bit else value # Добавляем знак
value /= 10 ** comma_position # Учитываем запятую
value = round(value, 2) # Округляем до двух знаков
print(f"Значение концентрации: {value:.2f}")
и так же Объединяли два регистра в одно 32-битное число, преобразовывали его в строку шестнадцатеричного представления и разделяли число на целую и дробную часть с учетом положения запятой.
def format_value_with_comma(hex_value, comma_position):
value_str = f"{hex_value:08X}" # Преобразует число в строку из 8 шестнадцатеричных символов
integer_part = value_str[2:-comma_position] if comma_position < len(value_str) else '0'
decimal_part = value_str[-comma_position:] if comma_position > 0 else '0'
formatted_value = f"{integer_part},{decimal_part}".lstrip('0') or '0'
return f"{formatted_value[:formatted_value.index(',') + 3]}" if ',' in formatted_value else formatted_value
Я могу теперь написать функциональный блок?) или есть готовые решения?
Если у вас в регистрах нестандартные числа (не real, word и т.п.), то придется писать код преобразования. А если стандартные, но в итоге число не то, что в действительности, то надо пробовать менять местами слова в регистрах. В кодесисе в библиотеках овен есть готовые блоки для этого.
Я бы попробовал для начала считать FLOAT, если не правильное отображение, то поменять местами регистры (потом байты) и проверить.
МихаилГл kondor3000 capzap Значения концентрации и порогов я сейчас получаю в 10 тичной системе , концентрация 1536, порог 1 1040 и порог 2 1056 , если в 16-ричную переводить то 0,0 10 и 20 . Простите ошибся. Получается нужно писать преобразователь, блок или функцию я не нашел
Код:from pymodbus.client.sync import ModbusSerialClient as ModbusClient
import time
# Параметры подключения
PORT = 'COM17'
BAUDRATE = 9600
client = ModbusClient(
method='rtu',
port=PORT,
baudrate=BAUDRATE,
stopbits=1,
parity='N',
timeout=1
)
def read_modbus_data(client, unit_id, address, count):
if not client.connect():
print("Не удалось подключиться к Modbus серверу")
return None
result = client.read_holding_registers(address, count, unit=unit_id)
client.close()
if result.isError():
print("Ошибка чтения данных: ", result)
return None
return result.registers
def format_value_with_comma(hex_value, comma_position):
value_str = f"{hex_value:08X}"
integer_part = value_str[2:-comma_position] if comma_position < len(value_str) else '0'
decimal_part = value_str[-comma_position:] if comma_position > 0 else '0'
formatted_value = f"{integer_part},{decimal_part}".lstrip('0') or '0'
return f"{formatted_value[:formatted_value.index(',') + 3]}" if ',' in formatted_value else formatted_value
def display_registers(registers):
if len(registers) < 2:
print("Недостаточно данных для отображения")
return
combined_hex = (registers[0] << 16) | registers[1]
comma_position = (registers[0] >> 8) & 0xFF
formatted_value = format_value_with_comma(combined_hex, comma_position)
print(f"Значение: {formatted_value}")
def display_concentration(registers):
if len(registers) < 2:
print("Недостаточно данных для отображения концентрации")
return
byte1 = (registers[0] >> 8) & 0xFF
byte2 = registers[0] & 0xFF
byte3 = (registers[1] >> 8) & 0xFF
byte4 = registers[1] & 0xFF
sign_bit = (byte1 >> 7) & 0x01
comma_position = byte1 & 0x07
sign = '-' if sign_bit else '+'
integer_part = byte2 * 10000 + byte3 * 10 + (byte4 >> 4)
decimal_part = (byte4 & 0x0F) * 100
value = integer_part + decimal_part / 10000
value = -value if sign_bit else value
value /= 10 ** comma_position
value = round(value, 2)
print(f"Значение концентрации: {value:.2f}")
def main():
unit_id = 1
count = 2
threshold1_address = 0x02
threshold2_address = 0x04
concentration_address = 0x00
while True:
p1_data = read_modbus_data(client, unit_id, threshold1_address, count)
if p1_data:
print("Установленное значение порога 1:")
display_registers(p1_data)
p2_data = read_modbus_data(client, unit_id, threshold2_address, count)
if p2_data:
print("Установленное значение порога 2:")
display_registers(p2_data)
conc_data = read_modbus_data(client, unit_id, concentration_address, count)
if conc_data:
print("Измеренное значение концентрации:")
display_concentration(conc_data)
time.sleep(3)
if __name__ == "__main__":
main()
Это разработчики СТГ-3 так постарались)) Если я любым методом буду считывать концентрацию и пороги, то буду получать значения , что я выше написал, а потом их приходится конвертировать и получать уже , то что нужно...ппц какой то
Вложение 81748
Вложение 81747