基于OxyPlot的C#串口波形显示助手

一、引言

  该简易串口助手借助OxyPlot库进行开发,具有波形显示功能。

二、正文

  关于C#串口助手的开发代码网上较多,不再赘述。开始尝试使用GDI技术,但实现相对繁琐,后了解并使用OxyPlot。OxyPlot是.Net的跨平台绘图库,在NuGet程序包管理器添加OxyPlot的引用即可使用该控件。使用VSPD工具虚拟两串口并运行程序,使用串口调试工具发送数据,波形显示界面如图1所示。

基于OxyPlot的C#串口波形显示助手

图1 波形显示界面

三、程序代码

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Threading.Tasks;
  9 using System.Threading;
 10 using System.Windows.Forms;
 11 using System.IO.Ports;
 12 using OxyPlot;
 13 using OxyPlot.Annotations;
 14 using OxyPlot.Axes;
 15 using OxyPlot.Series;
 16 using System.Collections;
 17 
 18 namespace SerialPortCommunication
 19 {
 20     public partial class FormSampleSerialPortTool : Form
 21     {
 22         public FormSampleSerialPortTool()
 23         {
 24             InitializeComponent();
 25         }
 26         SerialPort sp = new SerialPort();
 27         private void Form1_Load(object sender, EventArgs e)
 28         {
 29             foreach (string com in System.IO.Ports.SerialPort.GetPortNames())
 30             {
 31                 comboBoxPortName.Items.Add(com);
 32             }
 33             comboBoxPortName.SelectedIndex = 0;
 34             comboBoxBaudRate.Items.Add("4800");
 35             comboBoxBaudRate.Items.Add("9600");
 36             comboBoxBaudRate.Items.Add("19200");
 37             comboBoxBaudRate.Items.Add("38400");
 38             comboBoxBaudRate.Items.Add("57600");
 39             comboBoxBaudRate.Items.Add("76800"); 
 40             comboBoxBaudRate.Items.Add("115200");
 41             comboBoxBaudRate.SelectedIndex = 1;
 42             for (int i = 5; i < 9; i++)
 43             {
 44                 comboBoxDataBits.Items.Add(i.ToString());
 45             }
 46             comboBoxDataBits.SelectedIndex = 3;
 47             for (int i = 0; i < 3; i++)
 48             {
 49                 comboBoxStopBits.Items.Add(i.ToString());
 50             }
 51             comboBoxStopBits.Items.Add("1.5");
 52             comboBoxStopBits.SelectedIndex = 1;
 53             comboBoxParity.Items.Add("");
 54             comboBoxParity.Items.Add("奇校验");
 55             comboBoxParity.Items.Add("偶校验");
 56             comboBoxParity.SelectedIndex = 0;
 57             checkBoxSendHex.Checked = true;
 58             checkBoxReciveHex.Checked = true;
 59             sp.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
 60             WaveDisplay();
 61         }
 62         private void buttonOpenSerialPort_Click(object sender, EventArgs e)
 63         {
 64             if (sp.IsOpen==false)
 65             {
 66                 try
 67                 {
 68                     sp.PortName = comboBoxPortName.Text;
 69                     sp.BaudRate = Convert.ToInt32(comboBoxBaudRate.Text);
 70                     sp.DataBits = Convert.ToInt32(comboBoxDataBits.Text);
 71                     switch (comboBoxStopBits.Text)
 72                     {
 73                         case "0":
 74                             sp.StopBits = StopBits.None;
 75                             break;
 76                         case "1":
 77                             sp.StopBits = StopBits.One;
 78                             break;
 79                         case "2":
 80                             sp.StopBits = StopBits.Two;
 81                             break;
 82                         case "1.5":
 83                             sp.StopBits = StopBits.OnePointFive;
 84                             break;
 85                         default:
 86                             break;
 87                     }
 88                     switch (comboBoxParity.Text)
 89                     {
 90                         case "":
 91                             sp.Parity = Parity.None;
 92                             break;
 93                         case "奇校验":
 94                             sp.Parity = Parity.Odd;
 95                             break;
 96                         case "偶校验":
 97                             sp.Parity = Parity.Even;
 98                             break;
 99                         default:
100                             break;
101                     }
102                     sp.Open();
103                     buttonOpenSerialPort.Text = "关闭串口";
104                     comboBoxPortName.Enabled = false;
105                     comboBoxBaudRate.Enabled = false;
106                     comboBoxDataBits.Enabled = false;
107                     comboBoxStopBits.Enabled = false;
108                     comboBoxParity.Enabled = false;
109                 }
110                 catch (Exception)
111                 {
112                     MessageBox.Show("串口打开失败!","错误提示");
113                 }
114             }
115             else
116             {
117                 sp.Close();
118                 buttonOpenSerialPort.Text = "打开串口";
119                 comboBoxPortName.Enabled = true;
120                 comboBoxBaudRate.Enabled = true;
121                 comboBoxDataBits.Enabled = true;
122                 comboBoxStopBits.Enabled = true;
123                 comboBoxParity.Enabled = true;
124             }
125         }
126         private void buttonSendData_Click(object sender, EventArgs e)
127         {
128             try
129             {
130                 string sendAreaText = textBoxDataSendArea.Text.Trim();
131                 byte[] sendData = null;
132                 if (checkBoxSendHex.Checked==false)
133                 {
134                     sendData = Encoding.ASCII.GetBytes(sendAreaText);
135                 }
136                 else
137                 {
138                     if ((sendAreaText.Length) % 2==0)
139                     {
140                         sendData = new byte[(sendAreaText.Length) / 2];
141                         for (int i = 0; i < sendData.Length; i++)
142                         {
143                             sendData[i] = Convert.ToByte(sendAreaText.Substring(i * 2, 2).Replace(" ", ""), 16);
144                         }
145                     }
146                     else
147                     {
148                         string sendAreaNewText = sendAreaText.Substring(0, sendAreaText.Length - 1) + "0" + sendAreaText.Substring(sendAreaText.Length-1,1);
149                         sendData = new byte[(sendAreaNewText.Length) / 2];
150                         for (int i = 0; i < sendData.Length; i++)
151                         {
152                             sendData[i] = Convert.ToByte(sendAreaNewText.Substring(i * 2, 2).Replace(" ", ""), 16);
153                         }
154                     }
155                 }
156                 sp.Write(sendData,0,sendData.Length);
157             }
158             catch (Exception)
159             {
160                 if (sp.IsOpen == false)
161                 {
162                     MessageBox.Show("请先打开串口!", "错误提示");
163                 }
164                 else
165                 {
166                     MessageBox.Show("发送数据错误!", "错误提示");
167                 }
168             }
169         }
170         byte[] receiveData;
171         Queue qData = new Queue();
172         Queue qTime = new Queue();
173         private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
174         {
175             try
176             {
177                 receiveData= new byte[sp.BytesToRead];
178                 sp.Read(receiveData, 0, receiveData.Length);
179                 string receiveContent = null;
180                 if (checkBoxReciveHex.Checked==false)
181                 {
182                     receiveContent += new ASCIIEncoding().GetString(receiveData);
183                 }
184                 else
185                 {
186                     for (int i = 0; i < receiveData.Length; i++)
187                     {
188                         qData.Enqueue(receiveData[i]);
189                         qTime.Enqueue(DateTime.Now);
190                     }
191                     StringBuilder data = new StringBuilder();
192                     for (int i = 0; i < receiveData.Length; i++)
193                     {
194                         data.Append(receiveData[i].ToString("X2") + " ");
195                     }
196                     receiveContent += data.ToString().ToUpper();
197                 }
198                 textBoxDataReceiveArea.Invoke((EventHandler)(delegate
199                 {
200                     textBoxDataReceiveArea.AppendText(receiveContent);
201                 }));
202              }
203             catch (Exception)
204             {
205                 MessageBox.Show("接收数据错误!", "错误提示");
206             }
207         }
208         private void buttonClearData_Click(object sender, EventArgs e)
209         {
210             textBoxDataReceiveArea.Text = "";
211         }
212         void WaveDisplay()
213         {
214             PlotModel myPlotModel = new PlotModel();
215             myPlotModel.Title = "数据波形";
216             DateTimeAxis xDateAxis = new DateTimeAxis()
217             {
218                 Position = AxisPosition.Bottom,
219                 StringFormat = "hh:mm:ss",
220                 Minimum = DateTimeAxis.ToDouble(DateTime.Now),
221                 Maximum = DateTimeAxis.ToDouble(DateTime.Now.AddMinutes(1)),
222                 TitlePosition = 0,
223                 IntervalLength = 60,
224                 MinorIntervalType = DateTimeIntervalType.Seconds,
225                 IntervalType = DateTimeIntervalType.Seconds,
226                 MajorGridlineStyle = LineStyle.Solid,
227                 MinorGridlineStyle = LineStyle.None,
228             };
229             LinearAxis yValueAxis = new LinearAxis();
230             yValueAxis.MajorGridlineStyle = LineStyle.Solid;
231             yValueAxis.MinorGridlineStyle = LineStyle.Dot;
232             yValueAxis.IntervalLength = 20;
233             yValueAxis.Angle = 60;
234             yValueAxis.IsZoomEnabled = false;
235             yValueAxis.IsPanEnabled = false;
236             yValueAxis.Maximum = 100;
237             yValueAxis.Minimum = -1;
238             LineSeries mySeries = new LineSeries();
239             var myLine = new LineSeries();
240             myLine.Color = OxyColors.Green;
241             myLine.StrokeThickness = 2;
242             myLine.MarkerSize = 3;
243             myLine.MarkerStroke = OxyColors.DarkGreen;
244             myLine.MarkerType = MarkerType.Diamond;
245             plotView1.Model = myPlotModel;
246             myPlotModel.Axes.Add(xDateAxis);
247             myPlotModel.Axes.Add(yValueAxis);
248             myPlotModel.Series.Add(myLine);
249             Task.Factory.StartNew(() =>
250             {
251                 var rand = new Random();
252                 bool bToMove = false;
253                 while (true)
254                 {
255                     if (!bToMove)
256                     {
257                         TimeSpan timeSpan = DateTime.Now - DateTimeAxis.ToDateTime(xDateAxis.Minimum);
258                         if (timeSpan.TotalSeconds >= (1))
259                         {
260                             bToMove = true;
261                         }
262                     }
263                     else
264                     {
265                         if (qTime.Count > 0)
266                         {
267                             DateTime t = (DateTime)qTime.Peek();
268                             xDateAxis.Minimum = DateTimeAxis.ToDouble(t.AddSeconds(-10));
269                             xDateAxis.Maximum = DateTimeAxis.ToDouble(t.AddSeconds(0));
270                             myLine.Points.Add(new DataPoint(DateTimeAxis.ToDouble((DateTime)qTime.Dequeue()), (byte)qData.Dequeue()));
271                         }
272                         if (myLine.Points.Count > 1000)
273                         {
274                             myLine.Points.RemoveAt(0);
275                         }
276                         myPlotModel.InvalidatePlot(true);
277                         Thread.Sleep(10);
278                     }
279                 }
280             });
281         }
282     }
283 }

 

四、参考资料

1、GitHub - oxyplot/oxyplot: A cross-platform plotting library for .NET

https://github.com/oxyplot/oxyplot

2、OxyPlot在WinForm中的应用_C#_芝麻麻雀-Asp.Net学习之路-CSDN博客

https://blog.csdn.net/weixin_42930928/article/details/81706540

 

 

基于OxyPlot的C#串口波形显示助手

上一篇:mysql---多表关联


下一篇:WPF三种基本触发器与【与或】逻辑触发器