基于C#的湿度上位机实现方案

基于C#的湿度上位机实现方案,包含实时曲线显示、数据存储和报警功能


一、系统架构

graph TD A[传感器数据] --> B[串口通信模块] B --> C[数据处理中心] C --> D[实时显示模块] C --> E[历史存储模块] C --> F[报警管理模块] D --> G[用户界面] E --> G F --> G

二、核心代码

2.1 串口通信模块

using System.IO.Ports;

public class SerialPortManager : IDisposable
{
    private SerialPort _port;
    private const int BaudRate = 9600;
    private const Parity Parity = Parity.None;
    private const StopBits StopBits = StopBits.One;
    private const int DataBits = 8;

    public event Action<byte[]> DataReceived;

    public void Connect(string portName)
    {
        _port = new SerialPort(portName, BaudRate, Parity, DataBits, StopBits);
        _port.DataReceived += (s, e) => DataReceived?.Invoke(Encoding.ASCII.GetBytes(_port.ReadExisting()));
        _port.Open();
    }

    public void Disconnect() => _port?.Close();

    public void Dispose() => _port?.Dispose();
}

2.2 数据处理模块

public class DataProcessor
{
    public (float Temperature, float Humidity)? ParseData(byte[] data)
    {
        if (data.Length < 6) return null;

        // 假设数据格式:温度高字节+温度低字节+湿度高字节+湿度低字节
        short tempRaw = (short)(data[0] << 8 | data[1]);
        short humiRaw = (short)(data[2] << 8 | data[3]);

        float temperature = tempRaw / 10.0f;
        float humidity = humiRaw / 10.0f;

        return (temperature, humidity);
    }
}

2.3 实时曲线显示

using System.Windows.Forms.DataVisualization.Charting;

public class RealTimeChart
{
    private Chart _chart;
    private Series _tempSeries;
    private Series _humiSeries;
    private Queue<float> _tempBuffer = new Queue<float>();
    private Queue<float> _humiBuffer = new Queue<float>();
    private const int MaxPoints = 100;

    public RealTimeChart(Chart chart)
    {
        _chart = chart;
        InitializeChart();
    }

    private void InitializeChart()
    {
        _tempSeries = new Series("Temperature")
        {
            ChartType = SeriesChartType.Spline,
            Color = Color.Red
        };
        
        _humiSeries = new Series("Humidity")
        {
            ChartType = SeriesChartType.Spline,
            Color = Color.Blue
        };

        _chart.Series.Clear();
        _chart.Series.Add(_tempSeries);
        _chart.Series.Add(_humiSeries);
        
        _chart.ChartAreas[0].AxisX.Interval = 1;
        _chart.ChartAreas[0].AxisY.Interval = 5;
    }

    public void UpdateChart(float temp, float humi)
    {
        if (_tempBuffer.Count >= MaxPoints) _tempBuffer.Dequeue();
        if (_humiBuffer.Count >= MaxPoints) _humiBuffer.Dequeue();

        _tempBuffer.Enqueue(temp);
        _humiBuffer.Enqueue(humi);

        _tempSeries.Points.Clear();
        _humiSeries.Points.Clear();

        for (int i = 0; i < _tempBuffer.Count; i++)
        {
            _tempSeries.Points.AddXY(i, _tempBuffer.ElementAt(i));
            _humiSeries.Points.AddXY(i, _humiBuffer.ElementAt(i));
        }
    }
}

2.4 主程序集成

public partial class MainForm : Form
{
    private SerialPortManager _serialManager;
    private DataProcessor _dataProcessor;
    private RealTimeChart _realTimeChart;

    public MainForm()
    {
        InitializeComponent();
        InitializeComponents();
    }

    private void InitializeComponents()
    {
        _serialManager = new SerialPortManager();
        _dataProcessor = new DataProcessor();
        _realTimeChart = new RealTimeChart(chart1);

        _serialManager.DataReceived += OnDataReceived;
    }

    private void OnDataReceived(byte[] data)
    {
        if (InvokeRequired)
        {
            Invoke(new Action(() => OnDataReceived(data)));
            return;
        }

        var result = _dataProcessor.ParseData(data);
        if (result.HasValue)
        {
            UpdateUI(result.Value.Temperature, result.Value.Humidity);
        }
    }

    private void UpdateUI(float temp, float humi)
    {
        lblTemp.Text = $"{temp:F1} °C";
        lblHumi.Text = $"{humi:F1} %RH";
        _realTimeChart.UpdateChart(temp, humi);
    }

    private void btnConnect_Click(object sender, EventArgs e)
    {
        _serialManager.Connect("COM3");
    }
}

三、关键功能

3.1 报警功能

public class AlarmManager
{
    private const float TempUpper = 30.0f;
    private const float TempLower = 10.0f;
    private const float HumiUpper = 70.0f;
    private const float HumiLower = 30.0f;

    public bool CheckAlarm(float temp, float humi)
    {
        bool tempAlarm = temp > TempUpper || temp < TempLower;
        bool humiAlarm = humi > HumiUpper || humi < HumiLower;

        if (tempAlarm || humiAlarm)
        {
            PlayAlertSound();
            FlashAlarmLight();
            LogAlarm(temp, humi);
            return true;
        }
        return false;
    }

    private void PlayAlertSound()
    {
        System.Media.SoundPlayer player = new System.Media.SoundPlayer("alert.wav");
        player.Play();
    }

    private void FlashAlarmLight()
    {
        panelAlarm.BackColor = panelAlarm.BackColor == Color.Red ? Color.Transparent : Color.Red;
    }

    private void LogAlarm(float temp, float humi)
    {
        string log = $"{DateTime.Now}: Alarm! Temp={temp:F1}°C, Humi={humi:F1}%RH";
        File.AppendAllText("alarm.log", log);
    }
}

3.2 数据存储

public class DataStorage
{
    private const string DbPath = "data.sqlite";
    private SQLiteConnection _connection;

    public DataStorage()
    {
        _connection = new SQLiteConnection($"Data Source={DbPath};Version=3;");
        _connection.Open();
        CreateTable();
    }

    private void CreateTable()
    {
        string sql = @"CREATE TABLE IF NOT EXISTS measurements (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
                        temperature REAL,
                        humidity REAL)";
        using (var cmd = new SQLiteCommand(sql, _connection))
        {
            cmd.ExecuteNonQuery();
        }
    }

    public void SaveData(float temp, float humi)
    {
        string sql = "INSERT INTO measurements (temperature, humidity) VALUES (@temp, @humi)";
        using (var cmd = new SQLiteCommand(sql, _connection))
        {
            cmd.Parameters.AddWithValue("@temp", temp);
            cmd.Parameters.AddWithValue("@humi", humi);
            cmd.ExecuteNonQuery();
        }
    }
}

四、界面设计要点

<!-- 主界面布局示例 -->
<Form>
    <GroupBox Text="实时监测" Dock="Top">
        <Label x:Name="lblTemp" Text="温度: -- °C" FontSize="20"/>
        <Label x:Name="lblHumi" Text="湿度: -- %RH" FontSize="20"/>
        <Chart x:Name="chart1" Height="300"/>
    </GroupBox>

    <GroupBox Text="控制面板" Dock="Bottom">
        <Button x:Name="btnConnect" Text="连接设备" Click="btnConnect_Click"/>
        <Button Text="导出数据" Click="ExportData"/>
    </GroupBox>

    <StatusStrip>
        <ToolStripStatusLabel Text="状态: 未连接"/>
        <ToolStripStatusLabel x:Name="lblAlarmStatus"/>
    </StatusStrip>
</Form>

五、性能优化方案

  1. 数据缓冲机制

    private CircularBuffer<float> _buffer = new CircularBuffer<float>(1000);
    
  2. 双缓冲绘图

    protected override CreateParams CreateParams {
        get {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
            return cp;
        }
    }
    
  3. 异步数据读取

    private async Task ReadDataAsync()
    {
        while (true)
        {
            await Task.Delay(100);
            // 数据处理逻辑
        }
    }
    

参考代码 C#温湿度上位机软件源码 www.youwenfan.com/contentcnj/57308.html

六、调试与测试

  1. 模拟数据测试

    private void GenerateTestData()
    {
        Random rand = new Random();
        for(int i=0; i<100; i++)
        {
            float temp = 20 + rand.NextDouble()*10;
            float humi = 40 + rand.NextDouble()*20;
            _realTimeChart.UpdateChart(temp, humi);
        }
    }
    
  2. 性能监控

    public void MonitorPerformance()
    {
        PerformanceCounter cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
        PerformanceCounter ramCounter = new PerformanceCounter("Memory", "Available MBytes");
    }
    

七、部署方案

  1. 安装包制作

    • 使用Inno Setup创建安装程序
    • 包含依赖项:.NET Framework 4.8、SQLite
  2. 系统服务化

    public class BackgroundService : ServiceBase
    {
        protected override void OnStart(string[] args)
        {
            // 启动数据采集线程
        }
    }
    
posted @ 2025-10-16 15:55  躲雨小伙  阅读(9)  评论(0)    收藏  举报