C#记录(十):串口上位机实例之一

编程入门 行业动态 更新时间:2024-10-12 03:23:44

C#记录(十):串口<a href=https://www.elefans.com/category/jswz/34/1769546.html style=上位机实例之一"/>

C#记录(十):串口上位机实例之一

一、运行效果图

1、开关串口

2、波特率选择

3、串口数据处理(目前对应的是报警器设备,抓取的数据有:红外传感器和CO传感器、以及设备NTC温度值)

4、所有串口接收字串

5、四个Series显示,代表各自的电压值;

6、可以选择显示或者隐藏对应的Series

Chart绘图存在的问题:当显示的数据量很大,达到上万数据时,整个winform窗口变得卡顿。时间允许,会尝试用其他方法,需要源码的见最后链接。

二、程序讲解

1、整个winform程序包含的方法并不多,如下:因并未学习Java或C++等语言,所以整个代码里有很多C语言的影子,风格显得很突兀。

 

2、Chart初始化

        #region Chart初始化public void InitChart(){chart1.BackColor = System.Drawing.Color.White;//设置图表的背景颜色//chart1.Series["Series1"].IsValueShownAsLabel = true;//设置是否在Chart中显示坐标点值//chart1.Series["Series1"].XValueMember = "name";//设置X轴的数据源//chart1.Series["Series1"].YValueMembers = "mobile";//设置Y轴的数据源Series SeriesDark = chart1.Series[0];// 画样条曲线(Spline)SeriesDark.ChartType = SeriesChartType.Spline;// 线宽2个像素SeriesDark.BorderWidth = 2;// 线的颜色:红色SeriesDark.Color = System.Drawing.Color.Black;// 图示上的文字是否可见          SeriesDark.IsVisibleInLegend = true;// 线条名称SeriesDark.Name = "Dark";SeriesDark.Enabled = true;Series SeriesLight = chart1.Series[1];SeriesLight.ChartType = SeriesChartType.Spline;SeriesLight.BorderWidth = 2;SeriesLight.Color = System.Drawing.Color.Red;SeriesLight.IsVisibleInLegend = true;SeriesLight.Name = "Light";SeriesLight.Enabled = true;Series SeriesL_D = chart1.Series[2];SeriesL_D.ChartType = SeriesChartType.Spline;SeriesL_D.BorderWidth = 2;SeriesL_D.Color = System.Drawing.Color.Blue;SeriesL_D.IsVisibleInLegend = true;SeriesL_D.Name = "L_D";SeriesL_D.Enabled = true;Series SeriesCo = chart1.Series[3];SeriesCo.ChartType = SeriesChartType.Spline;SeriesCo.BorderWidth = 2;SeriesCo.Color = System.Drawing.Color.Green;SeriesCo.IsVisibleInLegend = true;SeriesCo.Name = "Co";SeriesCo.Enabled = true;// 设置显示范围ChartArea chartArea = chart1.ChartAreas[0];chartArea.AxisX.Minimum = 0;chartArea.AxisX.Maximum = 100000;chartArea.AxisX.Interval = 1;chartArea.AxisY.Minimum = 0;chartArea.AxisY.Maximum = 5;chartArea.AxisY.Interval = 0.5;//显示网格,虚线,且均设为灰色chartArea.AxisX.Enabled = AxisEnabled.True;                                 //可见chartArea.AxisY.Enabled = AxisEnabled.True;                                 chartArea.AxisX.MajorGrid.LineDashStyle = ChartDashStyle.Dash;              //虚线chartArea.AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dash;chartArea.AxisX.MajorGrid.LineColor = System.Drawing.Color.Silver;          //主网格线为灰色,Major,Minor主次chartArea.AxisY.MajorGrid.LineColor = System.Drawing.Color.Silver;//刻度显示下属性  //chartArea.AxisY.LabelStyle.Format = "{MMM}";//chartArea.AxisY.LabelStyle.Interval = 1;//chartArea.AxisY.LabelStyle.IntervalType = DateTimeIntervalType.Months;//chartArea.AxisY.MajorTickMark.LineColor = System.Drawing.Color.Red;//chartArea.AxisY.MajorTickMark.Enabled = true;//chartArea.AxisY.MajorTickMark.Interval = 1;//chartArea.AxisY.MajorTickMark.IntervalType = DateTimeIntervalType.Days;string[] AxisYLabelName = { "0.5v", "1.0v", "1.5v", "2.0v", "2.5v", "3.0v", "3.5v", "4.0v", "4.5v", "5.0v"};for (int i = 0; i < 10; i++){CustomLabel label = new CustomLabel();label.Text = AxisYLabelName[i];label.ToPosition = i+1;chartArea.AxisY.CustomLabels.Add(label);}//X,Y轴颜色设定//chartArea.AxisX.MajorTickMark.LineColor = System.Drawing.Color.Red;       //X轴颜色//chartArea.AxisY.MajorTickMark.LineColor = System.Drawing.Color.Red;       //X轴颜色//设置图表显示样式, 即X/Y显示比例this.chart1.ChartAreas[0].AxisX.ScaleView.Zoom(1,20);this.chart1.ChartAreas[0].CursorX.IsUserEnabled = true;this.chart1.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;this.chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;//设置滚动条this.chart1.ChartAreas[0].AxisX.ScrollBar.IsPositionedInside = true;                 //将滚动内嵌到坐标轴中this.chart1.ChartAreas[0].AxisX.ScrollBar.Size = 20;                                 //设置滚动条的大小this.chart1.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.All;   //设置滚动条的按钮的风格,下面代码是将所有滚动条上的按钮都显示出来this.chart1.ChartAreas[0].AxisX.ScrollBar.Enabled = true;this.chart1.ChartAreas[0].AxisX.ScaleView.Scroll(ScrollType.LargeDecrement);//chartArea.AxisX.LabelStyle.IsEndLabelVisible = true;                                //show the last label}#endregion

 

3、串口打开操作

        #region 串口打开操作button1private void button1_Click(object sender, EventArgs e){try{if (serialPort1.IsOpen)                                                 //open状态{while (UartBusyFlag){System.Windows.Forms.Application.DoEvents();}serialPort1.Close();mainForm.button1.Text = "打开串口";mainForm.pictureBox1_On_Off.Image = mainForm.pictureBox1_On_Off.InitialImage;//button1.ForeColor = Color.Gray;//DataProcessThread.Abort();//DataMatchThread.Abort();}else{serialPort1.Encoding = System.Text.Encoding.GetEncoding("GB2312");  //此行非常重要 可解决接收中文乱码问题serialPort1.PortName = comboBox1.Text;                              //得到当前COM选择口serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);             //得到当前设置的波特率serialPort1.Open();mainForm.button1.Text = "关闭串口";//button1.ForeColor = Color.Blue;//mainForm.richTextBox1.Text = "";                                    //清空接收区mainForm.pictureBox1_On_Off.Image = mainForm.pictureBox1_On_Off.ErrorImage;if (FirstClikFlag == true){FirstClikFlag = false;DataMatchThread.Start();}}}catch (Exception ex){SerialPort SerialPort1 = new System.IO.Ports.SerialPort();              //与下面语句作用一致string[] ComNum = SerialPort.GetPortNames();comboBox1.Text = ComNum[0];                                             //默认第一个数值值作为串口端口显示,COM1//SerialPort SerialPort1 = new SerialPort();MessageBox.Show(ex.Message);}}#endregion

 

4、串口接收事件处理

        #region 串口接收事件处理private void MySerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e){UartBusyFlag = true;Thread.Sleep(50);
#if SUPPORT_READ_BYTEint DataLength = serialPort1.BytesToRead;                   //接收到buffer的字节数byte[] DataBuf = new byte[DataLength];ReceiveTotalCnt += DataLength;serialPort1.Read(DataBuf, 0, DataLength);sb.Clear();                                                 //清空String LastValue = Encoding.ASCII.GetString(DataBuf);       //将整个数组解码为ASCII数组sb.Append(LastValue);                                       //遍历数组进行字符串转化及拼接
#else//int DataLength = serialPort1.BytesToRead;                   //接收到buffer的字节数//char[] DataBuf = new char[DataLength];//ReceiveTotalCnt += DataLength;//serialPort1.Read(DataBuf, 0, DataLength);//string LastValue = new string(DataBuf);string LastValue = serialPort1.ReadLine();//string LastValue = serialPort1.ReadExisting();
#endifPausedEvent.Reset();try{//因为要访问UI资源,所以需要使用invoke方式同步ui  //在创建this对象的线程上调用匿名委托.//匿名委托的代码就是你看见的那个://delegate {//xxx b//}//这是匿名委托的一种写法,算是C#的语法//Invoke((EventHandler)(delegate { this.richTextBox1.AppendText(sb.ToString()); }));  //invoke函数括号中的参数类型必须是委托//this.richTextBox1.Focus();                                                          //获取焦点//this.richTextBox1.Select(this.richTextBox1.TextLength, 0);                          //光标定位到文本最后//this.richTextBox1.ScrollToCaret();                                                  //滚动到光标处SetRichTextBox(sb.ToString());}catch (Exception ex){//响铃并显示异常给用户System.Media.SystemSounds.Beep.Play();MessageBox.Show(ex.Message);}UartDataBuf += LastValue;//for (int i = 0; i < 5; i++ )//{//    ValueObject[i].DataSourceValue += LastValue;//    if (ValueObject[i].DataSourceValue.Length > 1024)//    {//        ValueObject[i].DataSourceValue = ValueObject[i].DataSourceValue.Remove(0, 1000);//    }//}PausedEvent.Set();UartBusyFlag = false;//Console.WriteLine("{0}", TempValue);}private delegate void SetTextCallback(string text);private void SetRichTextBox(string text){// InvokeRequired需要比较调用线程ID和创建线程ID// 如果它们不相同则返回trueif (mainForm.richTextBox1.InvokeRequired){SetTextCallback d = new SetTextCallback(SetRichTextBox);mainForm.Invoke(d, new object[] { text });}else{mainForm.richTextBox1.AppendText(text);mainForm.richTextBox1.Focus();                                                          //获取焦点mainForm.richTextBox1.Select(this.richTextBox1.TextLength, 0);                          //光标定位到文本最后mainForm.richTextBox1.ScrollToCaret();                                                  //滚动到光标处}}#endregion

 

5、保存串口信息(以当前时间为文件名,保存为txt文档,路径固定为当前exe执行文件路径)

#region 保存串口信息button 2private void button2_Click(object sender, EventArgs e){string PathStrValue = System.Windows.Forms.Application.StartupPath;Console.WriteLine("Path:{0}", PathStrValue);System.DateTime currentTime = new System.DateTime();currentTime = System.DateTime.Now;string DataStrValue = currentTime.Year.ToString() + "-" + currentTime.Month.ToString() + "-" + currentTime.Day.ToString() + "-";DataStrValue += currentTime.Hour.ToString() + "-" + currentTime.Minute.ToString() + "-" + currentTime.Second.ToString();Console.WriteLine("Time:{0}", DataStrValue);PathStrValue = PathStrValue+"\\"+DataStrValue+".txt";Console.WriteLine("Last:{0}", PathStrValue);StreamWriter SW = File.CreateText(PathStrValue);SW.Write(richTextBox1.Text);SW.Flush();SW.Close();}#endregion

6、清除串口信息(效果如下)

        #region 清除串口信息button 3private void button3_Click(object sender, EventArgs e){string ZeroStrChar = "0";string NullStrChar = "null";richTextBox1.Text = "";         //清空接收文本框for(int i = 0; i<5; i++){for (int j = 0; j < 5; j++){ValueObject[i].DataValue[j] = defaultValue[j];}}for (int i = 0; i < 5; i++){mainForm.MyCoTextBoxList[i].Text = ZeroStrChar;}for (int i = 0; i < 5; i++){mainForm.MyDarkTextBoxList[i].Text = ZeroStrChar;}for (int i = 0; i < 5; i++){mainForm.MyLightTextBoxList[i].Text = ZeroStrChar;}for (int i = 0; i < 5; i++){mainForm.MyL_DTextBoxList[i].Text = ZeroStrChar;}for (int i = 0; i < 5; i++){mainForm.MyTempTextBoxList[i].Text = ZeroStrChar;}mainForm.textBox_CO_PPM.Text = ZeroStrChar;mainForm.textBox_MCU_BAT.Text = ZeroStrChar;mainForm.textBox_CO_BAT.Text = ZeroStrChar;mainForm.textBox_Event.Text = NullStrChar;for (int i = 0; i < 4; i++){mainForm.chart1.Series[i].Points.Clear();}CoSum = 0;DarkSum = 0;LightSum = 0;L_DSum = 0;SeriesSum = 0;}#endregion

7、实时动态曲线绘制方法

        #region 实时动态曲线绘制方法private static uint CoSum = 0;private static uint DarkSum = 0;private static uint LightSum = 0;private static uint L_DSum = 0;private static uint SeriesSum = 0;private delegate void DynamicDrawLine(int SeriesIndex, int DrawValue);private static void DynamicDrawLineFunc(int SeriesIndex, int DrawValue){ChartArea chartArea = mainForm.chart1.ChartAreas[0];double DisplayData = DrawValue / 1000.0;if (mainForm.chart1.InvokeRequired){DynamicDrawLine d = new DynamicDrawLine(DynamicDrawLineFunc);mainForm.Invoke(d, new object[] { SeriesIndex, DrawValue });}else{chartArea.AxisX.ScaleView.Size = 50D;switch (SeriesIndex){case 0:CoSum++;Series SeriesCo = mainForm.chart1.Series[3];SeriesCo.Points.AddXY(CoSum, DisplayData);break;case 1:DarkSum++;Series SeriesDark = mainForm.chart1.Series[0];SeriesDark.Points.AddXY(DarkSum, DisplayData);break;case 2:LightSum++;Series SeriesLight = mainForm.chart1.Series[1];SeriesLight.Points.AddXY(LightSum, DisplayData);break;case 3:L_DSum++;Series SeriesL_D = mainForm.chart1.Series[2];SeriesL_D.Points.AddXY(L_DSum, DisplayData);break;default:break;}SeriesSum++;chartArea.AxisX.ScaleView.Position = 0;if ((CoSum % 50 > 0) || (DarkSum % 50 > 0) || (LightSum % 50 > 0) || (L_DSum % 50 > 0)){double max = chartArea.AxisX.Maximum;max = (SeriesSum / 10 + 1) * 10;chartArea.AxisX.Interval = max / 10;chartArea.AxisX.ScaleView.Size = SeriesSum * 1.1;}}}#endregion

8、串口端口号实时获取

        #region 串口端口号实时获取private delegate void SerialPortGet();public void SerialPortGetFunc(){mainForm.serialPort1.PortName = mainFormboBox1.Text;   //得到当前COM选择口mainFormboBox1.Items.Clear();foreach (string portName in SerialPort.GetPortNames()){mainFormboBox1.Items.Add(portName);}}private void comboBox1_MouseClick(object sender, MouseEventArgs e){if (mainForm.serialPort1.IsOpen){}else{if (mainFormboBox1.InvokeRequired){SerialPortGet d = new SerialPortGet(SerialPortGetFunc);mainForm.Invoke(d, new object[] { });}else{SerialPortGetFunc();}}}#endregion

9、选择Series RadioButton (只选择Light, Co可见)

        #region 选择Series RadioButton private void Dark_Series_Button_Click(object sender, EventArgs e){Series SeriesDark = chart1.Series[0];if (SeriesDarkSelectFlag == true){Dark_Series_Button.Checked = false;SeriesDarkSelectFlag = false;SeriesDark.IsVisibleInLegend = false;           //Series 名称是否可见SeriesDark.Enabled = false;}else{Dark_Series_Button.Checked = true;SeriesDarkSelectFlag = true;SeriesDark.IsVisibleInLegend = true;SeriesDark.Enabled = true;}}private void Light_Series_Button_Click(object sender, EventArgs e){Series SeriesLight = chart1.Series[1];if (SeriesLightSelectFlag == true){Light_Series_Button.Checked = false;SeriesLightSelectFlag = false;SeriesLight.IsVisibleInLegend = false;           //Series 名称是否可见SeriesLight.Enabled = false;}else{Light_Series_Button.Checked = true;SeriesLightSelectFlag = true;SeriesLight.IsVisibleInLegend = true;SeriesLight.Enabled = true;}}private void L_D_Series_Button_Click(object sender, EventArgs e){Series SeriesL_D = chart1.Series[2];if (SeriesL_DSelectFlag == true){L_D_Series_Button.Checked = false;SeriesL_DSelectFlag = false;SeriesL_D.IsVisibleInLegend = false;           //Series 名称是否可见SeriesL_D.Enabled = false;}else{L_D_Series_Button.Checked = true;SeriesL_DSelectFlag = true;SeriesL_D.IsVisibleInLegend = true;SeriesL_D.Enabled = true;}}private void Co_Series_Button_Click(object sender, EventArgs e){Series SeriesCo = chart1.Series[3];if (SeriesCoSelectFlag == true){Co_Series_Button.Checked = false;SeriesCoSelectFlag = false;SeriesCo.IsVisibleInLegend = false;           //Series 名称是否可见SeriesCo.Enabled = false;}else{Co_Series_Button.Checked = true;SeriesCoSelectFlag = true;SeriesCo.IsVisibleInLegend = true;SeriesCo.Enabled = true;}}#endregion

10、窗体的关闭事件处理函数、chart鼠标滚动事 、显示帮助信息 button 4

        #region 窗体的关闭事件处理函数,在该事件中将之前创建的线程全部终止private void Form1_FormClosing(object sender, FormClosingEventArgs e){if (serialPort1.IsOpen)                                                 //open状态{while (UartBusyFlag){System.Windows.Forms.Application.DoEvents();}serialPort1.Close();}DataMatchThread.Abort();if (MyThreadList.Count > 0){//编列自定义队列,将所有线程终止foreach (Thread tWorkingThread in MyThreadList){tWorkingThread.Abort();}}}#endregion#region chart鼠标滚动事private void chart1_MouseEnter(object sender, MouseEventArgs e){ChartArea chartArea = mainForm.chart1.ChartAreas[0];if (e.Delta > 0)//鼠标向上{if (chartArea.AxisX.ScaleView.Size < 5000)//判断显示的最大数值chartArea.AxisX.ScaleView.Size += 5;//+=5---滚动一次显示5个}else//鼠标向下滚动{if (chartArea.AxisX.ScaleView.Size > 50)chartArea.AxisX.ScaleView.Size -= 5;// - = 5---滚动一次减小显示5个}}private void chart1_MouseEnter(object sender, EventArgs e){MouseWheel += new MouseEventHandler(chart1_MouseEnter);         //调用滚轮事件}#endregion#region 显示帮助信息 button 4private void button4_Click(object sender, EventArgs e){//DialogResult MsgBoxResult;//设置对话框的返回值//MsgBoxResult = MessageBox.Show("请选择你要按下的按钮",//对话框的显示内容//"提示",//对话框的标题//MessageBoxButtons.YesNo,//定义对话框的按钮,这里定义了YSE和NO两个按钮//MessageBoxIcon.Exclamation,//定义对话框内的图表式样,这里是一个黄色三角型内加一个感叹号//MessageBoxDefaultButton.Button2);//定义对话框的按钮式样//if (MsgBoxResult == DialogResult.Yes)//如果对话框的返回值是YES(按"Y"按钮)//{//    this.label1.ForeColor = System.Drawing.Color.Red;//字体颜色设定//    label1.Text = " 你选择了按下”Yes“的按钮!";//}//if (MsgBoxResult == DialogResult.No)//如果对话框的返回值是NO(按"N"按钮)//{//    this.label1.ForeColor = System.Drawing.Color.Blue;//字体颜色设定//    label1.Text = " 你选择了按下”No“的按钮!";//}DialogResult MsgBoxResult;//设置对话框的返回值MsgBoxResult = MessageBox.Show("采样电压,精度最大mV\nCO:      [Co=xmV] 或 [Co=x.xV]\nDark:   [Dark=xmV] 或 [Dark=x.xV]\nLight:  [Light=xmV] 或 [Light=x.xV]\nL_D:     [L_D=xmV] 或   [L_D=x.xV]\nT:         [T=xx^C] \n电池和事件\nppm:    [CO:xxxppm]\nMCU_Bat:  [MCU_Bat:xmV] 或 [MCU_Bat:x.xV]\nCO_Bat:     [CO_Bat:xmV] 或 [CO_Bat:x.xV]\nEvent:     [Event:xxxx\\n]",//对话框的显示内容"帮助(输出格式)",//对话框的标题MessageBoxButtons.OK,//定义对话框的按钮,这里定义了YSE和NO两个按钮MessageBoxIcon.Information,//定义对话框内的图表式样,这里是一个黄色三角型内加一个感叹号MessageBoxDefaultButton.Button1);//定义对话框的按钮式样}#endregion

 

更多推荐

C#记录(十):串口上位机实例之一

本文发布于:2024-03-23 20:13:51,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1742350.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:上位   串口   实例

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!