И снова я) Подскажите как получается такой адрес?
Если в плк имеем адрес 78:11 Включение вентилятора 18
Вложение 84866
то в панели на кнопке включения этого же вентилятора имеем адрес 0x 1259
Вложение 84867
Вложение 84868
Вид для печати
И снова я) Подскажите как получается такой адрес?
Если в плк имеем адрес 78:11 Включение вентилятора 18
Вложение 84866
то в панели на кнопке включения этого же вентилятора имеем адрес 0x 1259
Вложение 84867
Вложение 84868
Есть руководство по программированию ПЛК1ХХ, там много чего описано:
Вложение 84869
Всем спасибо большое , разобрался
Накидал программу, для быстрого подсчета всех адресов делаем экспорт конфигурации из плк или пишем количество блоков, по порядку ручками в программу и получаем весь список адресов. Пишите ваши пожелания и хотелки, добавлю)
Вложение 84878
Код:import tkinter as tk
from tkinter import ttk, messagebox, filedialog
class ModbusAddressCalculatorOrder(tk.Tk):
def __init__(self):
super().__init__()
self.title("Калькулятор адресов")
self.geometry("750x650")
self.resizable(True, True)
self.blocks = []
self.create_widgets()
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=1)
self.rowconfigure(3, weight=1)
self.rowconfigure(6, weight=1)
def create_widgets(self):
padding = {'padx': 10, 'pady': 5}
ttk.Label(self, text="Тип блока:").grid(column=0, row=0, sticky="w", **padding)
self.type_var = tk.StringVar()
self.type_combo = ttk.Combobox(self, textvariable=self.type_var,
values=["Float", "2 byte", "8 bit", "4 bytes"], state="readonly")
self.type_combo.grid(column=1, row=0, sticky="ew", **padding)
self.type_combo.current(0)
ttk.Label(self, text="Количество:").grid(column=0, row=1, sticky="w", **padding)
self.count_entry = ttk.Entry(self)
self.count_entry.grid(column=1, row=1, sticky="ew", **padding)
self.count_entry.insert(0, "1")
self.btn_add = ttk.Button(self, text="Добавить блок", command=self.add_block)
self.btn_add.grid(column=0, row=2, columnspan=2, pady=10, sticky="ew")
self.btn_load_exp = ttk.Button(self, text="Загрузить .EXP", command=self.load_exp_file)
self.btn_load_exp.grid(column=0, row=7, columnspan=2, pady=10, sticky="ew")
tree_frame = ttk.Frame(self)
tree_frame.grid(column=0, row=3, columnspan=2, sticky="nsew", padx=10, pady=5)
tree_frame.columnconfigure(0, weight=1)
tree_frame.rowconfigure(0, weight=1)
self.tree = ttk.Treeview(tree_frame, columns=("Тип", "Количество"), show="headings")
self.tree.heading("Тип", text="Тип блока")
self.tree.heading("Количество", text="Количество")
self.tree.column("Тип", width=250)
self.tree.column("Количество", width=100)
self.tree.grid(column=0, row=0, sticky="nsew")
tree_scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview)
tree_scrollbar.grid(column=1, row=0, sticky="ns")
self.tree.configure(yscrollcommand=tree_scrollbar.set)
btn_frame = ttk.Frame(self)
btn_frame.grid(column=0, row=4, columnspan=2, pady=10, sticky="ew")
btn_frame.columnconfigure((0, 1, 2), weight=1)
ttk.Button(btn_frame, text="Удалить блок", command=self.delete_block).grid(column=0, row=0, padx=5, sticky="ew")
ttk.Button(btn_frame, text="Вверх", command=self.move_up).grid(column=1, row=0, padx=5, sticky="ew")
ttk.Button(btn_frame, text="Вниз", command=self.move_down).grid(column=2, row=0, padx=5, sticky="ew")
self.btn_calc = ttk.Button(self, text="Рассчитать адреса", command=self.calculate_addresses)
self.btn_calc.grid(column=0, row=5, columnspan=2, pady=10, sticky="ew")
self.text_frame = ttk.Frame(self)
self.text_frame.grid(column=0, row=6, columnspan=2, sticky="nsew", padx=10, pady=5)
self.text_frame.columnconfigure(0, weight=1)
self.text_frame.rowconfigure(0, weight=1)
self.result_text = tk.Text(self.text_frame, wrap="none", font=("Consolas", 10))
self.result_text.grid(column=0, row=0, sticky="nsew")
self.scrollbar_v = ttk.Scrollbar(self.text_frame, orient="vertical", command=self.result_text.yview)
self.scrollbar_v.grid(column=1, row=0, sticky="ns")
self.result_text.configure(yscrollcommand=self.scrollbar_v.set)
self.scrollbar_h = ttk.Scrollbar(self.text_frame, orient="horizontal", command=self.result_text.xview)
self.scrollbar_h.grid(column=0, row=1, sticky="ew")
self.result_text.configure(xscrollcommand=self.scrollbar_h.set)
self.result_text.config(state="normal")
def add_block(self):
t = self.type_var.get()
c = self.count_entry.get()
try:
c = int(c)
if c <= 0:
raise ValueError
except ValueError:
messagebox.showerror("Ошибка", "Введите корректное положительное число для количества!")
return
self.blocks.append({"type": t, "count": c})
self.refresh_tree()
def refresh_tree(self):
self.tree.delete(*self.tree.get_children())
for idx, block in enumerate(self.blocks):
self.tree.insert("", "end", iid=idx, values=(block["type"], block["count"]))
def delete_block(self):
selected = self.tree.selection()
if not selected:
messagebox.showinfo("Информация", "Выберите блок для удаления.")
return
idx = int(selected[0])
del self.blocks[idx]
self.refresh_tree()
def move_up(self):
selected = self.tree.selection()
if not selected:
messagebox.showinfo("Информация", "Выберите блок для перемещения.")
return
idx = int(selected[0])
if idx == 0:
return
self.blocks[idx], self.blocks[idx - 1] = self.blocks[idx - 1], self.blocks[idx]
self.refresh_tree()
self.tree.selection_set(idx - 1)
def move_down(self):
selected = self.tree.selection()
if not selected:
messagebox.showinfo("Информация", "Выберите блок для перемещения.")
return
idx = int(selected[0])
if idx == len(self.blocks) - 1:
return
self.blocks[idx], self.blocks[idx + 1] = self.blocks[idx + 1], self.blocks[idx]
self.refresh_tree()
self.tree.selection_set(idx + 1)
def calculate_addresses(self):
addr = 0
lines = []
for idx, block in enumerate(self.blocks):
t = block["type"]
c = block["count"]
if t in ["Float", "4 bytes"]:
length = 2
total_length = c * length
elif t == "2 byte":
length = 1
total_length = c * length
elif t == "8 bit":
total_length = (c + 1) // 2
else:
messagebox.showerror("Ошибка", f"Неизвестный тип блока: {t}")
return
start_block = addr
end_block = addr + total_length - 1
lines.append(f"{idx + 1}. {t} ({c} шт.): от регистра {start_block} до {end_block}")
if t in ["Float", "2 byte", "4 bytes"]:
for i in range(c):
start_el = addr + i * length
end_el = start_el + length - 1
if length == 1:
lines.append(f" Элемент {i + 1}: регистр {start_el}")
else:
lines.append(f" Элемент {i + 1}: регистры {start_el} - {end_el}")
elif t == "8 bit":
for i in range(c):
reg = addr + i // 2
bit_pos = (i % 2) * 8
bit_addresses = [reg * 16 + bit_pos + b for b in range(8)]
bit_addresses_str = ", ".join(str(b) for b in bit_addresses)
lines.append(f" Элемент {i + 1}: регистр {reg}, биты {bit_pos}-{bit_pos + 7} → битовые адреса [{bit_addresses_str}]")
addr = end_block + 1
if lines:
lines.append(f"\nИтоговый конечный адрес регистра: {addr - 1}")
else:
lines.append("Список блоков пуст")
self.result_text.delete(1.0, tk.END)
self.result_text.insert(tk.END, "\n".join(lines))
def load_exp_file(self):
filepath = filedialog.askopenfilename(
title="Выберите файл .EXP",
filetypes=[("EXP files", "*.exp"), ("Все файлы", "*.*")]
)
if not filepath:
return
blocks_from_file = self.parse_exp_modules(filepath)
if blocks_from_file:
self.blocks = []
for count, block_type in blocks_from_file:
self.blocks.append({"type": block_type, "count": count})
self.refresh_tree()
messagebox.showinfo("Готово", f"Загружено {len(blocks_from_file)} блоков из файла.")
else:
messagebox.showwarning("Внимание", "Не удалось найти подходящие блоки в файле.")
def parse_exp_modules(self, filename):
results = []
count = 0
prev_module = None
module_aliases = {
'float': 'Float',
'2 byte': '2 byte',
'8 bits': '8 bit',
'4 byte': '4 bytes' # поддержка _MODULE_NAME: '4 byte'
}
encodings = ['utf-8', 'cp1251', 'latin1']
for enc in encodings:
try:
with open(filename, 'r', encoding=enc) as f:
for line in f:
line = line.strip()
if line.startswith("_MODULE_NAME:"):
start = line.find("'")
end = line.rfind("'")
if start != -1 and end != -1 and end > start:
raw = line[start + 1:end].strip().lower()
block_type = module_aliases.get(raw)
if not block_type:
if prev_module is not None:
results.append((count, prev_module))
prev_module = None
count = 0
continue
if block_type == prev_module:
count += 1
else:
if prev_module is not None:
results.append((count, prev_module))
prev_module = block_type
count = 1
if prev_module is not None:
results.append((count, prev_module))
break
except Exception:
continue
return results
if __name__ == "__main__":
app = ModbusAddressCalculatorOrder()
app.mainloop()
Добрый день, подскажите пожалуйста вот такой момент.
Если я добавлю в модбас fix еще 1 адрес , то у меня все адреса что ниже сдвинуться? Или то что я добавляю в модбаск fix на адресацию не повлияет.
Вложение 85038
Имею контроллер ОВЕН ПЛК 110-60 и среду программирования CoDeSys V2.3. Настройка фильтров входных сигналов распространяется на все входы (кроме быстрых)? У быстрых своя настройка. Или можно настраивать индивидуально каждую группу из 8 входов Discrete inputs[FIX] AT %IB.0, AT %IB.1, AT %IB.2 и AT %IB.3? Я что-то не нашел индивидуальную настройку для AT %IB.0, AT %IB.1, AT %IB.2 и AT %IB.3.
Добрый день, подскажите бредмаузер может блокировать связь между онлайн симулятором панели weintek и codesys 2.5 режиме эмуляции. Раньше все работало , теперь нет