前言:本文全部純手工打造,如有疏漏之處,還請諒解!
如果需要查看更多文章,請微信搜索公眾號 csharp編程大全,需要進C#交流群群請加微信z438679770,備注進群, 我邀請你進群! ! !
這篇文章涉及較多C#重要知識點,如果都能看懂,你至少可以算得上入門了!有興趣的同志可以下載原始碼除錯.
開始吧:
-》指令格式介紹
激光測距模塊
UDP: 192.168.1.200 8008發往8010;192.168.1.201 8008發往8011;
協議:C3 00為195cm

光電開關模塊
UDP:192.168.1.202 8008發往8012
幀頭59 59
資料 01 01 01 01 為4個光電開關狀態,依次為安檢通道入口光電開關、安檢門光電開關1、安檢門光電開關2,安檢通道出口光電開關,其中1為無人遮擋狀態,0為有人遮擋狀態
填充 44 55 66 77 88 99 00 12 23 34 45 56 67 ee

4個光電開關均無人
1、2、3光電開關有人 4光電開關無人
開發軟硬體環境:
硬體:1. 4路光電開關,4路測距雷達,資料通過udp發送到主機192.168.1.119
軟體:1. vs2017 + win10
-》重要知識點:
1. 多執行緒操作:thread和task的使用
2. winform的chart控制元件使用
3.佇列Queue和list使用
4.雙緩沖用法
5.定時器操作
6.執行緒中操作主表單控制元件:
this.Invoke((EventHandler)delegate
{
richTextBoxEx1.Text += stringData + "\r\n";
}):
7.通過回圈的方式遍歷操作控制元件
8.資料型別轉換:
Byte[] recv = client.Receive(ref endpoint);
string stringData = "https://www.cnblogs.com/zyr365/archive/2020/10/12/0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
-》開發難點:
1. chart需要繪制所有采集上來的資料點,光電開關1毫秒就一組資料,繪圖時間得跟得上
2. 多執行緒的靈活使用
全部代碼:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace lidarTest
{
public partial class mainForm : DevComponents.DotNetBar.Office2007Form
{
public mainForm()
{
this.DoubleBuffered = true;//設定本表單
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
SetStyle(ControlStyles.DoubleBuffer, true); // 雙緩沖
this.EnableGlass = false;
InitializeComponent();
InitChart();
checkBox2.Checked = false;
checkBox1.Checked = false;
}
private Queue<int>[] dataQueue = new Queue<int>[8];//把Queue<double>看成一個型別 int[] a=new int [8]
private List<int>[] dataList = new List<int>[8];
private Queue<string> dQueue = new Queue<string>();
bool isStart = false;
int count = 0;
private static readonly object Lock = new object();
Stopwatch elapsetime = new Stopwatch();
private void mainForm_Load(object sender, EventArgs e)
{
dataQueue[0] = new Queue<int>();
dataQueue[1] = new Queue<int>();
dataQueue[2] = new Queue<int>();
dataQueue[3] = new Queue<int>();
dataQueue[4] = new Queue<int>();
dataQueue[5] = new Queue<int>();
dataQueue[6] = new Queue<int>();
dataQueue[7] = new Queue<int>();
dataList[0] = new List<int>();
dataList[1] = new List<int>();
dataList[2] = new List<int>();
dataList[3] = new List<int>();
dataList[4] = new List<int>();
dataList[5] = new List<int>();
dataList[6] = new List<int>();
dataList[7] = new List<int>();
this.WindowState = FormWindowState.Normal;
this.FormBorderStyle = FormBorderStyle.Sizable;
this.Top = 0;
this.Left = 0;
this.Width = Screen.PrimaryScreen.WorkingArea.Width;
this.Height = Screen.PrimaryScreen.WorkingArea.Height;
Start();
//MessageBox.Show( DateTime.Now.ToString("yyyy_MM_dd_hh_mm_ss_fff"));
}
// 防止閃屏
//protected override CreateParams CreateParams
//{
// get
// {
// CreateParams cp = base.CreateParams;
// cp.ExStyle |= 0x02000000;
// return cp;
// }
//}
public void Start()
{
Thread t1 = new Thread(StartDataRevThread1); //第一路激光雷達資料接收執行緒
t1.Start();
t1.IsBackground = true;
Thread t2 = new Thread(StartDataRevThread2); //第二路激光雷達資料接收執行緒
t2.Start();
t2.IsBackground = true;
Thread t3 = new Thread(StartDataRevThread3);//第三路激光雷達資料接收執行緒
t3.Start();
t3.IsBackground = true;
Thread t4 = new Thread(StartDataRevThread4);////第四路激光雷達資料接收執行緒
t4.Start();
t4.IsBackground = true;
Thread t5 = new Thread(StartDataRevThread5);//四個廣電開關資料接受執行緒
t5.Start();
t5.IsBackground = true;
Thread t6 = new Thread(dataSaveThread6);//資料寫入執行緒
t6.Start();
t6.IsBackground = true;
}
private void StartDataRevThread1()
{
try
{
UdpClient client = new UdpClient(8021);
//IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);//
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.30"), 8008);
//client.Client.ReceiveBufferSize = 40960;//40960 默認值是8192
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
string stringData = "https://www.cnblogs.com/zyr365/archive/2020/10/12/0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
this.Invoke((EventHandler)delegate
{
//richTextBoxEx1.Text += stringData + "\r\n";
chartShow( recv[2] + (recv[3]<<8),1);
}
);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace) ;
}
}
private void StartDataRevThread2()
{
try
{
UdpClient client = new UdpClient(8022);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.40"), 8008);
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
string stringData = "https://www.cnblogs.com/zyr365/archive/2020/10/12/0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
this.Invoke((EventHandler)delegate
{
//richTextBoxEx2.Text += stringData + "\r\n";
chartShow(recv[2] + (recv[3] << 8),2);
}
);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
}
private void StartDataRevThread3()
{
try
{
UdpClient client = new UdpClient(8023);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.100"), 8008);
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
string stringData = "https://www.cnblogs.com/zyr365/archive/2020/10/12/0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
this.Invoke((EventHandler)delegate
{
//richTextBoxEx3.Text += stringData + "\r\n";
chartShow( recv[2] + (recv[3] << 8),3);
}
);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
}
private void StartDataRevThread4()
{
try
{
UdpClient client = new UdpClient(8024);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.200"), 8008);
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
string stringData = "https://www.cnblogs.com/zyr365/archive/2020/10/12/0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
this.Invoke((EventHandler)delegate
{
//richTextBoxEx4.Text += stringData + "\r\n";
chartShow( recv[2] + (recv[3] << 8),4);
}
);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
}
private void StartDataRevThread5()
{
try
{
UdpClient client = new UdpClient(8012);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.202"), 8008);
client.Client.ReceiveBufferSize = 1024*1024;//默認值是8192
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
elapsetime.Restart();//計時開始
this.Invoke((EventHandler)delegate
{
//if (count >= 100)
{
count = 0;
Task.Run(() =>
{
chartShow(recv[2], 5);
}
);
Task.Run(() =>
{
chartShow(recv[3], 6);
}
);
Task.Run(() =>
{
chartShow(recv[4], 7);
}
);
Task.Run(() =>
{
chartShow(recv[5], 8);
}
);
//chartShow(recv[2], 5);
//chartShow(recv[3], 6);
//chartShow(recv[4], 7);
//chartShow(recv[5], 8);
if (checkBox2.Checked == true)
{
string stringData = "https://www.cnblogs.com/zyr365/archive/2020/10/12/0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
dQueue.Enqueue(DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss:fff") + " " + stringData);
}
}
count++;
} );
elapsetime.Stop();//計時結束
this.Invoke((EventHandler)delegate
{
label1.Text = "接收資料耗時:"+ elapsetime.ElapsedMilliseconds.ToString("0000");
});
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
}
private void dataSaveThread6()
{
while (true)
{
if (checkBox2.Checked == true)
{
String LogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log");
if (dQueue.Count() > 0)
strWrite(dQueue.Dequeue(), LogPath, "log.txt");
}
}
}
private void InitChart()
{
Chart[] ch = new Chart[12] { chart1, chart2, chart3, chart4,chart5, chart6, chart7, chart8 , chart_1, chart_2, chart_3, chart_4 };
for (int i = 0; i < 4 ; i++)
{
ch[i].ChartAreas.Clear();
ChartArea chartArea1 = new ChartArea("C1");
ch[i].ChartAreas.Add(chartArea1);
//定義存盤和顯示點的容器
ch[i].Series.Clear();
Series series1 = new Series("S1");
series1.ChartArea = "C1";
ch[i].Series.Add(series1);
ch[i].ChartAreas[0].AxisY.IsStartedFromZero = false;
ch[i].Legends[0].Enabled = false;
ch[i].ChartAreas[0].AxisX.Interval = 100;
ch[i].ChartAreas[0].AxisX.Maximum = 1000;
//ch[i].ChartAreas[0].AxisX.ScaleView.Size = 8;//設定圖表可視區域資料點數,說白了一次可以看到多少個X軸區域
ch[i].ChartAreas[0].Axes[0].MajorGrid.Enabled = false;
ch[i].ChartAreas[0].Axes[1].MajorGrid.Enabled = false;
//y軸上網格
//ct.ChartAreas[0].Axes[1].MajorGrid.Enabled = false;
//ch[i].ChartAreas[0].AxisX.IsStartedFromZero = false;
//ch[i].ChartAreas[0].AxisX.MajorGrid.LineColor = System.Drawing.Color.Silver;
//ch[i].ChartAreas[0].AxisY.MajorGrid.LineColor = System.Drawing.Color.Silver;
//設定標題
ch[i].Titles.Clear();
//ch[i].Titles.Add("S01");
//ch[i].Titles[0].Text = "通道" + (i + 1) + " 折線圖顯示";
//ch[i].Titles[0].ForeColor = Color.RoyalBlue;
//ch[i].Titles[0].Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
//設定圖表顯示樣式
ch[i].Series[0].Color = Color.Red;
//this.chart1.Titles[0].Text = string.Format("{0}折線圖顯示", );
ch[i].Series[0].ChartType = SeriesChartType.FastLine;
ch[i].Series[0].Points.Clear();
}
for (int i = 4; i < 12; i++)
{
ch[i].ChartAreas.Clear();
ChartArea chartArea1 = new ChartArea("C1");
ch[i].ChartAreas.Add(chartArea1);
//定義存盤和顯示點的容器
ch[i].Series.Clear();
Series series1 = new Series("S1");
series1.ChartArea = "C1";
ch[i].Series.Add(series1);
ch[i].ChartAreas[0].AxisY.IsStartedFromZero = false;
ch[i].Legends[0].Enabled = false;
//ch[i].ChartAreas[0].AxisX.Interval = 100;
//ch[i].ChartAreas[0].AxisX.Maximum = 10000;
//ch[i].ChartAreas[0].AxisX.ScaleView.Size = 8;//設定圖表可視區域資料點數,說白了一次可以看到多少個X軸區域
ch[i].ChartAreas[0].Axes[0].MajorGrid.Enabled = false;
ch[i].ChartAreas[0].Axes[1].MajorGrid.Enabled = false;
//y軸上網格
//ct.ChartAreas[0].Axes[1].MajorGrid.Enabled = false;
//ch[i].ChartAreas[0].AxisX.IsStartedFromZero = false;
//ch[i].ChartAreas[0].AxisX.MajorGrid.LineColor = System.Drawing.Color.Silver;
//ch[i].ChartAreas[0].AxisY.MajorGrid.LineColor = System.Drawing.Color.Silver;
//設定標題
ch[i].Titles.Clear();
//ch[i].Titles.Add("S01");
//ch[i].Titles[0].Text = "通道" + (i + 1) + " 折線圖顯示";
//ch[i].Titles[0].ForeColor = Color.RoyalBlue;
//ch[i].Titles[0].Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
//設定圖表顯示樣式
ch[i].Series[0].Color = Color.Red;
//this.chart1.Titles[0].Text = string.Format("{0}折線圖顯示", );
ch[i].Series[0].ChartType = SeriesChartType.FastLine;
ch[i].Series[0].Points.Clear();
}
}
public void chartShow(int y, int ch)
{
Chart[] chNum = new Chart[8] { chart_1, chart_2, chart_3, chart_4, chart5, chart6, chart7, chart8 };
if (ch <= 8)
chartDisplay(chNum[ch - 1], ch, y);
}
delegate void ChartDelegate(Chart chart, int ch, int y);
private void chartDisplay(Chart chart, int ch, int y)
{
if (chart.InvokeRequired)
{
ChartDelegate chartDelegate = chartDisplay;
chart.Invoke(chartDelegate, new object[] { chart, ch, y });
}
else
{
lock (Lock)
{
if (isStart == true)
UpdateQueueValue(ch, y);//點擊開啟按鈕后,開始采集收集資料,并更新到佇列或串列中
}
}
}
private void UpdateQueueValue(int ch, int y)
{
lock (Lock)
{
if (dataQueue[ch - 1].Count > 1000)
//先出列
dataQueue[ch - 1].Dequeue();
dataQueue[ch - 1].Enqueue(y);
//方法二 用list
//if (dataList[ch - 1].Count > 20000)
// dataList[ch - 1].RemoveAt(0);
//dataList[ch - 1-4].Add(2);
dataList[ch - 1].Add(y);
}
}
private void btnStart_Click(object sender, EventArgs e)
{
if (!isStart)
{
dataQueue[0] = new Queue<int>();
dataQueue[1] = new Queue<int>();
dataQueue[2] = new Queue<int>();
dataQueue[3] = new Queue<int>();
dataQueue[4] = new Queue<int>();
dataQueue[5] = new Queue<int>();
dataQueue[6] = new Queue<int>();
dataQueue[7] = new Queue<int>();
dataList[0] = new List<int>();
dataList[1] = new List<int>();
dataList[2] = new List<int>();
dataList[3] = new List<int>();
dataList[4] = new List<int>();
dataList[5] = new List<int>();
dataList[6] = new List<int>();
dataList[7] = new List<int>();
chart_1.Series[0].Points.Clear();
chart_2.Series[0].Points.Clear();
chart_3.Series[0].Points.Clear();
chart_4.Series[0].Points.Clear();
chart5.Series[0].Points.Clear();
chart6.Series[0].Points.Clear();
chart7.Series[0].Points.Clear();
chart8.Series[0].Points.Clear();
btnStart.Text = @"停止采集";
btnStart.DisabledImage = btnStart.Image;
btnStart.Image = (Image)btnStart.PressedImage.Clone();
isStart = !isStart;
}
else
{
btnStart.Text = @"開始采集";
btnStart.Image = btnStart.DisabledImage;
isStart = !isStart;
}
}
/*************檔案寫入函式**************/
private void strWrite(string str, string filePath, string fileName)
{
lock (Lock)
{
if (!Directory.Exists(filePath))
Directory.CreateDirectory(filePath);
if (!File.Exists(filePath + "\\" + fileName))
File.Create(filePath + "\\" + fileName).Close(); //.Close 很關鍵,不然會有問題
StreamWriter sw = new StreamWriter(filePath + "\\" + fileName, true);//true 追加資料
sw.WriteLine(str);
sw.Close();
}
}
/*************chart圖片保存函式**************/
private void imageSave( Chart chart, string filePath, string fileName)
{
lock (Lock)
{
if (!Directory.Exists(filePath))
Directory.CreateDirectory(filePath);
chart.SaveImage(filePath +"\\" + fileName, ChartImageFormat.Png);
}
}
/*************定時器中更新chart**************/
private void timer1_Tick(object sender, EventArgs e)
{
Chart[] ch = new Chart[8] { chart1, chart2, chart3, chart4, chart5, chart6, chart7, chart8 };
Chart[] cha = new Chart[4] { chart_1, chart_2, chart_3, chart_4 };
string[] str = new string[8] { "chart1", "chart2", "chart3", "chart4", "chart5", "chart6", "chart7", "chart8" };
string[] stri = new string[4] { "chart_1", "chart_2", "chart_3", "chart_4", };
Label[] lb = new Label[4] { label2, label3, label4, label5 };
for (int j = 4; j < 8; j++)
{
Stopwatch sw = new Stopwatch();
var k = j;//引數需要傳入task中,不然j一直是7
Task.Run(() =>
{
sw.Start();
this.Invoke((EventHandler)delegate
{
//chart5.Series[0].Points.Clear();
for (int i = 0; i < dataList[k].Count; i++)
ch[k].Series[0].Points.AddY(dataList[k][i]);//光電開關波形圖-所有點
dataList[k].Clear();
ch[k-4].Series[0].Points.Clear();
for (int i = 0; i < dataQueue[k].Count; i++)
ch[k - 4].Series[0].Points.AddY(dataQueue[k].ElementAt(i));//光電開關波形圖-最近1000個點
for (int i = 0; i < dataList[k-4].Count; i++)
cha[k - 4].Series[0].Points.AddY(dataList[k-4][i]);//激光測距雷達波形圖--所有點
dataList[k-4].Clear();
if (checkBox1.Checked == true)
{
//保存曲線圖片
String imagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "image//" + str[k]);
imageSave(ch[k], imagePath, DateTime.Now.ToString("yyyy_MM_dd_hh_mm_ss_fff") + ".png");
}
sw.Stop();
lb[k - 4].Text = sw.ElapsedMilliseconds.ToString(str[k] + "耗時:" + "0000");//記錄chart繪制的好事呢
});
});
}
}
}
}
運行結果:

專案原始碼下載地址:
鏈接:https://pan.baidu.com/s/1QfoIVNarj-rgK449JM40yQ
提取碼:v2nu
------------------------------------------------------------------------
如果需要查看更多文章,請微信搜索公眾號 csharp編程大全,需要進C#交流群群請加微信z438679770,備注進群, 我邀請你進群! ! !
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/173447.html
標籤:.NET技术
