基于事件触发方式的串行通信接口数据接收案例

广东职业技术学院  欧浩源

1、案例背景

之前写过一篇《基于多线程方式的串行通信接口数据接收案例》的博文,讨论了采用轮询方式接收串口数据的情况。经过使用了多线程来处理,而然轮询的办法比较还是比较笨拙的。我们在实际的项目开发中,更加常用的是基于事件触发的方式,这个方式不但好用,而且灵活,只是使用起来需要更多的一点专业知识。在本博文中,就“传感器模块每隔1秒钟向上位机传送4字节的电压数据帧”的项目,对该方法的设计进行详细的讲述。

  数据帧的格式:帧头(0xAF)    电压数据高8位    电压数据低8位    帧尾(0xFA)

2、事件触发方式的工作原理

在SerialPort类中有一个DataReceived事件,当串口接收到了ReceivedBytesThreshold属性设置的字符个数或者接收到了文件结束符并将其放入了串口接收缓冲区时,就会触发DataReceived事件。

ReceivedBytesThreshold属性决定了串口读缓存中数据达到多少字节时才触发DataReceived事件,其默认值为1。如果串口接收的是固定长度的数据,则将ReceivedBytesThreshold属性设置为接收数据的长度;如果接收数据的结尾是固定的字符或字符串,则可以采用ReadTo方法或在DataReceived事件中判断接收的字符是否满足条件。

由于DataReceived事件在辅线程中被触发,不能与主线程中的数据显示控件直接进行数据传输,必须使用间接方式来实现。当收到完整的一条数据时,返回主线程处理或在主窗体上显示时,要使用跨线程的处理方式,在C#中可以采用控件异步委托的方法BeginInvoke或者控件同步委托的方法Invoke。

3、引入命令空间

使用多线程的方式,需要引入命名空间:System.Threading;

使用串行通信接口,需要引入命名空间:System.IO.Ports;

4、初始化工作

给主窗体添加窗体装载事件(即Load事件),在该事件中对各个控件的属性进行初始化工作。

重点:在这里要给DataReceived事件添加一个委托,将事件与数据接收处理方法DataReceivedHandler关联起来。

  com.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

        SerialPort com = new SerialPort();                  //实例化一个串口对象
private void Form2_Load(object sender, EventArgs e)
{
string[] ports = { "COM1", "COM2", "COM3", "COM4", "COM5" };
foreach (string str in ports)
{
comboBox1.Items.Add(str);
}
comboBox1.SelectedIndex = ; string[] baudrate = { "", "", "", "", "", "" };
foreach (string str in baudrate)
{
comboBox2.Items.Add(str);
}
comboBox2.SelectedIndex = ; comboBox3.Items.Add("");
comboBox3.Items.Add("");
comboBox3.Items.Add("");
comboBox3.SelectedIndex = ; comboBox4.Items.Add("");
comboBox4.Items.Add("1.5");
comboBox4.Items.Add("");
comboBox4.SelectedIndex = ; comboBox5.Items.Add("None");
comboBox5.SelectedIndex = ; com.ReceivedBytesThreshold = ; //设置串口接收到4个字节数据才触发DataReceived事件
//为串口DataReceived事件添加处理方法
com.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}

5、数据接收处理方法DataReceivedHandler

当串口接收到ReceivedBytesThreshold属性设置的字节数时,就会触发DataReceived事件,从而执行DataReceivedHandler方法。在该方法里进行对串口接收数据的分析处理等工作。如果需要在这个方法里面将接收到的数据或者对数据的处理结果显示到窗体的控件上,那么就需要进行跨线程的处理了。

注意:在本方法中采用了BeginInvoke方法来处理跨线程的问题,在这个过程中,涉及到Action委托和Lambda表达式的知识点是很常用的,但在这里就不展开叙述了,大家可以百度查找学习。

        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
string strRcv = "";
int count = com.BytesToRead; //获取串口缓冲器的字节数
byte[] readBuffer = new byte[count]; //实例化接收串口数据的数组
com.Read(readBuffer, , count); //从串口缓冲区读出数据到数组 for (int i = ; i < readBuffer.Length; i++)
{
strRcv += readBuffer[i].ToString("X2") + " "; //16进制显示
}
this.BeginInvoke(new Action(() =>
{
textBox1.AppendText(strRcv);
})); if (readBuffer[] == 0xAF && readBuffer[] == 0xFA) //判断数据的帧头和帧尾
{
Int32 ad = readBuffer[];
double advalue;
ad <<= ;
ad |= readBuffer[]; //从数据帧中将电压数据取出
advalue = ad;
advalue = (advalue * 3.3) / ; //将数据换算为实际的电压值
this.BeginInvoke(new Action(() =>
{
label2.Text = advalue.ToString("F2") + " V";
}));
}
}

6、打开串口

在进行串口通信的时候,一般的流程是:先设置通信的端口号、波特率、数据位、停止位和校验位,然后打开串口,接着发送数据和接收数据,最后要关闭串口。

        private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "打开串口")
{
com.PortName = comboBox1.Text; //选择串口号
com.BaudRate = int.Parse(comboBox2.Text); //选择波特率
com.DataBits = int.Parse(comboBox3.Text); //选择数据位数
com.StopBits = (StopBits)int.Parse(comboBox4.Text); //选择停止位数
com.Parity = Parity.None; //选择是否奇偶校验 try
{
if (com.IsOpen) //判断该串口是否已打开
{
com.Close();
com.Open();
}
else
{
com.Open();
} }
catch (Exception ex)
{
MessageBox.ReferenceEquals("错误:" + ex.Message, "串口通信");
}
button1.Text = "关闭串口";
}
else if (button1.Text == "关闭串口")
{
com.Close(); //关闭串口 button1.Text = "打开串口";
}
}

7、运行结果

8、结语

关于串口数据的接收读取无非就两种方法:一是通过轮询方式实时读取串口,而是通过事件触发实现串口读取。尽管可以使用多线程处理,但是轮询方式读取串口的效率并不十分高效,因此,本人觉得还是采用事件触发方式比较好。或许有人问,为什么只写串口读取数据,不讲串口发送数据呢?嗯.......没错,串口的数据读取和数据发送是同样重要的,但是数据读取的处理比数据发送要复杂很多,我想,如果能把串口的数据读取搞明白了,那串口数据发送还成问题吗?

【ALB学习笔记】基于事件触发方式的串行通信接口数据接收案例的更多相关文章

  1. 【ALB学习笔记】基于多线程方式的串行通信接口数据接收案例

    基于多线程方式的串行通信接口数据接收案例 广东职业技术技术学院  欧浩源 1.案例背景 在本博客的<[CC2530入门教程-06]CC2530的ADC工作原理与应用>中实现了电压数据采集的 ...

  2. 【ALB技术笔记】基于多线程方式的串行通信接口数据接收案例

    基于多线程方式的串行通信接口数据接收案例 广东职业技术技术学院  欧浩源 1.案例背景 在本博客的<[CC2530入门教程-06]CC2530的ADC工作原理与应用>中实现了电压数据采集的 ...

  3. Linux学习笔记——基于鸟哥的Linux私房菜

    Linux学习笔记--基于鸟哥的Linux私房菜 ***** ARM与嵌入式linux的入门建议 (1) 学习基本的裸机编程:ARM7或ARM9,理解硬件架构和控制原理 (这一步是绝对的根基) (2) ...

  4. 学习笔记---Javascript事件Event、IE浏览器下的拖拽效果

    学习笔记---Javascript事件Event.IE浏览器下的拖拽效果     1. 关于event常用属性有returnValue(是否允许事件处理继续进行, false为停止继续操作).srcE ...

  5. JavaSE学习笔记(4)---抽象类和接口

    JavaSE学习笔记(4)---抽象类和接口 抽象方法和抽象类 ·抽象方法 使用abstract修饰的方法,没有方法体,只有声明.定义的是一种"规范",就是告诉子类必须要给抽象方法 ...

  6. JavaWeb和WebGIS学习笔记(三)——GeoServer 发布shp数据地图

    系列链接: Java web与web gis学习笔记(一)--Tomcat环境搭建 Java web与web gis学习笔记(二)--百度地图API调用 JavaWeb和WebGIS学习笔记(三)-- ...

  7. 【Spring学习笔记-MVC-3.1】SpringMVC返回Json数据-方式1-扩展

    <Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...

  8. EF学习笔记(八):更新关联数据

    学习笔记主目录链接:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 上一篇链接:EF学习笔记(七):读取关联数据 本篇原文链接:Updating Related Data 本篇主要考 ...

  9. 【EF6学习笔记】(八)更新关联数据

    上一篇链接:EF学习笔记(七):读取关联数据 本篇原文链接:Updating Related Data 本篇主要考虑对于有关联的数据进行新增.删除.更新操作:比如Course .Instructor: ...

随机推荐

  1. C语言集成开发环境vs2017的使用技巧之修改快捷键

    首先这里是说编辑C语言内容,其次开发环境是vs2017(全称:visual studio 2017).像这个开发环境体积大,但你安装的时候不要安装到C盘,然后安装的时候选择模块,比如你不开发网站,就先 ...

  2. [Leetcode] Binary search, DP--300. Longest Increasing Subsequence

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

  3. Unslider Web前端框架之图片轮播

    前端框架,前端组件,前端库,都是一个意思,能看源码. 最近做H5小游戏,用到了图片轮播的组件,而且要求支持移动端触屏滑动.一开始用的是nivo slider,但是对大小不一样的图不支持box 的参数设 ...

  4. 什么是Web Worker?

    简单点说,Web Worker就是一个运行在后台的JavaScript线程,不会影响页面的响应. 我们知道,JavaScript是单线程的脚本语言,即同一时刻只能做一件事情,否则会带来极其复杂的同步问 ...

  5. Navicat连接报错:cannot load OCI DLL,126

    32位系统下报错:cannot load OCI DLL,126 解决方法:navicat 菜单中 -工具->选项->OCI 选择oracle安装目录下bin里面的oci.dll 在win ...

  6. Ubuntu17.04配置LNMP(Nginx+PHP7+MySQL)简单教程 快速 易学 简单易懂

    我安装的是当前最新的Ubuntu版本17.04,在虚拟机中先试用一下,如果没有什么不稳定的现象,准备以后作为主力操作系统 Ubuntu属于Debian系的Linux系统,拥有着一个很NB的软件包管理器 ...

  7. scrapy配置

    scrapy配置 增加并发 并发是指同时处理的request的数量.其有全局限制和局部(每个网站)的限制. Scrapy默认的全局并发限制对同时爬取大量网站的情况并不适用,因此您需要增加这个值. 增加 ...

  8. Advice详解

    1.前置增强 BeforeAdvice是前置增强的接口,方法前置增强的MethodBeforeAdvice接口是其子类, MethodBeforeAdvice接口仅仅定义了唯一的方法:before(M ...

  9. css的各种选择器

    一.基本选择器 1. * 通用元素选择器,匹配任何元素 2. E 标签选择器,匹配所有使用E标签的元素 3. .info class选择器,匹配所有class属性中包含info的元素 4. #foot ...

  10. windows下pycharm远程调试pyspark

    参考http://www.mamicode.com/info-detail-1523356.html1.远端执行:vi /etc/profile添加一行:PYTHONPATH=$SPARK_HOME/ ...