李工ROBOT架构之开篇

以下是一个基于 .NET Core + WPF 的半导体可靠性测试机上位机系统的完整架构设计,涵盖 UI、业务逻辑、硬件驱动、数据处理模块、日志、计算和扩展功能等。内容将按照模块化、分层设计进行详细说明,并提供关键代码示例。由于内容较长,我会分模块逐步展开,确保清晰且实用。同时,我会根据你的需求(MVVM、Prism、Autofac、Serilog、LiveCharts 等)提供一个系统性框架,并附带中文解释。后续可以根据需要进一步细化代码或扩展其他功能(如深度学习、云端部署等)。


一、系统整体架构设计

1.1 架构目标

  • 模块化:通过 Prism 实现模块化设计,各个功能模块(如首页、配置、监控等)独立开发、动态加载。

  • 可扩展性:硬件驱动抽象化,支持不同厂商硬件切换;数据存储支持多种格式(CSV、MySQL、SQLite 等)。

  • 高性能:异步处理高频采集数据,NumSharp 用于高效计算热阻、结构函数等。

  • 易维护:使用 MVVM 模式分离 UI 和逻辑,Serilog 提供详细日志,DI 容器(Autofac)管理依赖。

  • 用户友好:界面提供帮助提示,LiveCharts 绘制实时曲线,操作简单直观。

1.2 分层架构

  1. UI 层:WPF + Prism + MVVM,负责界面展示和用户交互。

  2. 应用服务层:业务逻辑处理,如实验流程控制、数据解析、硬件操作等。

  3. 驱动层:硬件抽象接口,适配不同厂商设备(串口、TCP/UDP、Modbus 等)。

  4. 数据层:支持 CSV、MySQL、SQLite、SQL Server,Entity Framework Core 管理数据库。

  5. 计算层:NumSharp 实现热阻、结构函数等半导体计算公式。

  6. 日志层:Serilog 记录操作日志、硬件状态、实验数据。

  7. 通信层:SerialPort、TcpClient、UdpClient、Modbus 实现硬件通信。

1.3 项目结构

SemiconductorTestSystem/
├── SemiconductorTestSystem.sln
├── Src/
│   ├── SemiconductorTestSystem.UI/              # WPF UI 项目
│   │   ├── Views/                              # XAML 界面
│   │   ├── ViewModels/                         # MVVM 视图模型
│   │   ├── Modules/                            # Prism 模块(首页、配置等)
│   │   ├── App.xaml                            # 应用入口
│   │   └── Bootstrapper.cs                     # Prism 启动配置
│   ├── SemiconductorTestSystem.Core/           # 核心业务逻辑
│   │   ├── Services/                           # 业务服务(实验控制、数据处理等)
│   │   ├── Models/                             # 数据模型
│   │   └── Interfaces/                         # 服务接口
│   ├── SemiconductorTestSystem.Hardware/       # 硬件驱动
│   │   ├── Drivers/                            # 具体硬件驱动实现
│   │   ├── Interfaces/                         # 硬件抽象接口
│   │   └── Communication/                      # 通信协议(串口、TCP 等)
│   ├── SemiconductorTestSystem.Data/           # 数据存储
│   │   ├── Repositories/                       # 数据访问层
│   │   ├── Configurations/                     # CSV/DB 配置
│   │   └── DbContexts/                         # EF Core 上下文
│   ├── SemiconductorTestSystem.Calculations/   # 计算模块
│   │   ├── ThermalCalculations.cs              # 热阻、结构函数计算
│   │   └── TestCalculations.cs                 # 其他测试公式
│   ├── SemiconductorTestSystem.Common/         # 公共类库
│   │   ├── Extensions/                         # 扩展方法
│   │   ├── Utilities/                          # 工具类
│   │   └── Enums/                              # 枚举定义
│   └── SemiconductorTestSystem.Tests/          # 单元测试
├── Docs/                                       # 文档
└── README.md

二、UI 框架设计

2.1 UI 框架技术栈

  • WPF:使用 XAML 实现现代化界面,支持数据绑定。

  • Prism:实现模块化开发,导航管理和依赖注入。

  • MVVM:分离界面和逻辑,ViewModel 处理业务逻辑。

  • LiveCharts:绘制实时曲线(如温度、电压等)。

  • MaterialDesignThemes:美化界面,提供现代化 UI 风格。

2.2 UI 模块划分

根据需求,设计以下五个主要界面模块:

  1. 首页:显示通道信息、实验状态,点击查看数据表格和曲线。

  2. 配置界面:设置实验流程(升温、升压、延时等)。

  3. 监控界面:实时查看硬件状态(温箱、通道、电源等)。

  4. 日志界面:显示设备和实验日志,支持订阅和过滤。

  5. 硬件控制界面:查看和操作硬件状态。

2.3 Prism 模块化实现

每个界面作为一个 Prism 模块,动态加载到主窗口的 Region 中。

2.3.1 Bootstrapper 配置

csharp

using Prism.Ioc;
using Prism.Modularity;
using Prism.Unity;
using Unity;

namespace SemiconductorTestSystem.UI
{
    public class Bootstrapper : PrismBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            return Container.Resolve();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            // 注册服务
            containerRegistry.RegisterSingleton();
            containerRegistry.RegisterSingleton();
            containerRegistry.RegisterSingleton();
            containerRegistry.RegisterSingleton();
        }

        protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
        {
            // 注册模块
            moduleCatalog.AddModule();
            moduleCatalog.AddModule();
            moduleCatalog.AddModule();
            moduleCatalog.AddModule();
            moduleCatalog.AddModule();
        }
    }
}

2.3.2 主窗口 XAML

xaml


    
        
        
            

2.3.3 首页模块示例

HomeView.xaml

xaml


    
        
            
            
        
        
        
        
            
                
                    
                        
                        
                    
                
            
        
        
        
        
            
            
            
            
        
    

HomeViewModel.cs

csharp

using Prism.Mvvm;
using Prism.Regions;
using LiveCharts;
using LiveCharts.Wpf;
using SemiconductorTestSystem.Core.Services;

namespace SemiconductorTestSystem.UI.Modules.Home.ViewModels
{
    public class HomeViewModel : BindableBase, INavigationAware
    {
        private readonly ITestController _testController;
        private Channel _selectedChannel;
        private ObservableCollection _channels;
        private SeriesCollection _seriesCollection;

        public HomeViewModel(ITestController testController)
        {
            _testController = testController;
            Channels = new ObservableCollection(_testController.GetChannels());
            SeriesCollection = new SeriesCollection();
        }

        public Channel SelectedChannel
        {
            get => _selectedChannel;
            set
            {
                SetProperty(ref _selectedChannel, value);
                UpdateChannelData();
            }
        }

        public ObservableCollection Channels
        {
            get => _channels;
            set => SetProperty(ref _channels, value);
        }

        public SeriesCollection SeriesCollection
        {
            get => _seriesCollection;
            set => SetProperty(ref _seriesCollection, value);
        }

        private async void UpdateChannelData()
        {
            if (SelectedChannel != null)
            {
                var data = await _testController.GetChannelDataAsync(SelectedChannel.Id);
                SeriesCollection.Clear();
                SeriesCollection.Add(new LineSeries
                {
                    Title = "Temperature",
                    Values = new ChartValues(data.Temperatures)
                });
            }
        }

        public void OnNavigatedTo(NavigationContext navigationContext) { }
        public bool IsNavigationTarget(NavigationContext navigationContext) => true;
        public void OnNavigatedFrom(NavigationContext navigationContext) { }
    }
}

HomeModule.cs

csharp

using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;

namespace SemiconductorTestSystem.UI.Modules.Home
{
    public class HomeModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            var regionManager = containerProvider.Resolve();
            regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.HomeView));
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation();
        }
    }
}

2.4 UI 设计要点

  • 首页:使用 ListBox 显示通道列表,DataGrid 显示表格数据,LiveCharts 绘制温度、电压等曲线。

  • 配置界面:使用 TreeView 或 FlowDocument 展示实验流程,支持拖拽调整步骤。

  • 监控界面:使用 Grid 布局展示硬件状态,颜色指示(绿色正常、红色故障)。

  • 日志界面:使用 DataGrid 显示日志,支持筛选和导出。

  • 硬件控制界面:使用 ComboBox 选择硬件,Button 执行操作,TextBox 设置参数。


三、硬件驱动设计

3.1 硬件驱动目标

  • 抽象化:通过接口和抽象类定义硬件通用操作(初始化、开启、关闭、设置、读取)。

  • 可切换:支持不同厂商硬件,通过反射或 DI 动态加载驱动。

  • 多协议:支持串口(COM)、TCP/UDP、Modbus 等通信协议。

  • 事件驱动:硬件状态变化触发事件,通知上层逻辑。

3.2 硬件抽象接口

csharp

namespace SemiconductorTestSystem.Hardware.Interfaces
{
    public interface IHardwareDevice : IDisposable
    {
        string DeviceId { get; }
        string DeviceName { get; }
        DeviceStatus Status { get; }

        Task InitializeAsync();
        Task StartAsync();
        Task StopAsync();
        Task SetParameterAsync(string parameter, object value);
        Task ReadParameterAsync(string parameter);

        event EventHandler StatusChanged;
    }

    public class DeviceStatusChangedEventArgs : EventArgs
    {
        public DeviceStatus Status { get; set; }
        public string Message { get; set; }
    }

    public enum DeviceStatus
    {
        Idle,
        Running,
        Error,
        Disconnected
    }
} 
  

3.3 具体驱动实现(以电源为例)

csharp

using SemiconductorTestSystem.Hardware.Interfaces;
using System.IO.Ports;

namespace SemiconductorTestSystem.Hardware.Drivers
{
    public class TektronixPowerSupply : IHardwareDevice
    {
        private readonly SerialPort _serialPort;
        public string DeviceId { get; }
        public string DeviceName { get; } = "Tektronix Power Supply";
        public DeviceStatus Status { get; private set; }
        public event EventHandler StatusChanged;

        public TektronixPowerSupply(string portName)
        {
            DeviceId = Guid.NewGuid().ToString();
            _serialPort = new SerialPort(portName, 9600);
        }

        public async Task InitializeAsync()
        {
            try
            {
                _serialPort.Open();
                Status = DeviceStatus.Idle;
                RaiseStatusChanged("Initialized");
            }
            catch (Exception ex)
            {
                Status = DeviceStatus.Error;
                RaiseStatusChanged($"Initialization failed: {ex.Message}");
            }
        }

        public async Task StartAsync()
        {
            Status = DeviceStatus.Running;
            RaiseStatusChanged("Started");
        }

        public async Task StopAsync()
        {
            Status = DeviceStatus.Idle;
            RaiseStatusChanged("Stopped");
        }

        public async Task SetParameterAsync(string parameter, object value)
        {
            // 示例:设置电压
            if (parameter == "Voltage")
            {
                _serialPort.WriteLine($"VOLT {value}");
            }
        }

        public async Task ReadParameterAsync(string parameter)
        {
            // 示例:读取电流
            if (parameter == "Current")
            {
                _serialPort.WriteLine("MEAS:CURR?");
                return await Task.FromResult(_serialPort.ReadLine());
            }
            return null;
        }

        private void RaiseStatusChanged(string message)
        {
            StatusChanged?.Invoke(this, new DeviceStatusChangedEventArgs
            {
                Status = Status,
                Message = message
            });
        }

        public void Dispose()
        {
            _serialPort?.Close();
            _serialPort?.Dispose();
        }
    }
} 
  

3.4 硬件驱动加载(反射 + DI)

使用 Autofac 动态注册硬件驱动,支持通过配置文件切换厂商。

csharp

using Autofac;
using SemiconductorTestSystem.Hardware.Interfaces;
using System.Reflection;

namespace SemiconductorTestSystem.Hardware
{
    public class HardwareModule : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            // 动态加载驱动
            var assembly = Assembly.GetExecutingAssembly();
            var driverTypes = assembly.GetTypes()
                .Where(t => typeof(IHardwareDevice).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

            foreach (var type in driverTypes)
            {
                builder.RegisterType(type).As().InstancePerDependency();
            }
        }
    }
}

配置文件(appsettings.json)

json

{
  "Hardware": {
    "PowerSupply": {
      "Type": "TektronixPowerSupply",
      "Port": "COM1"
    },
    "Oven": {
      "Type": "CustomOven",
      "Address": "192.168.1.100",
      "Protocol": "TCP"
    }
  }
}

硬件服务

csharp

using Microsoft.Extensions.Configuration;
using SemiconductorTestSystem.Hardware.Interfaces;

namespace SemiconductorTestSystem.Core.Services
{
    public class HardwareService : IHardwareService
    {
        private readonly IConfiguration _configuration;
        private readonly ILifetimeScope _scope;
        private readonly Dictionary _devices;

        public HardwareService(IConfiguration configuration, ILifetimeScope scope)
        {
            _configuration = configuration;
            _scope = scope;
            _devices = new Dictionary();
            LoadDevices();
        }

        private void LoadDevices()
        {
            var hardwareConfig = _configuration.GetSection("Hardware");
            foreach (var deviceConfig in hardwareConfig.GetChildren())
            {
                var typeName = deviceConfig["Type"];
                var deviceType = Type.GetType($"SemiconductorTestSystem.Hardware.Drivers.{typeName}");
                if (deviceType != null)
                {
                    var device = (IHardwareDevice)_scope.Resolve(deviceType);
                    _devices.Add(deviceConfig.Key, device);
                }
            }
        }

        public IHardwareDevice GetDevice(string deviceId)
        {
            return _devices.ContainsKey(deviceId) ? _devices[deviceId] : null;
        }
    }
}

四、数据存储设计

4.1 数据存储目标

  • 支持多种存储格式:CSV、MySQL、SQL Server、SQLite。

  • 通过配置文件动态切换存储方式。

  • 使用 Entity Framework Core 管理数据库操作。

  • CSV 文件支持自定义格式,通过反射实现灵活存储。

4.2 数据模型

csharp

namespace SemiconductorTestSystem.Core.Models
{
    public class TestData
    {
        public int Id { get; set; }
        public string ChannelId { get; set; }
        public DateTime Timestamp { get; set; }
        public double Temperature { get; set; }
        public double Voltage { get; set; }
        public double Current { get; set; }
        public string TestMode { get; set; }
    }

    public class Channel
    {
        public string Id { get; set; }
        public string ChannelName { get; set; }
        public string OvenId { get; set; }
        public string ZoneId { get; set; }
        public string Status { get; set; }
    }
}

4.3 EF Core 配置

csharp

using Microsoft.EntityFrameworkCore;

namespace SemiconductorTestSystem.Data.DbContexts
{
    public class TestDbContext : DbContext
    {
        public DbSet TestDatas { get; set; }
        public DbSet Channels { get; set; }

        public TestDbContext(DbContextOptions options) : base(options) { }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity().HasKey(t => t.Id);
            modelBuilder.Entity().HasKey(c => c.Id);
        }
    }
}

Startup 配置

csharp

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace SemiconductorTestSystem.UI
{
    public class Startup
    {
        public void ConfigureServices(ContainerBuilder builder, IConfiguration configuration)
        {
            var storageType = configuration["Storage:Type"];
            var connectionString = configuration["Storage:ConnectionString"];

            if (storageType == "MySQL")
            {
                builder.Register(c => new TestDbContext(
                    new DbContextOptionsBuilder()
                        .UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))
                        .Options)).AsSelf().InstancePerLifetimeScope();
            }
            else if (storageType == "SQLite")
            {
                builder.Register(c => new TestDbContext(
                    new DbContextOptionsBuilder()
                        .UseSqlite(connectionString)
                        .Options)).AsSelf().InstancePerLifetimeScope();
            }
        }
    }
}

appsettings.json

json

{
  "Storage": {
    "Type": "SQLite",
    "ConnectionString": "Data Source=testdata.db"
  }
}

4.4 CSV 存储(反射实现)

csharp

using System.Reflection;

namespace SemiconductorTestSystem.Data.Configurations
{
    public class CsvStorageProvider
    {
        private readonly string _filePath;
        private readonly Type _dataType;

        public CsvStorageProvider(string filePath, Type dataType)
        {
            _filePath = filePath;
            _dataType = dataType;
        }

        public async Task SaveAsync(IEnumerable data)
        {
            using var writer = new StreamWriter(_filePath, append: true);
            var properties = _dataType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            
            // 写入表头
            if (new FileInfo(_filePath).Length == 0)
            {
                await writer.WriteLineAsync(string.Join(",", properties.Select(p => p.Name)));
            }

            // 写入数据
            foreach (var item in data)
            {
                var values = properties.Select(p => p.GetValue(item)?.ToString() ?? "");
                await writer.WriteLineAsync(string.Join(",", values));
            }
        }
    }
}

五、实验控制与计算

5.1 TestController 设计

统一管理半导体可靠性实验(HTRB、HTGB、TC 等)。

csharp

using SemiconductorTestSystem.Core.Models;

namespace SemiconductorTestSystem.Core.Services
{
    public interface ITestController
    {
        Task StartTestAsync(string testMode, TestConfig config);
        Task StopTestAsync();
        Task> GetChannelsAsync();
        Task GetChannelDataAsync(string channelId);
    }

    public class TestController : ITestController
    {
        private readonly IHardwareService _hardwareService;
        private readonly IDataStorageService _dataStorageService;
        private readonly ILogService _logService;

        public TestController(IHardwareService hardwareService, IDataStorageService dataStorageService, ILogService logService)
        {
            _hardwareService = hardwareService;
            _dataStorageService = dataStorageService;
            _logService = logService;
        }

        public async Task StartTestAsync(string testMode, TestConfig config)
        {
            _logService.Information($"Starting {testMode} test with config: {config}");
            
            foreach (var step in config.Steps)
            {
                if (step.Type == TestStepType.Temperature)
                {
                    var oven = _hardwareService.GetDevice("Oven");
                    await oven.SetParameterAsync("Temperature", step.Value);
                }
                else if (step.Type == TestStepType.Delay)
                {
                    await Task.Delay(TimeSpan.FromSeconds(step.Value));
                }
            }
        }

        public async Task StopTestAsync()
        {
            _logService.Information("Stopping test");
            var devices = _hardwareService.GetAllDevices();
            foreach (var device in devices)
            {
                await device.StopAsync();
            }
        }
    }
}

5.2 热阻计算(NumSharp)

csharp

using NumSharp;

namespace SemiconductorTestSystem.Calculations
{
    public class ThermalCalculations
    {
        public static double CalculateThermalResistance(double[] temperatures, double[] powers)
        {
            var tempArray = np.array(temperatures);
            var powerArray = np.array(powers);
            var deltaT = tempArray.max() - tempArray.min();
            var avgPower = powerArray.mean();
            return deltaT / avgPower;
        }

        public static NDArray CalculateStructureFunction(double[] times, double[] temperatures)
        {
            // 示例:结构函数计算(简化)
            var timeArray = np.array(times);
            var tempArray = np.array(temperatures);
            return np.cumsum(tempArray) / timeArray;
        }
    }
}

六、日志系统

6.1 Serilog 配置

csharp

using Serilog;

namespace SemiconductorTestSystem.Core.Services
{
    public class SerilogService : ILogService
    {
        public SerilogService()
        {
            Log.Logger = new LoggerConfiguration()
                .WriteTo.Console()
                .WriteTo.File("logs/app.log", rollingInterval: RollingInterval.Day)
                .CreateLogger();
        }

        public void Information(string message) => Log.Information(message);
        public void Error(string message, Exception ex) => Log.Error(ex, message);
    }
}

七、异步 vs 同步

7.1 异步优势

  • 高吞吐量:异步适合高频硬件通信和数据采集,避免 UI 阻塞。

  • 扩展性:异步支持多设备并发操作,适合 200+ 设备场景。

  • 用户体验:异步保持 UI 响应,适合实时监控。

7.2 测试用例

csharp

public class AsyncVsSyncTest
{
    [Fact]
    public async Task AsyncReadTest()
    {
        var device = new Mock();
        device.Setup(d => d.ReadParameterAsync("Voltage")).ReturnsAsync(5.0);

        var stopwatch = Stopwatch.StartNew();
        var result = await device.Object.ReadParameterAsync("Voltage");
        stopwatch.Stop();

        Assert.Equal(5.0, result);
        Assert.True(stopwatch.ElapsedMilliseconds < 100);
    }

    [Fact]
    public void SyncReadTest()
    {
        var device = new Mock();
        device.Setup(d => d.ReadParameterAsync("Voltage")).Returns(Task.FromResult(5.0));

        var stopwatch = Stopwatch.StartNew();
        var result = device.Object.ReadParameterAsync("Voltage").Result; // 阻塞
        stopwatch.Stop();

        Assert.Equal(5.0, result);
        Assert.True(stopwatch.ElapsedMilliseconds < 100);
    }
}

结论:异步优先,特别是在多设备、高频采集场景下,使用 async/await 提高效率和扩展性。


八、扩展功能

8.1 多设备管理

通过 HardwareService 支持动态添加设备,配置文件驱动。

8.2 历史数据查询

csharp

public class DataQueryService
{
    private readonly TestDbContext _dbContext;

    public DataQueryService(TestDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task> QueryDataAsync(string channelId, DateTime startTime, DateTime endTime)
    {
        return await _dbContext.TestDatas
            .Where(d => d.ChannelId == channelId && d.Timestamp >= startTime && d.Timestamp <= endTime)
            .ToListAsync();
    }
}

九、学习路线与教程建议

9.1 C# 高级编程

  1. 基础:掌握类、方法、属性、集合(List、Dictionary 等)。

  2. 面向对象:深入理解封装、继承、多态,设计 SOLID 原则。

  3. 高级特性:

    • 反射:动态加载类型、调用方法,适合动态硬件驱动。 - 接口/抽象类:定义硬件规范,提高扩展性。 - 泛型:约束类型安全,优化数据处理。 - 委托/事件:实现硬件状态通知。 - 多线程/异步:处理高频数据采集。

  4. 设计模式:工厂模式(硬件驱动创建)、单例模式(服务实例)、观察者模式(事件通知)。

  5. 性能优化:使用 Span、Memory 优化内存,Parallel.For 处理并发。

9.2 上位机开发教程

  1. WPF 入门:学习 XAML、数据绑定、命令。

  2. MVVM 实践:使用 Prism 实现导航和模块化。

  3. 硬件通信:掌握 SerialPort、TcpClient、Modbus。

  4. 数据处理:学习 EF Core、CSV 处理、NumSharp 计算。

  5. 日志与调试:使用 Serilog 记录日志,VS 调试工具。


十、后续扩展

如果你需要以下内容,我可以进一步提供:

  • 深度学习模型:集成 ML.NET 用于实验数据预测。

  • 云端部署:使用 Azure 或 AWS 实现远程监控。

  • 200+ 设备优化:基于 Actor 模型(如 Akka.NET)实现分布式设备管理。

  • 边缘计算:在设备端部署轻量级推理模型。

请明确具体需求,我会提供更详细的代码和说明!

你可能感兴趣的:(架构)