C#实现简易的串⼝监视上位机功能附源码下载
实现上位机和下位机之间的通信,通常使⽤的是串⼝通信,接下来实现⼀个通过上位机和串⼝调试助⼿来完成串⼝通信测试。
在创建好的⼯程下⾯,通过⼯具箱中已有的控件完成界⾯的搭建,如下图所⽰,为了⽅便初学者容易看懂程序,下图将控件的命名⼀并标注出来:
直接进⼊正题,将完整的⼯程代码黏贴出来:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Diagnostics;
namespace Tem_Hum_Monitorring
{
public partial class Form1 : Form
{
//实例化串⼝
SerialPort s =new SerialPort();
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls =false;
button1.Text ="打开串⼝";
int[] item ={9600,115200};//遍历
foreach(int a in item)
{
comboBox2.Items.Add(a.ToString());
}
comboBox2.SelectedItem = comboBox2.Items[1];
}
private void Form1_Load(object sender, EventArgs e)
{
portInit();
}
/
// <summary>
/// 串⼝初始化
/// </summary>
private void portInit()
{
writeline方法的作用string[] ports = SerialPort.GetPortNames();
comboBox1.Items.AddRange(ports);
comboBox1.SelectedItem = comboBox1.Items[0];
}
#region开关串⼝
private void button1_Click(object sender, EventArgs e)
{
try
{
if(!s.IsOpen)
{
s.PortName = comboBox1.SelectedItem.ToString();
s.BaudRate = Convert.ToInt32(comboBox2.SelectedItem.ToString());
s.Open();
s.DataReceived += s_DataReceived;//"+="代表指定响应事件时要调⽤的⽅法
button1.Text ="关闭串⼝";
}
else
{
s.Close();
s.DataReceived -= s_DataReceived;
button1.Text ="打开串⼝";
}
}
catch(Exception ee)
{
MessageBox.Show(ee.ToString());
}
}
#endregion
#region串⼝接收
void s_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int count = s.BytesToRead;
string str =null;
if(count ==8)
{
//数据解析
byte[] buff =new byte[count];
s.Read(buff,0, count);
foreach(byte item in buff)
{
str += item.ToString("X2")+" ";
}
richTextBox1.Text ="["+ System.DateTime.Now.ToString()+"] "+ str +"\n"+ richTextBox1.Text; if(buff[0]==0x04)
{
ID.Text = buff[0].ToString();
switch(buff[2])
{
case0x01:
{
Tem.Text =(buff[5]*4+ buff[4]*0.05-30).ToString();
Hum.Text =(buff[6]+ buff[7]).ToString();
break;
}
case0x02:
Light.Text =(buff[6]+ buff[7]).ToString();
break;
}
case0x04:
{
Dust.Text =(buff[6]+ buff[7]).ToString();
break;
}
default:
break;
}
}
}
else
{
//当接收数据不在设定的数据位范围之内时,会出现接受到的数据⼀直保存在接收缓存区之内,后续每次接⼿数据都会将上⼀次的数据进⾏叠加,造成只能通过关闭串⼝的⽅法来清除缓冲区的数据
s.DiscardInBuffer();//丢弃来⾃串⾏驱动程序的接收缓冲区的数据
}
}
#endregion
#region串⼝发送
private void button3_Click(object sender, EventArgs e)
{
string[] sendbuff = richTextBox2.Text.Split();
Debug.WriteLine("发送字节数:"+ sendbuff.Length);
foreach(string item in sendbuff)
{
int count =1;
byte[] buff =new byte[count];
buff[0]=byte.Parse(item, System.Globalization.NumberStyles.HexNumber);
s.Write(buff,0,count);
}
}
#endregion
private void button2_Click(object sender, EventArgs e)
{
int count =1;
byte[] buff =new byte[count];
buff[0]=byte.Parse("04", System.Globalization.NumberStyles.HexNumber);
s.Write(buff,0, count);
}
}
}
在Winfrom窗体设计中,实现串⼝可以通过⼯具箱中的串⼝控件来实现,不过⼀般推荐直接通过代码来实例化串⼝,实例化串⼝需使⽤如下代码来实现:
//实例化串⼝
   SerialPort s =new SerialPort();
串⼝初始化可以在窗体的Load函数中实现,以下初始化可以⾃动化取当前设备中的存在的串⼝,包括真实串⼝和虚拟串⼝:
private void Form1_Load(object sender, EventArgs e)
{
portInit();
}
/// <summary>
/// 串⼝初始化
/// </summary>
private void portInit()
{
string[] ports = SerialPort.GetPortNames();
comboBox1.Items.AddRange(ports);
comboBox1.SelectedItem = comboBox1.Items[0];
}
通过对开关按键button1控件的点击事件,实现串⼝的开关,通过对控件的⽂字修改,可以实现⼀个控件机能实现开⼜能实现关串⼝的作⽤:
#region开关串⼝
private void button1_Click(object sender, EventArgs e)
{
try
{
if(!s.IsOpen)
{
s.PortName = comboBox1.SelectedItem.ToString();
s.BaudRate = Convert.ToInt32(comboBox2.SelectedItem.ToString());
s.Open();
s.DataReceived += s_DataReceived;//"+="代表指定响应事件时要调⽤的⽅法
button1.Text ="关闭串⼝";
}
else
{
s.Close();
s.DataReceived -= s_DataReceived;
button1.Text ="打开串⼝";
}
}
catch(Exception ee)
{
MessageBox.Show(ee.ToString());
}
}
#endregion
串⼝数据接收和数据解析,⾸先获取数据接收缓存区数据的字节长度,通过确认长度是否是设定中的长度⼤⼩,如果是设定的8位数据长度则对接收的数据进⾏解析:
#region串⼝接收
void s_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int count = s.BytesToRead;
string str =null;
if(count ==8)
{
//数据解析
byte[] buff =new byte[count];
s.Read(buff,0, count);
foreach(byte item in buff)
{
str += item.ToString("X2")+" ";
}
richTextBox1.Text ="["+ System.DateTime.Now.ToString()+"] "+ str +"\n"+ richTextBox1.Text;
if(buff[0]==0x04)
{
ID.Text = buff[0].ToString();
switch(buff[2])
{
case0x01:
{
Tem.Text =(buff[5]*4+ buff[4]*0.05-30).ToString();
Hum.Text =(buff[6]+ buff[7]).ToString();
break;
}
case0x02:
{
Light.Text =(buff[6]+ buff[7]).ToString();
break;
}
case0x04:
{
Dust.Text =(buff[6]+ buff[7]).ToString();
break;
}
default:
break;
}
}
}
else
{
//当接收数据不在设定的数据位范围之内时,会出现接受到的数据⼀直保存在接收缓存区之内,后续每次接⼿数据都会将上⼀次的数据进⾏叠加,造成只能通过关闭串⼝的⽅法来清除缓冲区的数据
s.DiscardInBuffer();//丢弃来⾃串⾏驱动程序的接收缓冲区的数据
}
}
#endregion
当接收到的数据长度不等于8的时候,将丢弃来⾃串⾏驱动程序的接收缓冲区的数据,接下来通过断点调试来分析丢弃缓冲区和不丢弃缓冲区数据两种情况进⾏仿真,分析如下⼏点。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。