实现上位机和下位机之间的通信,通常使用的是串口通信,接下来实现一个通过上位机和串口调试助手来完成串口通信测试。

首先创建一个WInfrom窗体应用工程文件,创建过程可参考 https://www.jb51.net/article/150973.htm

在创建好的工程下面,通过工具箱中已有的控件完成界面的搭建,如下图所示,为了方便初学者容易看懂程序,下图将控件的命名一并标注出来:

直接进入正题,将完整的工程代码黏贴出来:

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(){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]){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#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);}}#endregionprivate 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]){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()对不符合长度的数据进行丢弃,实现的vb.net教程效果如下所示:

需要完整源码的朋友可以通过以下链接进行下载,如有大佬有更好的优化意见欢迎一块进行讨论,谢谢!

链接: https://pan.baidu.com/s/1MXVIFQHHsEmx4p28Pz-wcQ 提取码: ibu9
到此这篇关于C# 实现简易的串口监视上位机功能的文章就介绍到这了

C# 实现简易的串口监视上位机功能附源码下载相关推荐

  1. stm32之iap实现应用(基于串口,上位机,详细源码)

    开发环境:Window 7 开发工具:Keil uVision4 硬件:stm32f103c8t6 篇幅略长,前面文字很多,主要是希望能让小白们理解,后面就是实现步骤,包括实现的代码. 在研发调试的时 ...

  2. DWM1000 定位上位机软件 以及 源码下载

    蓝点DWM1000 模块已经打样测试完毕,有兴趣的可以申请购买了,更多信息参见 蓝点论坛 正文: 经过一段学习,今天终于将定位软件编译成功,简单修改,可以正确读取串口的数据了. 主要修改点: 1 官方 ...

  3. 三菱FX系列源码,C#上位机FX系列源码,串口485.232通讯

    三菱FX系列源码,C#上位机FX系列源码,串口485.232通讯,可读X/Y/M/S/D,可写Y/M/S/D,FX系列,有备注. 新增仿真FX3U仿真器和上位机通信,全程不需要实物. 拿回去可编辑,源 ...

  4. 激光雕刻机图片解析C#上位机stm32f407控制板源码

    激光雕刻机图片解析C#上位机stm32f407控制板源码 视频中机器运行慢是因为测试激光头功率小,跑快了光斑在像素点烧蚀时间短打不出痕迹,需要速度快把激光头功率加大即可 支持多种常用图片格式的转换例如 ...

  5. STM32 I2C总线从机发送接收源码下载,有图有真相!

    功能: 1.接收主机发送的数据并储存在内部缓冲区,然后通过串口打印输出: 2.主机读取数据时,将内部缓冲区中的数据返回: 3.发送接收都采用中断方式实现,经验证基本上没什么问题: 串口打印输出的数据: ...

  6. 两款简易计算器纯js版附源码下载

    效果如图: 还有一款更简易的 下载地址: csdn下载需要c币,没有c币可从微信公众号[无心有云] 发送[js版计算器],可获取百度云地址下载

  7. Android串口编程--开关灯Demo(附源码)

    1.项目简述 第二次玩硬件了,第一次是通过局域网控制门的开关,这次是通过ZB(大概就是这么叫,具体名字不清楚)控制灯的开关,感觉控制硬件也就是给硬件发个byte数组而已. 这里有个框架usb-seri ...

  8. Android串口通信实例分析【附源码】

    Android 串口通信实例分析,用的时开源的android-serialport-api 这个是用android ndk实现的串口通信,我把他做了一个简化,适合于一般的程序的串口通信移植,欢迎拍砖- ...

  9. 基于matlab的串口通信,基于Matlab GUI的单片机串口与PC的通信 附源码

    我也是最近学习单片机和MATLAB的小白平时在看学习的时候 下载了一些有价值的参考文献 概述采用51单片机,atmel的STC89C52RC芯片,主要用到的是七段数码管用来做一个时钟,程序编写软件为k ...

  10. 再来一个小游戏——原生js逐句解释开发简易版别踩白块,附源码

    芜湖!没想到上个做扫雷的阅读量这么高(激动) 先捞一下:做个小项目~纯原生JS手把手逐句解释写一个扫雷小游戏(附源码) 快看↑ 这次就做一个别踩白块吧哈哈哈哈哈 最终版演示地址:钢琴块 源码在最后!最 ...

最新文章

  1. 公众号接口,memcached缓存
  2. 牛客练习赛44 A 小y的序列 (模拟,细节)
  3. 纪中2019(上)游记+总结
  4. php 开启命令模式,如何启用PhpStorm中的命令行工具
  5. STM32-GPIO篇
  6. WebAPI——自动生成帮助文档
  7. iframe页面里的链接在ios设备无法点击的解决办法
  8. pythonATM,购物车项目实战4-settings配置设置
  9. Message Queue基本使用说明
  10. python教学反思_Python语言教学反思
  11. 10个免费的在线Markdown编辑器
  12. 正则表达式(二)验证邮箱、电话号码
  13. nodejs和php性能,Nodejs 和PHP 性能测试结果
  14. 作业1:从产品经理人的角度规划项目
  15. Eviews中实现ARIMA模型并进行预测
  16. ASP.NET Core : 八.图说管道,唐僧扫塔的故事
  17. android epub 开源,EPUB SDK
  18. 读写Excel工具类ExcelUtil
  19. 优课联盟 实境英语 Test for Unit 5
  20. 医学图像处理和深度学习入门

热门文章

  1. 史上最全的OpenCV入门教程
  2. PRML Chapter01 练习题Exercise
  3. 蓝电电池测试系统工步编辑软件,蓝电电池测试系统中标结果
  4. 分子动力学模拟算法框架
  5. 万能显卡驱动win7_驱动工具更新!完美支持苹果电脑驱动
  6. java 入门面试题
  7. linux镜像下载和vmware虚拟主机部署
  8. 效率提升总结-Unity 项目规范文档 【建议收藏】
  9. 三维重建之环境搭建1-VS2017安装
  10. android vulkan 游戏,王者荣耀Vulkan版