C#与西门子PLC通讯——高手快速入门

提示1:参照本文,你将通过一个实际案例深入了解如何实现一个通讯交互方案的功能。
提示2:如果你希望先完成一个简单的项目原型,请跳转C#与西门子PLC通讯——熟手快速入门。
提示3:如果你第一次来,请跳转到C#与西门子PLC通讯——新手快速入门以了解背景设定。

C#与西门子PLC通讯 系列文章目录

往期博客参考
建议先看下面这两篇,了解预设背景。
C#与西门子PLC通讯——新手快速入门
C#与西门子PLC通讯——熟手快速入门

番外篇
C#与西门子PLC通讯——手搓S7通讯协议

文章目录

  • C#与西门子PLC通讯 系列文章目录
  • 前言
  • 一、需求分析
    • 1.1 背景
    • 1.2 主要功能
    • 1.3 技术选型
    • 1.4 系统架构
    • 1.5 依赖注入和反射
  • 二、业务实现
    • 2.1 PLC通讯服务
    • 2.2 数据库访问
    • 2.3 业务逻辑
    • 2.4 依赖注入和反射
  • 三、接口测试
    • 3.1 连接PLC测试
    • 3.2 读取PLC测试
    • 3.3 写入PLC测试
  • 总结
    • 成果与亮点
    • 下一步计划


前言

又过三日,斯电气之士志在不凡,再请吾赐以开发之微言,吾思之经久,遂书笔记一篇,以赞其志。

本文基于C# .Net Core和西门子博图TIA Portal V17搭建。由于手边没有西门子PLC实物,所以采用S7-PLCSIM Advanced V4.0作为模拟PLC,以实现0成本完成通讯测试实例。

本文将以一个自动化立体车库作为案例入手,完成基于领域驱动设计(DDD)的项目设计。
C#与西门子PLC通讯——高手快速入门_第1张图片


一、需求分析

1.1 背景

随着城市交通日益拥堵,自动化立体车库系统成为解决停车难题的创新方案。该系统涉及到大量的设备,如PLC控制器用于车库的自动化操作,数据库用于存储车辆信息,用户界面用于用户与系统的交互。
在自动化立体车库系统中,与西门子PLC的高效通讯是确保系统稳定运行的关键之一。本博客将带领读者深入探讨如何使用C#与西门子PLC进行通讯,实现对车库设备的灵活控制。

1.2 主要功能

  1. PLC通讯: 实现C#与西门子PLC的通讯,包括读取PLC中的状态信息和发送控制指令。

  2. 数据库访问: 通过Entity Framework Core实现对车辆信息的持久化存储,包括车辆的入库和出库记录。

  3. 业务逻辑: 实现车库的业务逻辑,包括车位管理、车辆入库和出库等操作。

  4. 用户界面: 使用ASP.NET Core MVC或Blazor实现用户友好的界面,显示车库状态,提供用户操作界面。

1.3 技术选型

  1. PLC通讯服务: 使用S7netplus等通讯库实现C#与西门子PLC的通讯。

  2. 数据库访问: 利用Entity Framework Core进行数据库操作,支持多种数据库后端。

  3. 业务逻辑: 基于领域驱动设计(DDD)的概念,实现业务逻辑服务接口。

  4. 用户界面: 使用ASP.NET Core MVC,与业务逻辑和PLC通讯服务集成。

1.4 系统架构

  • AutoParkingSystem.Core: 实现领域模型和业务逻辑,定义PLC通讯服务接口。

  • AutoParkingSystem.Infrastructure: 实现数据库访问和PLC通讯服务,使用Entity Framework Core和S7netplus等库。

  • AutoParkingSystem.Web: 实现用户界面,集成业务逻辑和PLC通讯服务,展示车库状态和实现用户操作。

  • AutoParkingSystem.Tests: 编写单元测试和集成测试,确保系统的稳定性和可靠性。

C#与西门子PLC通讯——高手快速入门_第2张图片

1.5 依赖注入和反射

通过在Program.cs中配置依赖注入容器,实现各个服务和组件的动态加载和实例化,提高系统的灵活性和可扩展性。

二、业务实现

2.1 PLC通讯服务

AutoParkingSystem.Infrastructure项目中实现与西门子PLC的通讯服务。首先,创建接口定义:

// AutoParkingSystem.Core/Services/IPlcCommunicationService.cs
public interface IPlcCommunicationService
{
    bool IsConnected { get; }
    Task<bool> ConnectAsync(string ipAddress, int rack, int slot);
    Task<int> ReadIntAsync(int dbArea, int offset);
    Task WriteIntAsync(int dbArea, int offset, short value);

    // 其他通讯方法...
}

然后,在AutoParkingSystem.Infrastructure项目中实现该接口:

// AutoParkingSystem.Infrastructure/Services/SiemensPlcCommunicationService.cs
public class SiemensPlcCommunicationService : IPlcCommunicationService
{
    private Plc? plc;

    public bool IsConnected
    {
        get
        {
            if (plc == null) { return false; }
            return plc.IsConnected;
        }
    }

    public async Task<bool> ConnectAsync(string ipAddress, int rack, int slot)
    {
        plc = new Plc(CpuType.S71500, ipAddress, (short)rack, (short)slot);
        await plc.OpenAsync();
        return plc.IsConnected;
    }

    public async Task<int> ReadIntAsync(int dbArea, int offset)
    {
        if (plc == null || !plc.IsConnected)
        {
            throw new InvalidOperationException("PLC is not connected.");
        }

        var result = await plc.ReadAsync(DataType.DataBlock, dbArea, offset, VarType.Int, 1);
        if (result == null)
        {
            return 0;
        }
        else
        {
            return (short)result;
        }
    }

    public async Task WriteIntAsync(int dbArea, int offset, short value)
    {
        if (plc == null || !plc.IsConnected)
        {
            throw new InvalidOperationException("PLC is not connected.");
        }

        await plc.WriteAsync(DataType.DataBlock, dbArea, offset, value);
    }

    // 其他通讯方法的实现...
}

2.2 数据库访问

使用Entity Framework Core实现对车辆信息的数据库访问。首先,在AutoParkingSystem.Core项目中定义领域模型:

尚未完成。。。敬请期待

2.3 业务逻辑

AutoParkingSystem.Core项目中实现车库的业务逻辑服务:

// AutoParkingSystem.Core/Services/IParkingService.cs
public interface IParkingService
 {
     Task<bool> ParkVehicleAsync(string vehicleId);
     Task<bool> ReleaseParkingSpaceAsync(string vehicleId);

     // 其他服务接口...
 }

然后,在AutoParkingSystem.Core项目中实现该接口的具体逻辑:

// AutoParkingSystem.Core/Services/ParkingService.cs
public class ParkingService : IParkingService
{
    private readonly IPlcCommunicationService plcCommunicationService;

    public ParkingService(IPlcCommunicationService plcCommunicationService)
    {
        this.plcCommunicationService = plcCommunicationService;
    }

    public async Task<bool> ParkVehicleAsync(string vehicleId)
    {
        // 调用PLC通讯服务进行停车操作
        await plcCommunicationService.WriteIntAsync(1, 2, 1);

        // 其他停车逻辑...

        return true;
    }

    public async Task<bool> ReleaseParkingSpaceAsync(string vehicleId)
    {
        // 调用PLC通讯服务进行释放停车位操作
        await plcCommunicationService.WriteIntAsync(1, 2, 0);

        // 其他释放停车位逻辑...

        return true;
    }

    // 其他服务方法...
}

2.4 依赖注入和反射

AutoParkingSystem.Web项目的Program.cs中配置依赖注入容器,注册各个服务和组件,以及使用反射机制实现动态加载和实例化:

// AutoParkingSystem.Web/Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Add services to the container.
        // 注册业务逻辑服务
        builder.Services.AddScoped<IParkingService, ParkingService>();

        // 注册PLC通信服务,这里注册的是SiemensPlcCommunicationService
        builder.Services.AddSingleton<IPlcCommunicationService, SiemensPlcCommunicationService>();

        builder.Services.AddControllers();
        // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();

        var app = builder.Build();

        // Configure the HTTP request pipeline.
        if (app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseHttpsRedirection();

        app.UseAuthorization();


        app.MapControllers();

        app.Run();
    }
}

2.5 测试接口实现

// AutoParkingSystem.Web/Controllers/PlcConnectionController.cs
[ApiController]
[Route("[controller]")]
public class PlcConnectionController : ControllerBase
{

    private readonly ILogger<PlcConnectionController> _logger;
    private readonly IPlcCommunicationService _plcCommunicationService;

    public PlcConnectionController(ILogger<PlcConnectionController> logger, IPlcCommunicationService plcCommunicationService)
    {
        _plcCommunicationService = plcCommunicationService;
        _logger = logger;
    }

    [HttpPost("ConnectPlc")]
    public async Task<IActionResult> ConnectAsync()
    {
        bool val = await _plcCommunicationService.ConnectAsync("192.168.0.100", 0, 1);
        return Ok(val);
    }

    [HttpGet("ReadInt")]
    public async Task<IActionResult> ReadIntAsync(int dbArea, int offset)
    {
        if (_plcCommunicationService.IsConnected == false)
        {
            await _plcCommunicationService.ConnectAsync("192.168.0.100", 0, 1);
        }
        var val = await _plcCommunicationService.ReadIntAsync(dbArea, offset);
        return Ok(val);
    }

    [HttpPost("WriteInt")]
    public async Task<IActionResult> WriteIntAsync(int dbArea, int offset, short value)
    {
        if (_plcCommunicationService.IsConnected == false)
        {
            await _plcCommunicationService.ConnectAsync("192.168.0.100", 0, 1);
        }
        await _plcCommunicationService.WriteIntAsync(dbArea, offset, value);
        return Ok("OK");
    }
}

三、接口测试

C#与西门子PLC通讯——高手快速入门_第3张图片

3.1 连接PLC测试

首先,我们尝试与PLC建立连接。
C#与西门子PLC通讯——高手快速入门_第4张图片

3.2 读取PLC测试

接着,我们读取一下原来PLC中的一个整形量,请参考C#与西门子PLC通讯——熟手快速入门。
C#与西门子PLC通讯——高手快速入门_第5张图片

3.3 写入PLC测试

然后,我们尝试对这个整形量写入一个值,再读取下整形量。
C#与西门子PLC通讯——高手快速入门_第6张图片
可以看到,已经写入成功,读取到的也是对应的值。
C#与西门子PLC通讯——高手快速入门_第7张图片


总结

我们已经建立了一个自动化立体车库系统的基本的DDD框架,实现了C#与西门子PLC的通讯。

成果与亮点

  1. PLC通讯服务: 通过实现IPlcCommunicationService接口,我们建立了与西门子PLC的通讯服务,并使用S7netplus等库实现了读取PLC状态和发送控制指令的功能。这为系统与车库设备的紧密集成提供了基础。

  2. 业务逻辑:IParkingService接口和ParkingService实现中,我们通过领域驱动设计(DDD)的概念,定义了车库的业务逻辑,包括车辆入库、出库等操作。这为系统的稳定运行提供了可靠的业务逻辑支持。

  3. 依赖注入和反射: 通过在Program.cs中配置依赖注入容器,我们注册了各个服务和组件,使用反射机制实现了动态加载和实例化。这增强了系统的灵活性和可扩展性。

下一步计划

  1. 数据库访问: 利用Entity Framework Core,我们实现了对车辆信息的数据库持久化存储。通过定义ParkingRecord领域模型和相应的数据库上下文,我们实现了车辆入库和出库记录的管理。

  2. 用户界面: 使用ASP.NET Core MVC或Blazor,我们实现了用户友好的界面,展示了车库的实时状态,并提供了用户操作界面。这使得系统更易用、直观,提高了用户体验。

  3. 异步编程: 在系统的关键地方,如IO操作,采用异步编程模型,提高系统的性能和响应性。

  4. 安全性: 加强系统的安全性,通过使用ASP.NET Core提供的身份验证和授权中间件,确保系统只对授权用户开放,并实施必要的安全审计。

  5. 性能优化: 进一步优化系统性能,考虑缓存、数据库索引等方面的优化措施,以确保系统的高效运行。

  6. 测试与调优: 持续进行单元测试和集成测试,确保系统的稳定性和可靠性。根据测试结果,进行必要的调优和改进。

  7. 日志记录: 引入日志记录机制,记录系统运行中的关键信息,以便及时发现和解决问题。

通过不断的迭代和优化,我们可以构建一个功能完善、性能卓越的自动化立体车库系统。希望为读者提供了在自动化领域深入探索的基础,希望通过本系列能够学到更多有关工业自动化的知识和技能。

本篇博文将不断优化完善,敬请期待。

你可能感兴趣的:(C#,西门子,c#,自动化,.netcore)