当前位置: 首页 > news >正文

C#实现实时读取西门子PLC数据,并存到Redis数据库中

using S7.Net;

using StackExchange.Redis;

using System.Threading.Channels;

// ====== PLC配置 ======

public class PlcConfig
{
public string Ip { get; set; } = "192.168.0.1";

public int Rack { get; set; } = 0;

public int Slot { get; set; } = 1;

public CpuType CpuType { get; set; } = CpuType.S71200;

}

// ====== Redis配置 ======

public class RedisConfig
{

public string ConnectionString { get; set; } = "localhost:6379";

public int Database { get; set; } = 0;

}

// ====== 主服务类 ======

public class PlcToRedisService
{

private readonly Plc _plc; private readonly IDatabase _redisDb;

private readonly Channel<PlcData> _dataChannel = Channel.CreateUnbounded<PlcData>(); private CancellationTokenSource _cts = new();

public PlcToRedisService(PlcConfig plcConfig, RedisConfig redisConfig)
{

_plc = new Plc(plcConfig.CpuType, plcConfig.Ip, plcConfig.Rack, plcConfig.Slot) { ReadTimeout = 500, WriteTimeout = 500

};

var redis = ConnectionMultiplexer.Connect(redisConfig.ConnectionString);

_redisDb = redis.GetDatabase(redisConfig.Database);

}

public async Task StartAsync()
{
// PLC读取线程

var readTask = Task.Run(async () => { while (!_cts.IsCancellationRequested)
{
 try
 {

if (!_plc.IsConnected) await _plc.OpenAsync();

// 读取DB100中前20字节(根据实际PLC地址修改)

var data = await _plc.ReadBytesAsync(DataType.DataBlock, 100, 0, 20);

var plcData = ParseData(data); // 自定义数据解析

await _dataChannel.Writer.WriteAsync(plcData, _cts.Token);
}

catch (Exception ex)
{

Console.WriteLine($"PLC读取失败: {ex.Message}");

await ReconnectPlc();
}

await Task.Delay(100, _cts.Token); // 100ms采样周期

} }); // Redis写入线程

var writeTask = Task.Run(async () => { await foreach (var data in _dataChannel.Reader.ReadAllAsync(_cts.Token))
{

try

{
// 使用Hash存储数据到
Redis var entries = new HashEntry[]
{
new("Temperature", data.Temperature), new("Pressure", data.Pressure), new("Timestamp", DateTime.UtcNow.Ticks)
};

await _redisDb.HashSetAsync($"plc:{data.DeviceId}", entries);

await _redisDb.KeyExpireAsync($"plc:{data.DeviceId}", TimeSpan.FromMinutes(10));

}

catch (Exception ex)
{
Console.WriteLine($"Redis写入失败: {ex.Message}"); } } });
await Task.WhenAll(readTask, writeTask);
}

private PlcData ParseData(byte[] rawData)
{
// 示例解析逻辑(需根据实际PLC数据结构实现)
return new PlcData { DeviceId = 1, Temperature = BitConverter.ToSingle(rawData, 0), // 前4字节转float Pressure = BitConverter.ToInt16(rawData, 4) // 5-6字节转short };
}

private async Task ReconnectPlc()
{
_plc.Close(); for (int i = 0; i < 3; i++)
{
try
{

await _plc.OpenAsync(); Console.WriteLine("PLC重连成功"); return; }

catch { await Task.Delay(1000);

}

}

throw new Exception("PLC无法连接");

}

public async Task StopAsync()
{
_cts.Cancel(); _plc.Close();
await _redisDb.Multiplexer.CloseAsync();

}

}

// ====== 数据模型 ======

public class PlcData
{
public int DeviceId { get; set; }
public float Temperature { get; set; }
public short Pressure { get; set; }
}

// ====== 使用示例 ======

var plcConfig = new PlcConfig();
var redisConfig = new RedisConfig();
var service = new PlcToRedisService(plcConfig, redisConfig);
await service.StartAsync();

// 运行中... await Task.Delay(TimeSpan.FromMinutes(60));

await service.StopAsync();

相关文章:

  • Scala 异常处理
  • 如何高效生成达梦数据库测试数据?官方管理工具来了!
  • 蓝桥杯 2. 开赛主题曲【算法赛】
  • 基于AI设计开发出来的业务系统是什么样的?没有菜单?没有表格?
  • Winform零基础从入门到精通(13)——WinForm综合项目开发
  • 练习(含指针数组与数组指针的学习)
  • Unity 实现伤害跳字
  • 使用 node.js 和 MongoDB 编写一个简单的增删改接口 demo
  • 李建忠:智能体正将互联网从信息网络重构为行动网络
  • 【Oracle篇】跨字符集迁移:基于数据泵的ZHS16GBK转AL32UTF8全流程迁移
  • 【鸿蒙HarmonyOS】如何实现网络请求
  • 【区块链+ 人才服务】区块链虚拟仿真教学平台 | FISCO BCOS 应用案例
  • Kafka 和 Flink的讲解
  • git 的常用指令
  • Java面试42-什么是幂等?如何解决幂等性问题?
  • Axure RP9教程 【数据传输】(页面值传递)| 作用域 :全局变量、局部变量
  • kafka分区策略详解
  • MCP+Blender创建电力塔
  • H.265视频编码技术:下一代高清时代的数字密码
  • NO.73十六届蓝桥杯备战|搜索算法-剪枝与优化-记忆化搜索|数的划分|小猫爬山|斐波那契数|Function|天下第一|滑雪(C++)
  • 做外贸都有哪些好网站/谷歌商店下载不了软件
  • 医院网站前置审批最快多久出来/seo经理
  • 网站为什么做微云的采集/seo优化师就业前景
  • 工厂网站建设费用/新网站百度seo如何做
  • 网站搜索条怎么做/网站更新seo
  • 网络游戏公司/seo主要做什么