最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于C# WinForm實現串口數據讀取與實時折線圖顯示

 更新時間:2026年02月27日 08:55:18   作者:foundbug999  
這篇文章主要介紹了如何使用C# WinForms開發(fā)一個串口數據讀取和實時顯示的系統,包括系統架構設計、核心代碼實現、關鍵功能、界面設計、擴展功能、調試優(yōu)化、部署方案以及測試用例,需要的朋友可以參考下

一、系統架構設計

二、核心代碼實現

1. 串口通信模塊(SerialPortManager.cs)

using System.IO.Ports;
using System.Threading.Tasks;

public class SerialPortManager : IDisposable
{
    private SerialPort _port;
    private readonly BlockingCollection<byte[]> _buffer = new(100);
    private CancellationTokenSource _cts;

    public event Action<byte[]> DataReceived;

    public void Connect(string portName, int baudRate = 115200)
    {
        _port = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One)
        {
            ReadTimeout = 1000,
            WriteTimeout = 1000
        };
        
        _cts = new CancellationTokenSource();
        _ = Task.Run(() => ReadDataAsync(_cts.Token));
    }

    private async Task ReadDataAsync(CancellationToken token)
    {
        try
        {
            while (!token.IsCancellationRequested)
            {
                int bytesAvailable = _port.BytesToRead;
                if (bytesAvailable > 0)
                {
                    byte[] chunk = new byte[bytesAvailable];
                    _port.Read(chunk, 0, bytesAvailable);
                    _buffer.Add(chunk, token);
                    DataReceived?.Invoke(chunk);
                }
                await Task.Delay(10, token);
            }
        }
        catch (OperationCanceledException) { }
        catch (Exception ex)
        {
            HandleError($"串口讀取錯誤: {ex.Message}");
        }
    }

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

    private void HandleError(string message)
    {
        // 實現錯誤處理邏輯
    }
}

2. 數據解析與圖表更新(MainForm.cs)

using System.Windows.Forms.DataVisualization.Charting;

public partial class MainForm : Form
{
    private readonly SerialPortManager _serialManager;
    private readonly CircularBuffer<float> _dataBuffer = new(1000);
    private Chart _chart;
    private Series _series;

    public MainForm()
    {
        InitializeComponent();
        InitializeChart();
        _serialManager = new SerialPortManager();
        _serialManager.DataReceived += OnDataReceived;
    }

    private void InitializeChart()
    {
        _chart = new Chart { Dock = DockStyle.Fill };
        _series = new Series("傳感器數據")
        {
            ChartType = SeriesChartType.Spline,
            BorderWidth = 2,
            Color = Color.Blue
        };

        _chart.Series.Add(_series);
        _chart.ChartAreas[0].AxisX.Title = "時間";
        _chart.ChartAreas[0].AxisY.Title = "數值";
        _chart.ChartAreas[0].AxisX.Interval = 1;
        _chart.ChartAreas[0].AxisY.Interval = 5;
        
        this.Controls.Add(_chart);
    }

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

        // 假設數據格式:溫度高字節(jié)+溫度低字節(jié)(16位)
        if (data.Length >= 2)
        {
            short raw = (short)(data[0] << 8 | data[1]);
            float value = raw / 10.0f;
            _dataBuffer.Enqueue(value);
            UpdateChart();
        }
    }

    private void UpdateChart()
    {
        if (_dataBuffer.Count > _chart.Series[0].Points.Count)
        {
            _chart.Series[0].Points.AddY(_dataBuffer.Last());
            if (_chart.Series[0].Points.Count > 1000)
            {
                _chart.Series[0].Points.RemoveAt(0);
            }
        }
        
        // 啟用雙緩沖減少閃爍
        _chart.DoubleBuffered = true;
        _chart.Invalidate();
    }

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

    private void btnDisconnect_Click(object sender, EventArgs e)
    {
        _serialManager.Disconnect();
    }
}

三、關鍵功能實現

1. 數據緩沖區(qū)(CircularBuffer.cs)

public class CircularBuffer<T>
{
    private readonly T[] _buffer;
    private int _head;
    private int _tail;
    private int _count;

    public CircularBuffer(int capacity)
    {
        _buffer = new T[capacity];
    }

    public void Enqueue(T item)
    {
        _buffer[_head] = item;
        _head = (_head + 1) % _buffer.Length;
        if (_count < _buffer.Length) _count++;
        else _tail = (_tail + 1) % _buffer.Length;
    }

    public T Dequeue() => _buffer[_tail];

    public T Last() => _buffer[(_tail + _count - 1) % _buffer.Length];

    public int Count => _count;
}

2. 性能優(yōu)化配置

// 在Form_Load事件中配置
private void MainForm_Load(object sender, EventArgs e)
{
    // 啟用雙緩沖
    this.DoubleBuffered = true;
    
    // 設置控件更新模式
    _chart.Series[0].ChartType = SeriesChartType.FastLine;
    _chart.ChartAreas[0].AxisX.ScrollBar.Enabled = true;
    _chart.ChartAreas[0].AxisX.ScaleView.Size = 60; // 顯示最近60秒數據
}

// 定時清理舊數據
private void timerCleanup_Tick(object sender, EventArgs e)
{
    while (_dataBuffer.Count > 1000)
    {
        _dataBuffer.Dequeue();
        _chart.Series[0].Points.RemoveAt(0);
    }
}

四、界面設計(MainForm.Designer.cs)

partial class MainForm
{
    private System.ComponentModel.IContainer components = null;
    private Button btnConnect;
    private Button btnDisconnect;

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    private void InitializeComponent()
    {
        this.btnConnect = new System.Windows.Forms.Button();
        this.btnDisconnect = new System.Windows.Forms.Button();
        
        this.SuspendLayout();
        
        // 連接按鈕
        this.btnConnect.Location = new System.Drawing.Point(20, 20);
        this.btnConnect.Size = new System.Drawing.Size(75, 23);
        this.btnConnect.Text = "連接";
        this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click);
        
        // 斷開按鈕
        this.btnDisconnect.Location = new System.Drawing.Point(101, 20);
        this.btnDisconnect.Size = new System.Drawing.Size(75, 23);
        this.btnDisconnect.Text = "斷開";
        this.btnDisconnect.Click += new System.EventHandler(this.btnDisconnect_Click);
        
        // 主布局
        this.Controls.Add(this.btnDisconnect);
        this.Controls.Add(this.btnConnect);
        this.ClientSize = new System.Drawing.Size(800, 600);
        this.Name = "MainForm";
        this.Text = "串口實時監(jiān)控";
        this.ResumeLayout(false);
    }
}

五、擴展功能實現

1. 多通道支持

// 修改數據解析邏輯
private void OnDataReceived(byte[] data)
{
    if (data.Length >= 4)
    {
        short tempRaw = (short)(data[0] << 8 | data[1]);
        short humiRaw = (short)(data[2] << 8 | data[3]);
        
        float temp = tempRaw / 10.0f;
        float humi = humiRaw / 10.0f;
        
        _tempBuffer.Enqueue(temp);
        _humiBuffer.Enqueue(humi);
        
        UpdateCharts();
    }
}

private void UpdateCharts()
{
    if (_chart.Series.Count < 2)
    {
        _chart.Series.Add(new Series("濕度") { ChartType = SeriesChartType.Spline, Color = Color.Red });
    }
    
    // 更新溫度曲線
    if (_tempBuffer.Count > _chart.Series[0].Points.Count)
    {
        _chart.Series[0].Points.AddY(_tempBuffer.Last());
        _chart.Series[0].Points.RemoveAt(0);
    }
    
    // 更新濕度曲線
    if (_humiBuffer.Count > _chart.Series[1].Points.Count)
    {
        _chart.Series[1].Points.AddY(_humiBuffer.Last());
        _chart.Series[1].Points.RemoveAt(0);
    }
}

2. 數據存儲集成

// 添加SQLite存儲
public class DataStorage
{
    private readonly string _dbPath = "data.sqlite";
    
    public void SaveData(float temp, float humi)
    {
        using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
        {
            conn.Open();
            var cmd = new SQLiteCommand(
                "INSERT INTO sensor_data (timestamp, temperature, humidity) " +
                "VALUES (datetime('now'), @temp, @humi)", conn);
                
            cmd.Parameters.AddWithValue("@temp", temp);
            cmd.Parameters.AddWithValue("@humi", humi);
            cmd.ExecuteNonQuery();
        }
    }
}

// 在OnDataReceived中調用
private void OnDataReceived(byte[] data)
{
    // ...解析數據...
    _storage.SaveData(temp, humi);
}

六、調試與優(yōu)化建議

1. 性能監(jiān)控

// 在狀態(tài)欄顯示性能指標
private void UpdatePerformanceMetrics()
{
    var cpuUsage = new PerformanceCounter("Processor", "% Processor Time", "_Total");
    var ramUsage = new PerformanceCounter("Memory", "Available MBytes");
    
    lblStatus.Text = $"CPU: {cpuUsage.NextValue()}% | 內存: {ramUsage.NextValue()}MB";
}

2. 異常處理

// 添加串口狀態(tài)監(jiān)控
private void CheckSerialPortStatus()
{
    if (!_serialManager.IsOpen)
    {
        btnConnect.Enabled = true;
        btnDisconnect.Enabled = false;
        lblStatus.Text = "串口未連接";
    }
    else
    {
        btnConnect.Enabled = false;
        btnDisconnect.Enabled = true;
        lblStatus.Text = "數據接收中...";
    }
}

七、部署方案

1. 安裝包配置(Inno Setup腳本)

[Files]
Source: "YourApp.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "zlgcan.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "data.sqlite"; DestDir: "{app}"; Flags: ignoreversion

[Icons]
Name: "{group}\實時監(jiān)控"; Filename: "{app}\YourApp.exe"

2. 系統服務化

public class BackgroundService : ServiceBase
{
    protected override void OnStart(string[] args)
    {
        _serialManager.Connect("COM3");
        _timer.Start();
    }

    protected override void OnStop()
    {
        _serialManager.Disconnect();
        _timer.Stop();
    }
}

八、測試用例

1. 模擬數據測試

// 生成測試數據
private void GenerateTestData()
{
    var rand = new Random();
    var timer = new Timer(100);
    timer.Elapsed += (s, e) => {
        var temp = 20 + rand.NextDouble() * 10;
        var humi = 40 + rand.NextDouble() * 20;
        _serialManager.RaiseDataReceived(new byte[] 
        { (byte)(temp >> 8), (byte)temp, (byte)(humi >> 8), (byte)humi });
    };
    timer.Start();
}

2. 壓力測試

// 高負載數據測試
private void HighLoadTest()
{
    var buffer = new byte[1024 * 1024]; // 1MB數據塊
    Parallel.For(0, 1000, i => {
        _serialManager.RaiseDataReceived(buffer);
    });
}

以上就是基于C# WinForm實現串口數據讀取與實時折線圖顯示的詳細內容,更多關于C# WinForm串口數據讀取與折線圖顯示的資料請關注腳本之家其它相關文章!

相關文章

  • C# 委托中 Invoke/BeginInvoke/EndInvoke和DynamicInvoke 方法的區(qū)別和聯系

    C# 委托中 Invoke/BeginInvoke/EndInvoke和DynamicInvoke&

    在C#中,委托(Delegate)提供了多種調用方式,包括 Invoke、BeginInvoke、EndInvoke 和 DynamicInvoke,每種調用方式都有其特定的用途和適用場景,下面將詳細介紹這些方法的區(qū)別與聯系,感興趣的朋友一起看看吧
    2025-03-03
  • WPF實現html中的table控件的示例代碼

    WPF實現html中的table控件的示例代碼

    相信很多做WPF開發(fā)的小伙伴都遇到過表格類的需求,雖然現有的Grid控件也能實現,但是使用起來的體驗感并不好,所以本文我們就來用WPF自己實現一個html中的table控件吧
    2024-03-03
  • C# 利用ICSharpCode.SharpZipLib實現在線壓縮和解壓縮

    C# 利用ICSharpCode.SharpZipLib實現在線壓縮和解壓縮

    本文主要主要介紹了利用ICSharpCode.SharpZipLib第三方的DLL庫實現在線壓縮和解壓縮的功能,并做了相關的代碼演示。
    2016-04-04
  • C#從XmlDocument提取完整字符串的方法

    C#從XmlDocument提取完整字符串的方法

    文章介紹了兩種生成格式化XML字符串的方法,方法一使用`XmlDocument`的`OuterXml`屬性,但輸出的XML字符串不帶格式,可讀性差,方法二利用`XmlWriterSettings`控制格式,并通過`MemoryStream`作為輸出流,可以自定義編碼,如UTF-8,感興趣的朋友跟隨小編一起看看吧
    2025-02-02
  • 簡單C#代碼實現modbus-rtu通訊發(fā)送數據方式

    簡單C#代碼實現modbus-rtu通訊發(fā)送數據方式

    這篇文章主要介紹了簡單C#代碼實現modbus-rtu通訊發(fā)送數據方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • C#鍵值對容器的介紹

    C#鍵值對容器的介紹

    C#鍵值對容器的介紹,需要的朋友可以參考一下
    2013-05-05
  • C#?wpf使用DockPanel實現制作截屏框

    C#?wpf使用DockPanel實現制作截屏框

    做桌面客戶端的時候有時需要實現截屏功能,能夠在界面上框選截屏,本文就來為大家介紹一下wpf如何使用DockPanel制作截屏框吧,感興趣的可以了解下
    2023-09-09
  • C#中的正則表達式雙引號問題

    C#中的正則表達式雙引號問題

    正則表達式獲取CSS里面的圖片的例子,里面有URL里面的圖片地址有雙引號,要注意用兩個雙引號表示
    2015-05-05
  • Unity實現虛擬鍵盤

    Unity實現虛擬鍵盤

    這篇文章主要為大家詳細介紹了Unity實現虛擬鍵盤,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • c#中winform根據郵箱地址和密碼一鍵發(fā)送email的實現

    c#中winform根據郵箱地址和密碼一鍵發(fā)送email的實現

    本文主要介紹了c#winform根據郵箱地址和密碼一鍵發(fā)送email的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07

最新評論

石狮市| 西昌市| 甘孜| 洪雅县| 巴林右旗| 高雄市| 肇东市| 遂昌县| 霍城县| 福鼎市| 临清市| 株洲县| 芮城县| 梁河县| 高雄县| 罗江县| 金阳县| 上杭县| 锡林郭勒盟| 哈密市| 从化市| 台安县| 墨江| 陆良县| 泗洪县| 兴安盟| 祁连县| 镇原县| 怀宁县| 万源市| 邯郸县| 汪清县| 桂东县| 佛坪县| 荣成市| 陆河县| 白山市| 邓州市| 东源县| 安龙县| 凉城县|