C#柱状图、折线图、饼图源码 可基于modbus,tcpip协议实时采集数据

在很多工业监控和数据分析场景中,我们需要实时采集数据并通过图表直观展示。今天咱们就来聊聊如何用C#结合Modbus和TCP/IP协议实现数据采集,并绘制柱状图、折线图和饼图。

基于Modbus和TCP/IP的数据采集

Modbus协议相关引用

首先,我们要引用Modbus.Device命名空间来操作Modbus设备。如果还没安装相关库,可以通过NuGet包管理器搜索Modbus.Device进行安装。

简单的TCP/IP连接代码示例

using System;
using System.Net.Sockets;

class TcpIpConnection
{
    private TcpClient client;
    private NetworkStream stream;

    public TcpIpConnection(string ip, int port)
    {
        client = new TcpClient();
        try
        {
            client.Connect(ip, port);
            stream = client.GetStream();
        }
        catch (SocketException e)
        {
            Console.WriteLine($"连接失败: {e.Message}");
        }
    }

    public void SendData(byte[] data)
    {
        if (stream.CanWrite)
        {
            stream.Write(data, 0, data.Length);
        }
    }

    public byte[] ReceiveData(int bufferSize)
    {
        byte[] buffer = new byte[bufferSize];
        int bytesRead = stream.Read(buffer, 0, buffer.Length);
        byte[] receivedData = new byte[bytesRead];
        Array.Copy(buffer, receivedData, bytesRead);
        return receivedData;
    }

    public void Close()
    {
        stream.Close();
        client.Close();
    }
}

在这段代码里,TcpIpConnection类封装了TCP/IP连接的操作。构造函数尝试连接到指定的IP和端口,SendData方法用于发送数据,ReceiveData接收数据并返回,Close方法关闭连接。

Modbus数据读取示例

using Modbus.Device;
using System.Net.Sockets;

class ModbusDataReader
{
    private TcpClient client;
    private ModbusIpMaster master;

    public ModbusDataReader(string ip, int port)
    {
        client = new TcpClient(ip, port);
        master = ModbusIpMaster.CreateIp(client);
    }

    public ushort[] ReadHoldingRegisters(int slaveAddress, int startAddress, int numRegisters)
    {
        try
        {
            return master.ReadHoldingRegisters(slaveAddress, startAddress, numRegisters);
        }
        catch (Exception e)
        {
            Console.WriteLine($"读取寄存器错误: {e.Message}");
            return null;
        }
    }

    public void Dispose()
    {
        master.Dispose();
        client.Close();
    }
}

这里ModbusDataReader类使用ModbusIpMaster来读取Modbus设备的保持寄存器。构造函数创建连接,ReadHoldingRegisters方法实际执行读取操作,Dispose方法释放资源。

图表绘制

柱状图绘制

我们可以使用System.Windows.Forms.DataVisualization.Charting命名空间来绘制图表。先在项目中添加对System.Windows.Forms.DataVisualization的引用。

using System.Windows.Forms.DataVisualization.Charting;

class BarChartCreator
{
    public static void CreateBarChart(Chart chart, string[] categories, int[] values)
    {
        chart.Series.Clear();
        Series series = new Series("BarSeries");
        series.ChartType = SeriesChartType.Column;
        for (int i = 0; i < categories.Length; i++)
        {
            series.Points.AddXY(categories[i], values[i]);
        }
        chart.Series.Add(series);
    }
}

CreateBarChart方法里,先清空图表原有的序列,创建一个新的柱状图序列,然后根据传入的类别和对应的值添加数据点。

折线图绘制

class LineChartCreator
{
    public static void CreateLineChart(Chart chart, string[] categories, int[] values)
    {
        chart.Series.Clear();
        Series series = new Series("LineSeries");
        series.ChartType = SeriesChartType.Line;
        for (int i = 0; i < categories.Length; i++)
        {
            series.Points.AddXY(categories[i], values[i]);
        }
        chart.Series.Add(series);
    }
}

折线图绘制和柱状图类似,只是把图表类型设置为SeriesChartType.Line

饼图绘制

class PieChartCreator
{
    public static void CreatePieChart(Chart chart, string[] labels, int[] values)
    {
        chart.Series.Clear();
        Series series = new Series("PieSeries");
        series.ChartType = SeriesChartType.Pie;
        for (int i = 0; i < labels.Length; i++)
        {
            series.Points.AddXY(labels[i], values[i]);
        }
        chart.Series.Add(series);
    }
}

饼图绘制也是类似的逻辑,图表类型设为SeriesChartType.Pie

结合数据采集与图表更新

在实际应用中,我们可以定时采集数据并更新图表。

using System;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

public partial class MainForm : Form
{
    private Timer dataUpdateTimer;
    private ModbusDataReader reader;

    public MainForm()
    {
        InitializeComponent();
        dataUpdateTimer = new Timer();
        dataUpdateTimer.Interval = 5000; // 每5秒更新一次
        dataUpdateTimer.Tick += DataUpdateTimer_Tick;
        reader = new ModbusDataReader("192.168.1.100", 502);
        dataUpdateTimer.Start();
    }

    private void DataUpdateTimer_Tick(object sender, EventArgs e)
    {
        ushort[] registers = reader.ReadHoldingRegisters(1, 0, 5);
        if (registers!= null)
        {
            int[] values = Array.ConvertAll(registers, Convert.ToInt32);
            string[] categories = { "Cat1", "Cat2", "Cat3", "Cat4", "Cat5" };
            BarChartCreator.CreateBarChart(barChart, categories, values);
            LineChartCreator.CreateLineChart(lineChart, categories, values);
            PieChartCreator.CreatePieChart(pieChart, categories, values);
        }
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        base.OnFormClosing(e);
        reader.Dispose();
        dataUpdateTimer.Stop();
    }
}

在这个MainForm类里,我们创建了一个定时器,每5秒触发一次数据采集并更新柱状图、折线图和饼图。在FormClosing事件里释放资源并停止定时器。

通过上述步骤,我们就可以实现基于Modbus和TCP/IP协议的数据实时采集,并通过不同类型的图表进行直观展示啦。当然,实际应用中还可能需要更多的错误处理和优化,但这已经搭建起了一个基本的框架。希望对大家有所帮助!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐