.NET 8 跨平台自动化开发实战
基于真实中小型自动化项目经验(实验室温湿度监控、智能家居、小型产线测试台等),本文探讨如何全部使用 .NET 8(跨平台)构建解决方案。代码同时适用于 Windows 工控机 / 上位机和树莓派 / 工业迷你 PC / Jetson Nano 等下位机运行环境。
用 C# 做下位机,正好能弥补传统方案的短板。尤其是.NET Core(现在的.NET 8)跨平台之后,C#不仅能跑在Windows上,还能流畅运行在树莓派、工业迷你PC等嵌入式设备上,这让'同一套语言写上下位机'成为可能。
一句话总结:在中小规模、非极端苛刻实时性的场景里,C#上下位机一体化开发是当前性价比最高、最容易维护的方案。
一、典型场景与技术选型对比
| 场景类型 | 传统方案 | C#上下位机一体化方案优势 | 适用性评分 |
|---|---|---|---|
| 实验室温湿度监控 | PLC + 组态王 / LabVIEW | C#统一开发,成本低,易集成数据库/云端,扩展性强 | ★★★★★ |
| 小型产线测试台 | STM32 + 上位机C# | 上下位机共享代码逻辑,调试效率翻倍,维护成本大幅降低 | ★★★★★ |
| 智能家居/小型设备控制 | ESP32 + App/小程序 | C#跨端(桌面+嵌入式+移动端MAUI),生态统一 | ★★★★☆ |
| 高实时运动控制 | 西门子1200 + C#上位机 | 下位机仍建议PLC,上位机C#,不适合C#做下位机 | ★★☆☆☆ |
结论:当实时性要求 < 10ms、需要极高抗干扰时,优先PLC/单片机;当实时性 50–500ms 可接受、需要快速迭代、数据分析、网络通信时,C#上下位机一体化是最佳选择。
二、架构设计与通信协议
[上位机(PC/工控机).NET 8 WinForms / MAUI]
├── UI 层(实时曲线、参数设置、报警看板)
├── 业务层(数据分析、报表、云端同步)
└── 通信层(MQTT / TCP Socket / gRPC)
↑↓(同一协议,双向通信)
[下位机(树莓派 / 迷你 PC / Jetson).NET 8 Console / Worker Service]
├── 采集层(串口 / I2C / GPIO / ADC)
├── 执行层(继电器 / PWM / DAC / 步进电机)
└── 通信层(MQTT / TCP Socket / gRPC)
↑↓
[物理层]
├── 传感器(DHT22、SHT30、PT100、压力变送器)
└── 执行器(继电器、电磁阀、步进电机、伺服)
核心通信协议选择(中小项目推荐排序):
- MQTT(首选):轻量、发布订阅、断网续传、跨端天然支持
- TCP Socket:自定义协议,延迟最低,适合高频小包
- gRPC:结构化、高性能、支持流式通信(未来趋势)
- Modbus TCP:兼容老设备,但效率较低
三、实战代码实现(温湿度监控 + 设备控制)
1. 下位机(树莓派 / 迷你 PC)核心代码(Console + MQTT)
下位机项目:Worker Service(.NET 8)
using Microsoft.Extensions.Hosting;
Microsoft.Extensions.Logging;
MQTTnet;
MQTTnet.Client;
System.Device.Gpio;
System.Device.I2c;
Iot.Device.Dht;
:
{
ILogger<Worker> _logger;
IMqttClient _mqttClient;
Dht22 _dht22;
{
_logger = logger;
}
{
_dht22 = Dht22(, PinNumberingScheme.Board);
factory = MqttFactory();
_mqttClient = factory.CreateMqttClient();
options = MqttClientOptionsBuilder()
.WithTcpServer(, )
.WithClientId( + Guid.NewGuid().ToString().Substring(, ))
.Build();
_mqttClient.ConnectAsync(options, stoppingToken);
_mqttClient.SubscribeAsync( MqttTopicFilterBuilder().WithTopic().Build());
_mqttClient.ApplicationMessageReceivedAsync += e =>
{
topic = e.ApplicationMessage.Topic;
payload = Encoding.UTF8.GetString(e.ApplicationMessage.PayloadSegment);
(topic == )
{
state = payload == ;
controller = GpioController();
controller.OpenPin(, PinMode.Output);
controller.Write(, state ? PinValue.High : PinValue.Low);
_logger.LogInformation(, state ? : );
}
};
(!stoppingToken.IsCancellationRequested)
{
{
reading = _dht22.Read();
(reading.IsValid)
{
json = System.Text.Json.JsonSerializer.Serialize(
{
temperature = reading.Temperature.DegreesCelsius,
humidity = reading.Humidity.Percent,
timestamp = DateTime.UtcNow
});
msg = MqttApplicationMessageBuilder()
.WithTopic()
.WithPayload(json)
.Build();
_mqttClient.PublishAsync(msg, stoppingToken);
}
}
(Exception ex)
{
_logger.LogError(ex, );
}
Task.Delay(, stoppingToken);
}
}
}

