C# cơ bản cho kỹ sư tự động hóa: kiểu dữ liệu, lớp, LINQ, async
Những gì cần nắm để viết phần mềm trạm kiểm tra bằng C#: record, LINQ, async/await giữ giao diện không treo, xử lý ngoại lệ và giải phóng tài nguyên.
Nội dung bài viết
C# là ngôn ngữ phổ biến nhất cho phần mềm trên máy tính công nghiệp tại nhà máy: giao diện vận hành, kết nối PLC, cơ sở dữ liệu, SDK camera. Bài này tóm tắt những gì một kỹ sư tự động hóa cần nắm để bắt đầu viết ứng dụng Vision bằng C#.
Cài đặt
- Cài .NET SDK (bản LTS mới nhất) và Visual Studio Community hoặc VS Code + extension C# Dev Kit.
- Tạo dự án:
dotnet new console -n TramKiemTra, chạy bằngdotnet run.
Kiểu dữ liệu và biến
int soLuong = 120;
double kichThuoc = 25.034; // mm
bool ok = kichThuoc >= 24.95 && kichThuoc <= 25.05;
string maSp = "SP-001";
var thoiGian = DateTime.Now; // var: trình biên dịch tự suy ra kiểu
Console.WriteLine($"{maSp}: {kichThuoc:F3} mm -> {(ok ? "OK" : "NG")}");
C# là ngôn ngữ kiểu tĩnh: sai kiểu bị báo lỗi ngay khi biên dịch, giúp phần mềm chạy 24/7 ổn định hơn.
Lớp (class) để mô hình hóa dữ liệu
public record KetQuaKiemTra(string MaSp, double KichThuoc, bool Ok, DateTime ThoiGian);
public class BoKiemTra
{
public double Min { get; }
public double Max { get; }
public BoKiemTra(double min, double max) { Min = min; Max = max; }
public KetQuaKiemTra DanhGia(string maSp, double kichThuoc) =>
new(maSp, kichThuoc, kichThuoc >= Min && kichThuoc <= Max, DateTime.Now);
}
var bo = new BoKiemTra(24.95, 25.05);
var kq = bo.DanhGia("SP-002", 25.08);
Console.WriteLine(kq); // in đầy đủ các trường của record
record rất hợp để lưu kết quả: bất biến, tự có ToString và so sánh theo giá trị.
Danh sách và LINQ
var ketQua = new List<KetQuaKiemTra>();
// ... thêm kết quả ...
int soNg = ketQua.Count(k => !k.Ok);
double tb = ketQua.Any() ? ketQua.Average(k => k.KichThuoc) : 0;
var ngGanNhat = ketQua.Where(k => !k.Ok).OrderByDescending(k => k.ThoiGian).Take(10);
Bất đồng bộ (async/await): không để giao diện bị treo
Chụp ảnh, xử lý, gửi dữ liệu cho PLC đều tốn thời gian. Nếu chạy trên luồng giao diện, cửa sổ sẽ "đơ". Dùng async/await:
private async void btnChup_Click(object sender, EventArgs e)
{
btnChup.Enabled = false;
try
{
var kq = await Task.Run(() => XuLyAnh()); // chạy trên luồng nền
lblKetQua.Text = kq.Ok ? "OK" : "NG";
}
finally
{
btnChup.Enabled = true;
}
}
Xử lý ngoại lệ và giải phóng tài nguyên
try
{
using var file = new StreamWriter("log.csv", append: true);
file.WriteLine($"{kq.ThoiGian:O},{kq.MaSp},{kq.KichThuoc},{kq.Ok}");
}
catch (IOException ex)
{
Console.WriteLine($"Không ghi được log: {ex.Message}");
}
using đảm bảo file, kết nối mạng, ảnh Mat của OpenCvSharp luôn được giải phóng, kể cả khi có lỗi.
Bước tiếp theo
- Xử lý ảnh: C# với OpenCvSharp.
- Giao diện camera: WinForms hiển thị camera.
- Kết nối PLC: Modbus TCP từ C#.


