C# 简易的串口监视上位机实现
实现上位机和下位机之间的通信,通常使用的是串口通信,接下来实现一个通过上位机和串口调试助手来完成串口通信测试。
首先创建一个WInfrom窗体应用工程文件,创建过程可参考https://www.cnblogs.com/xionglaichuangyichuang/p/13734179.html;
在创建好的工程下面,通过工具箱中已有的控件完成界面的搭建,如下图所示,为了方便初学者容易看懂程序,下图将控件的命名一并标注出来:
直接进入正题,将完整的工程代码黏贴出来:


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.Windows.Forms;
10 using System.IO.Ports;
11 using System.Diagnostics;
12
13 namespace Tem_Hum_Monitorring
14 {
15
16 public partial class Form1 : Form
17 {
18 //实例化串口
19 SerialPort s = new SerialPort();
20
21 public Form1()
22 {
23 InitializeComponent();
24 Control.CheckForIllegalCrossThreadCalls = false;
25 button1.Text = "打开串口";
26 int[] item = { 9600,115200}; //遍历
27 foreach (int a in item)
28 {
29 comboBox2.Items.Add(a.ToString());
30 }
31 comboBox2.SelectedItem = comboBox2.Items[1];
32 }
33
34 private void Form1_Load(object sender, EventArgs e)
35 {
36 portInit();
37 }
38
39 /// <summary>
40 /// 串口初始化
41 /// </summary>
42 private void portInit()
43 {
44 string[] ports = SerialPort.GetPortNames();
45 comboBox1.Items.AddRange(ports);
46 comboBox1.SelectedItem = comboBox1.Items[0];
47 }
48
49 #region 开关串口
50 private void button1_Click(object sender, EventArgs e)
51 {
52 try
53 {
54 if (!s.IsOpen)
55 {
56 s.PortName = comboBox1.SelectedItem.ToString();
57 s.BaudRate = Convert.ToInt32(comboBox2.SelectedItem.ToString());
58 s.Open();
59 s.DataReceived += s_DataReceived; //"+="代表指定响应事件时要调用的方法
60 button1.Text = "关闭串口";
61 }
62 else
63 {
64 s.Close();
65 s.DataReceived -= s_DataReceived;
66 button1.Text = "打开串口";
67 }
68 }
69 catch(Exception ee)
70 {
71 MessageBox.Show(ee.ToString());
72 }
73 }
74 #endregion
75
76 #region 串口接收
77 void s_DataReceived(object sender, SerialDataReceivedEventArgs e)
78 {
79 int count = s.BytesToRead;
80 string str = null;
81 if (count == 8)
82 {
83 //数据解析
84 byte[] buff = new byte[count];
85 s.Read(buff, 0, count);
86 foreach (byte item in buff)
87 {
88 str += item.ToString("X2") + " ";
89 }
90 richTextBox1.Text = "[" + System.DateTime.Now.ToString() + "] " + str + "\n" + richTextBox1.Text;
91 if (buff[0] == 0x04)
92 {
93 ID.Text = buff[0].ToString();
94 switch (buff[2])
95 {
96 case 0x01:
97 {
98 Tem.Text = (buff[5] * 4 + buff[4] * 0.05 - 30).ToString();
99 Hum.Text = (buff[6] + buff[7]).ToString();
100 break;
101 }
102 case 0x02:
103 {
104 Light.Text = (buff[6] + buff[7]).ToString();
105 break;
106 }
107 case 0x04:
108 {
109 Dust.Text = (buff[6] + buff[7]).ToString();
110 break;
111 }
112 default:
113 break;
114 }
115 }
116 }
117 else
118 {
119 //当接收数据不在设定的数据位范围之内时,会出现接受到的数据一直保存在接收缓存区之内,后续每次接手数据都会将上一次的数据进行叠加,造成只能通过关闭串口的方法来清除缓冲区的数据
120 s.DiscardInBuffer(); //丢弃来自串行驱动程序的接收缓冲区的数据
121 }
122 }
123 #endregion
124
125 #region 串口发送
126 private void button3_Click(object sender, EventArgs e)
127 {
128 string[] sendbuff = richTextBox2.Text.Split();
129 Debug.WriteLine("发送字节数:" + sendbuff.Length);
130 foreach (string item in sendbuff)
131 {
132 int count = 1;
133 byte[] buff = new byte[count];
134 buff[0] = byte.Parse(item, System.Globalization.NumberStyles.HexNumber);
135 s.Write(buff,0,count);
136 }
137 }
138 #endregion
139
140 private void button2_Click(object sender, EventArgs e)
141 {
142 int count = 1;
143 byte[] buff = new byte[count];
144 buff[0] = byte.Parse("04", System.Globalization.NumberStyles.HexNumber);
145 s.Write(buff, 0, count);
146 }
147 }
148 }
在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])
{
case 0x01:
{
Tem.Text = (buff[5] * 4 + buff[4] * 0.05 - 30).ToString();
Hum.Text = (buff[6] + buff[7]).ToString();
break;
}
case 0x02:
{
Light.Text = (buff[6] + buff[7]).ToString();
break;
}
case 0x04:
{
Dust.Text = (buff[6] + buff[7]).ToString();
break;
}
default:
break;
}
}
}
else
{
//当接收数据不在设定的数据位范围之内时,会出现接受到的数据一直保存在接收缓存区之内,后续每次接手数据都会将上一次的数据进行叠加,造成只能通过关闭串口的方法来清除缓冲区的数据
s.DiscardInBuffer(); //丢弃来自串行驱动程序的接收缓冲区的数据
}
}
#endregion
当接收到的数据长度不等于8的时候,将丢弃来自串行驱动程序的接收缓冲区的数据,接下来通过断点调试来分析丢弃缓冲区和不丢弃缓冲区数据两种情况进行仿真,分析如下几点。
- 使用串口助手给上位机发送数据数据位长度为8位的数据,串口调试助手和上位机的终端的显示界面如下,发送端数据和接收端数据一样,并未出现异常:
- 将串口调试助手发送数据位修改成9位之后,进行发送,可以发现上位机并未接收到相关的数据:
- 接着修改串口调试助手的发送数据位,修改成8位,可以发现上位机尚未能接收到来自串口调试助手发来的数据,这是为什么呢?
- 接下来将通过断点逐步进行调试,来解释是为啥上位机没有接收到调试助手发来的数据,当串口调试助手发来的数据长度位9位时,通过监视器可以查看到接收缓冲器中的数据长度长度是9
- 第一次点击完发送之后,上位机未能成功接收到数据,我们就会好奇,并且一般都会点击第二次、第三次、甚至一直点下去,观察是否会出现啥异常现象,当点击第二次时,通过监视窗口,可以观察到到串口缓冲区的数据长度变成了18,这是因为缓冲区将上一次接收的数据给保留了下来并没有删除,就算下次发送的数据长度为8位的时候,也一样是通过叠加的方式将其保存到缓冲区,这样就会造成缓冲区的数据位长度会一直大于8;如果不通过 s.DiscardInBuffer()方法丢弃来自串行驱动程序的接收缓冲区的数据,就只能通过关闭串口然后重新打开相应的串口来实现缓冲区的数据清除。
- 使用s.DiscardInBuffer()对不符合长度的数据进行丢弃,实现的效果如下所示:
需要完整源码的朋友可以通过以下链接进行下载,如有大佬有更好的优化意见欢迎一块进行讨论,谢谢!
链接:https://pan.baidu.com/s/1Yb1YjdAZfficRtx2srBpzw
提取码:7yc2
C# 简易的串口监视上位机实现的更多相关文章
- 开源串口 Ymodem 上位机软件
概述 上位机使用Qt开发,计划整合多个工具为一体,用作以后的调试工具. 当前完成功能: 1.串口调试 支持hex和ascii 码发送,接受. 支持自动添加回车换行. 支持定时发送,最短间隔100ms, ...
- VC++编写简单串口上位机程序
VC++编写简单串口上位机程序 转载: http://blog.sina.com.cn/s/articlelist_1809084904_0_1.html VC++编写简单串口上位机程序 串口通信 ...
- 基于Arduino和python的串口通信和上位机控制
引言 经常的时候我们要实现两个代码之间的通信,比如说两个不同不同人写的代码要对接,例如将python指令控制Arduino控件的开关,此处使用串口通信是非常方便的,下面笔者将结合自己踩过的坑来讲述下自 ...
- 快速设计一个简单的WPF串口上位机
最近一直在学习UWP,其中有的技术参考了WPF,所以又回头再来学习WPF,感觉学的东西很杂,必须记录一下,不然时间长了还得忘掉,于是申请开始写博客,将学习的心得记录一下,以备后用.这次是因为公司内训, ...
- C#上位机串口控制12864显示
实现的效果 上面是用Proteus仿真的,,对了如果自己想用proteus仿真需要安装下面这个软件 再看一下实物显示效果 先做上位机部分........... 为了程序一启动就把电脑上能用的串口号显示 ...
- c#上位机与三菱PLC(FX3U)串口通讯
项目中会经常用到上位机与PLC之间的串口通信,本文介绍一下C#如何编写上位机代码 与三菱FX3U进行通讯 1. 第一种方法是自己写代码实现,主要代码如下: //对PLC的Y7进行置1 byte[] Y ...
- [python] 3 、基于串口通信的嵌入式设备上位机自动测试程序框架(简陋框架)
星期一, 20. 八月 2018 01:53上午 - beautifulzzzz 1.前言 做类似zigbee.ble mesh...无线网络节点性能测试的时候,手动操作然后看表象往往很难找出真正的原 ...
- LabVIEW上位机与串口通信
渊源 大一的时候,学校开了门公共选修课,叫LabVIEW编程,当时的我当然还不知道LabVIEW是啥东东,但还是选了.上课的老师是机械学院的一个副教授.他给我们展示了好几个用LabVIEW做的项目.譬 ...
- C#做一个简单的进行串口通信的上位机
C#做一个简单的进行串口通信的上位机 1.上位机与下位机 上位机相当于一个软件系统,可以用于接收数据.控制数据.即可以对接收到的数据直接发送操控命令来操作数据.上位机可以接收下位机的信号.下位机是 ...
随机推荐
- spring boot:使用poi导出excel电子表格文件(spring boot 2.3.1)
一,什么是poi? 1,poi poi是用来兼容微软文档格式的java api, 它是apache的顶级项目之一, 也是我们在生产环境中导出excel时使用最多的库 2,poi官方网站: http:/ ...
- phpstorm配置sftp自动上传
勾选自动上传 手动上传 qq_23049573 原创文章 14获赞 4访问量 2万+ 关注 私信
- Postgres 10.11安装教程
Postgres搭建 考虑到Drone和Sonarqube等都需要借助Postgres存储,为了保证CI服务的高效的工作,将考虑独立其中依赖的数据库,避免在繁忙时占用过多资源从而影响整体CI的速度. ...
- JavaSE学习笔记02运算符、帮助文档生成与Scanner输入
1. 运算符 1. 算术运算符:+,-,*,/,%,++,-- //二元运算符 int a = 10; int b = 20; int c = 25; int d = 25; System.out.p ...
- plsql查询中文乱码
1.查看数据库字符集 select userenv('language') from dual 查看数据库字符集 2.在环境变量中添加并设置变量 变量名:NLS_LANG: 变量值:第一步查询的数据库 ...
- 在centOS上安装oracle出现java.lang.NoClassDefFoundError问题及解决方法
问题一:CentOS6.5 静默安装Oracle 11G过程中提示:Exception in thread "main" java.lang.NoClassDefFoundErro ...
- pytest-pyppeteer:在pytest中运行pyppeteer
pytest-pyppeteer pytest-pyppeteer是我写的一个 pytest 插件,支持在 pytest 中运行pyppeteer,起因是为了解决工作中的一个测试需求,现在将其开源并做 ...
- Jupyter Notebook使用教程
关于安装我就不说了,可以参考知乎https://zhuanlan.zhihu.com/p/33105153(总结的很全面) 首先打开Jupyter Notebook后,新建notebook:点击右上角 ...
- VMware Workstation Pro 虚拟机安装CentOS-7
一.下载CentOS-7镜像 我是通过阿里开源镜像站下载的, 下载url:https://mirrors.aliyun.com/centos/7/isos/x86_64/ 下载CentOS-7-x86 ...
- 数据结构(C++)——链表
顺序表和链表的比较 1.存取方式 顺序表可以随机访问,而链表只能从表头顺序查找.(因此经常查找顺序表某一个元素时,顺序表更适合) 2.逻辑结构与物理结构 顺序表中,逻辑上相邻的元素,其物理存储位置也相 ...