车间主任老张最近盯着监控屏直挠头,设备数据像脱缰野马抓不住。我递给他一杯枸杞茶:“要不试试用C#搞个数据抓取系统?“ 他眼镜片突然反光:“细说
·
C#上位机与西门子PLC通讯,读取数据,存储数据库,形成报表可查询,报警历史查询,变量自定义配置。 每一步都有视频讲解(详细视频教程) 案例:涉及多线程,数据库存储,与PLC通讯等技术

通讯连接才是硬道理

Sharp7库的DLL扔进项目,连PLC跟找对象似的得先对上暗号:
var plc = new S7Client();
int result = plc.ConnectTo("192.168.0.1", 0, 1); //IP,机架,槽号
if (result == 0)
{
Console.WriteLine("握手成功!PLC型号:" + plc.GetCpuType());
}
遇到过最邪门的bug是网线水晶头氧化导致随机掉线,后来加了个心跳检测线程:
Task.Run(() =>
{
while (true)
{
if (!plc.GetPlcStatus())
{
_logger.Warning("PLC失联!尝试重连...");
plc.ForceReconnect();
}
Thread.Sleep(3000);
}
});
数据入库要玩出花

用EF Core搞批量插入比单条写入快20倍不止:
var buffer = new ConcurrentQueue<PlcData>(); //多线程缓冲队列
using var context = new DataContext();
context.ChangeTracker.AutoDetectChangesEnabled = false;
while (!token.IsCancellationRequested)
{
if (buffer.TryDequeue(out var data))
{
context.Add(data);
if (++count % 500 == 0) //每500条提交
{
context.SaveChanges();
context.Dispose();
context = new DataContext();
}
}
}
注意这个坑:DbContext实例不是线程安全的,每个写入线程得单独实例化。

报警处理得像急诊室

C#上位机与西门子PLC通讯,读取数据,存储数据库,形成报表可查询,报警历史查询,变量自定义配置。 每一步都有视频讲解(详细视频教程) 案例:涉及多线程,数据库存储,与PLC通讯等技术

报警触发时除了写库,还得实时弹窗:
public class AlarmDispatcher
{
private readonly BlockingCollection<Alarm> _alarms = new();
public void RaiseAlarm(string msg)
{
_alarms.Add(new Alarm(msg));
PlaySound("alert.wav"); //蜂鸣器模拟
}
void ProcessAlarms()
{
foreach (var alarm in _alarms.GetConsumingEnumerable())
{
using var popup = new AlarmWindow(alarm);
popup.ShowDialog();
}
}
}
用BlockingCollection实现生产者-消费者模型,比手动lock省心多了。

报表生成别当老实人
别傻乎乎自己写SQL统计,用LINQ分组查询真香:
var dailyReport = context.HistoricalData
.Where(d => d.Time.Date == DateTime.Today)
.GroupBy(d => d.TagName)
.Select(g => new {
Tag = g.Key,
Avg = g.Average(d => d.Value),
Max = g.Max(d => d.Value),
Min = g.Min(d => d.Value)
}).ToList();
搭配ClosedXML导出Excel,比Interop方式快还不依赖Office:
using var workbook = new XLWorkbook();
var ws = workbook.AddWorksheet("日报");
ws.Cell(1, 1).Value = "今日设备心跳全记录";
ws.Range("A1:D1").Merge().Style.Font.Bold = true;
变量配置得会七十二变
用JSON动态配置点位表才是王道:
{
"DataPoints": [
{
"Name": "烘箱温度",
"DB": 10,
"Offset": 12,
"DataType": "Real"
},
{
"Name": "传送带速度",
"DB": 12,
"Offset": 8,
"DataType": "Int"
}
]
}
解析时上反射大法:
var config = JsonConvert.DeserializeObject<PlcConfig>(File.ReadAllText("points.json"));
foreach (var point in config.DataPoints)
{
var reader = typeof(S7Client).GetMethod($"Read{point.DataType}");
object value = reader.Invoke(plc, new object[] { point.DB, point.Offset });
}
这套系统上线三个月后,老张的枸杞茶终于凉透了——他现在有更多时间盯着大盘指数而不是设备屏了。想看PLC通讯时如何处理字节序问题?数据库连接池怎么优化?点我主页找完整视频教程,连异常处理时的祖传代码都给你瞅瞅。
更多推荐
所有评论(0)