driver lader, C Script
Theo tôi, chưa cần tạo thêm SCL Driver ngay nếu ScadaWeb của bạn đã có Script C# và LadderDriver.
Hai thứ này có thể bổ trợ nhau:
Script C#: xử lý thuật toán, tính toán, điều kiện phức tạp, xử lý dữ liệu và các hàm tùy chỉnh.
LadderDriver: lập trình điều khiển bằng sơ đồ tiếp điểm, cuộn dây, timer, counter và các FB tái sử dụng.
SCL: là một ngôn ngữ lập trình PLC theo kiểu văn bản có cấu trúc, thường dùng trong môi trường Siemens. Nếu muốn hỗ trợ SCL trong ScadaWeb, bạn cần xác định rõ cách phân tích và thực thi mã SCL; chỉ thêm một driver mang tên SCL chưa đủ để chạy được mã.
úng rồi! Với cấu trúc JSON bạn đưa ra, tôi hiểu chính xác hơn cơ chế thư viện FB Ladder của ScadaWeb.
Bạn đã có định dạng lưu trữ logic Ladder bằng JSON. Không cần chuyển sang SCL hay viết lại bằng C# chỉ để tạo thư viện. Bạn có thể dùng chính cấu trúc này làm định dạng chuẩn cho FB Library.
1. JSON của bạn đang mô tả điều gì?
Trong ví dụ
Block_1, logic Ladder tương đương với mạch tự giữ motor:Sơ đồ logic tương ứng
StartNO
∥
outHai nhánh song song (PAR)
StopNC
COIL
outBiểu thức logic dự kiến là:
\[ out_{next}=(Start\lor out_{current})\land\neg Stop \]Đây là mạch tự giữ: Start bật đầu ra,
outduy trì trạng thái, Stop ngắt đầu ra.2. Cách xây dựng thư viện phù hợp nhất
Tôi đề xuất giữ nguyên định dạng JSON hiện tại và xây dựng thêm cơ chế đóng gói thư viện.
Thành phần
Nhiệm vụ
placeplate_LADER.htmlThiết kế Ladder, khai báo biến và chân I/O
JSON FB
Lưu
vars,nets,Items,Branchesvà metadataZIP Library
Đóng gói một hoặc nhiều FB JSON cùng thông tin thư viện
LadderDriver
Nhập ZIP, chọn FB và gán tag cho các chân
Ladder Runtime
Thực thi logic theo chu kỳ quét
Ví dụ khi thêm FB vào LadderDriver:
#Start→ tagMotor01_Start#Stop→ tagMotor01_Stop#out→ tagMotor01_Run
Các tag có tiền tố
#là biến nội bộ của FB theo quy ước bạn đang sử dụng; khi triển khai cần bảo đảm bộ nạp thư viện thay thế hoặc ánh xạ chúng đúng cách.3. Có một điểm cần thiết kế đúng
Trong JSON của bạn,
outđược khai báo làInOutvà vừa được đọc trong nhánh tự giữ, vừa được ghi bởi cuộn dâyCOIL.Khi tạo nhiều instance, ví dụ
Motor01vàMotor02, mỗi instance phải có trạng tháioutriêng. Đồng thời, Runtime cần xử lý đúng thứ tự đọc/ghi và chu kỳ quét để tránh mất trạng thái tự giữ.Kết luận: Giữ JSON làm định dạng logic Ladder chuẩn là hợp lý nhất. Việc tiếp theo là xây dựng
placeplate_LADER.htmlđể xuất FB JSON thành ZIP và sửa LadderDriver để nhập thư viện, ánh xạ tag, tạo instance và chạy logic bằng Runtime hiện có. Không cần thêm SCL Driver cho chức năng này.
hiện tại chưa cần SCL
1. Khi nào cần SCL Driver?
Nhu cầu | Có cần SCL? |
|---|---|
Điều khiển motor, contactor, liên động | Không bắt buộc; Ladder phù hợp |
Tính toán, xử lý thuật toán phức tạp bằng C# | Thường không cần |
Tái sử dụng hàm qua thư viện FB ZIP | Không cần SCL nếu FB Ladder đáp ứng |
Nhập mã SCL từ Siemens TIA Portal | Có, nếu cần tương thích mã nguồn |
Muốn kỹ sư PLC viết Structured Text trực tiếp | Nên cân nhắc bổ sung |
2. Tôi đề xuất cho ScadaWeb
LadderDriver + FB Library
Điều khiển logic, thiết kế kéo thả, thư viện ZIP dùng lại.
Script C#
Thuật toán tùy chỉnh, tính toán và xử lý dữ liệu.
SCL Editor/Runtime
Bổ sung khi cần viết hoặc chuyển đổi chương trình SCL.
Lưu ý: C# và SCL không hoàn toàn tương đương về kiểu dữ liệu PLC, chu kỳ quét, biến có nhớ và timer/counter. Nếu muốn C# đảm nhiệm cả hai vai trò, cần thiết kế quy tắc thực thi rõ ràng, không nên cho Script tùy ý truy cập trực tiếp đầu ra thiết bị.
Kết luận: Tôi khuyên bạn hoàn thiện LadderDriver và thư viện FB trước. Khi cần tương thích Siemens hoặc muốn người dùng viết mã Structured Text, lúc đó mới bổ sung SCL. Cách này tránh phát triển hai bộ thực thi trùng chức năng và giảm độ phức tạp của ScadaWeb
trong LadderDriver.cs: khai báo ở LdInfo.All và viết logic ở case trong EvalEl. Giao diện sẽ tự hiện hàm mới.
Zip bạn gửi có 4 file, gồm LadderDriver.cs, LadderDialog.razor, app.css và file hướng dẫn. Các phần khác của project (ScadaEngine, các driver còn lại, file .csproj) không có trong zip nên mình không biết chúng có dùng NuGet hay không.
Mình đã thêm thư viện lệnh theo bố cục TIA Portal vào Basic instructions. Phần driver và giao diện đều biên dịch sạch trong project thử nghiệm, nhưng mình chưa chạy được app thật nên chưa thấy giao diện hiển thị.
Giải nén ladder_update.zip chép đè vào project, giữ nguyên đường dẫn. File thay đổi: LadderDriver.cs, Components/LadderDialog.razor, wwwroot/app.css, HUONG_DAN_LADDER.md. ladder.js không cần sửa, và Models.cs, ScadaEngine.cs, Home.razor, App.razor mình không đụng tới.
Nhóm lệnh trong palette (mới thêm in đậm):
- Timer: TP, TON, TOF, TONR, –(TP)–, –(TON)–, –(TOF)–, –(TONR)–, –(RT)–, –(PT)–.
- Counter: CTU, CTD, CTUD.
- Comparator: các lệnh CMP có sẵn, thêm IN_Range, OUT_Range, –|OK|–, –|NOT_OK|–.
- Math: CALCULATE (gõ biểu thức theo IN1..IN4), ADD, SUB, MUL, DIV, rồi MOD, NEG, INC, DEC, ABS, MIN, MAX, LIMIT, SQR, SQRT, LN, EXP, SIN, COS, TAN, ASIN, ACOS, ATAN, FRAC, EXPT.
- Move: MOVE, MOVE_BLK, UMOVE_BLK, FILL_BLK, UFILL_BLK, SWAP.
- Conversion: CONVERT, ROUND, CEIL, FLOOR, TRUNC, SCALE_X, NORM_X.
- Program control: –(JMP)–, –(JMPN)–, LABEL, JMP_LIST, –(RET)–.
- Runtime control: STP.
- Word logic: AND, OR, XOR, INVERT, DECO, ENCO, SEL, MUX, DEMUX.
- Shift and rotate: SHR, SHL, ROR, ROL.
Nhóm Bit logic đã đủ từ trước, mình chỉ giữ nguyên.
Ngoài lệnh, mình thêm vài thứ để dùng thư viện lớn dễ hơn:
- Ô tìm lệnh phía trên bảng lệnh.
- Bấm đúp lệnh để chèn vào điểm đang chọn trên dây.
- Ô thả xuống chọn kiểu DWORD/WORD/BYTE hoặc INT/DINT/REAL... trong các hộp lệnh cần kiểu.
- Ô văn bản riêng cho LABEL và biểu thức CALCULATE, không bị báo “không thấy tag”.
Khác với TIA:
- Lệnh nhảy chỉ nhảy tiến, trong cùng một Program, để tránh vòng lặp vô hạn làm đứng vòng quét.
- Move block làm việc trên danh sách tag ngăn bởi dấu phẩy, vì ScadaWeb không có kiểu mảng.
- Lệnh tính toán gặp lỗi (chia 0, SQRT số âm...) thì ENO = FALSE và không ghi OUT.
- SCALE_X và NORM_X chặn kết quả ở biên và đặt ENO = FALSE khi VAL ngoài miền. Đây là cách mình chọn, chưa đối chiếu với tài liệu Siemens, nên bạn kiểm tra thêm nếu cần giống hệt.
Chưa thêm: ENDIS_PW, RE_TRIGR, GET_ERROR, GET_ERR_ID, RUNTIME, Serialize/Deserialize, MOVE_BLK_VARIANT, SWITCH và các thư mục Variant/Array/Legacy. Các lệnh này gắn với PLC thật, DB hoặc kiểu dữ liệu phức hợp nên không có nghĩa tương ứng ở đây.
Đã kiểm tra: mình chạy thử 21 phép kiểm tra trên engine: CALCULATE, MOD, LIMIT, SQRT, shift/rotate, AND, DECO, ENCO, MUX, CONVERT, JMP/LABEL, timer cuộn dây, RT, CTUD, TONR. Tất cả đều khớp kết quả mong đợi.
Project dùng gói NuGet nên mình không build được toàn bộ. Nếu build báo lỗi ở LadderDialog.razor hoặc LadderDriver.cs, gửi mình dòng lỗi để sửa ngay.
Cách dùng từng lệnh mới, kèm các quy ước ở trên, nằm trong HUONG_DAN_LADDER.md.
Đang viết lõi driver LADDER (LadderDriver.cs). Mình cũng cài xong .NET SDK trong máy để biên dịch thử các file mới trước khi đóng gói.
Mình đã thêm driver LADDER vào project (nền là z263) và đóng gói full thành z264_23_10_2026_LADDER_driver_ScadaWeb.zip. Mình chưa build cả project hay thử trên trình duyệt: sandbox không tải được NuGet và không có trình duyệt. Mình chỉ biên dịch riêng các file mới và chạy logic với engine giả: seal-in (start/stop tự giữ), nhánh song song, TON, CTU, SR, ADD đều chạy đúng, và Network có tag lỗi không ghi gì ra ngoài. Phần kéo thả mới kiểm tra ở mức biên dịch và HTML sinh ra, chưa kéo thử bằng chuột.
Mình đã đóng gói toàn bộ project vào ScadaWeb_full_ladder_edit.zip, gồm code đổi loại tiếp điểm và cuộn dây đã sửa. Mình chưa build thử vì môi trường không có dotnet.
Nguyên nhân lỗi: trong ảnh, @inject IJSRuntime JS vẫn ở dòng 3. File mình gửi lần trước có dòng đó ở dòng 5, vì mình đã chèn thêm 2 dòng @using lên đầu. Vậy Visual Studio đang biên dịch một bản LadderDialog.razor cũ, không phải bản mới. Nhiều khả năng đó là thư mục ladder_update/ bạn chép nguyên vào project từ lần đầu. File nằm trong ladder_update/Components/ không có _Imports.razor đi kèm nên thiếu JSInterop và Components.Web. File trong Components/ thật thì vẫn đúng, vì _Imports.razor của project đã khai báo sẵn hai namespace này.
Cách làm:
- Đóng Visual Studio. Xoá thư mục
ladder_update/nếu nó đang nằm trong project, cùng hai thư mụcbin/vàobj/. - Giải nén
ScadaWeb_full_ladder_edit.zipđè lên thư mục project. - Mở
Components/LadderDialog.razorvà kiểm tra dòng 1 là@using Microsoft.JSInterop. Nếu không phải thì file chưa được thay. - Mở lại solution và chọn Rebuild Solution.
Trong ScadaWeb.csproj mình thêm một đoạn loại trừ thư mục ladder_update\** khỏi quá trình build. Nhờ đó, nếu thư mục này còn sót lại thì cũng không gây lỗi trùng nữa.
Nếu Rebuild vẫn báo lỗi ở LadderDialog.razor dòng 3, bạn mở Solution Explorer, tìm “LadderDialog” và gửi mình đường dẫn của các file tìm được.
Cách dùng
- Ở trang Thiết bị & Tag, chọn Driver LADDER, đặt tên rồi bấm Thêm PLC.
- Ở dòng thiết bị bấm 🪜 Ladder để mở trình soạn.
- Bên phải có bảng lệnh Basic instructions (như ảnh TIA của bạn) và danh sách tag:
- Kéo lệnh vào Network.
- Kéo tag vào ô toán hạng của lệnh. Ô này cũng gõ tay được, nhận tên tag hoặc hằng số (
100,TRUE,T#5s). - Thả tag thẳng lên dây: giữa dây tự tạo tiếp điểm
–| |–, cuối dây tự tạo cuộn dây–( )–. - Click ô toán hạng rồi click một tag cũng gán được.
- Kéo phần tử đã đặt để di chuyển, kéo vào ô 🗑 để xoá. Open branch và Close branch tạo hoặc bỏ nhánh song song.
- Bấm ▶ RUN. Dây có dòng điện sáng xanh, dưới tiếp điểm hiện giá trị tag.
Lệnh có sẵn
- Bit logic:
–| |–,–|/|–, NOT,–|P|–,–|N|–,–( )–,–(/)–,–(R)–,–(S)–,–(P)–,–(N)–, SET_BF, RESET_BF, SR, RS, P_TRIG, N_TRIG, R_TRIG, F_TRIG. - Timer và Counter: TON, TOF, TP, CTU, CTD.
- So sánh:
==,<>,>,<,>=,<=. - Math và Move: ADD, SUB, MUL, DIV, MOVE.
Lưu ý
- Thiết bị LADDER mới tạo luôn ở trạng thái STOP, soạn xong mới bấm RUN. Sửa ladder khi đang RUN có hiệu lực ngay.
- Một Network có tag không tồn tại, mất kết nối, ô toán hạng trống hoặc Empty box thì không ghi gì ra tag, và hiện cảnh báo đỏ ở đầu Network.
- Nút + Tag trạng thái tạo
Tên.RUN,Tên.SCAN_MS,Tên.ERRđể đưa lên màn hình. Ghi 0 hoặc 1 vào.RUNlà STOP hoặc RUN. - Đổi tên tag trong Tag Manager sẽ tự cập nhật trong ladder. Chương trình ladder lưu trong
project.json. - ET của timer và CV của counter nên trỏ tới tag InternalMemory để giữ giá trị.
File thay đổi
- Thêm mới: LadderDriver.cs, Components/LadderDialog.razor, wwwroot/ladder.js, HUONG_DAN_LADDER.md.
- Sửa nhỏ: Models.cs, ScadaEngine.cs, Components/Home.razor, Components/App.razor, wwwroot/app.css.
· Nền soạn thảo trước đây là xanh tối, nên nét đen khi STOP gần như không thấy. Mình đổi vùng Network sang nền sáng giống TIA Portal như ảnh bạn gửi. Viền khối lệnh (MOVE, TON…) cũng theo quy tắc này.
· Mình chỉ sửa 4 file: Components/LadderDialog.razor, wwwroot/ladder.js, wwwroot/app.css, HUONG_DAN_LADDER.md. Các file còn lại trong danh sách bạn nêu (LadderDriver.cs, Models.cs, ScadaEngine.cs, Home.razor, App.razor) mình không đụng tới.
· Nếu build báo lỗi ở LadderDialog.razor, gửi mình dòng lỗi để mình sửa ngay.
- Thêm mới: LadderDriver.cs, Components/LadderDialog.razor, wwwroot/ladder.js, HUONG_DAN_LADDER.md.
Mình viết
LadderFb.cs(model thư viện, nhập/xuất .zip, engine chạy FB) và thêm các endpoint vào Program.cs

