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

广东职业技术学院  欧浩源

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. php中的数组遍历的几种方式

    [(重点)数组循环遍历的四种方式]   1.使用for循环遍历数组     conut($arr);用于统计数组元素的个数.     for循环只能用于遍历,纯索引数组!!!!     如果存在关联数 ...

  2. C/C++遍历目录下的所有文件(Windows篇,超详细)

    注: 1. 本文讨论的是怎么用Windows API遍历目录下的所有文件.除Windows API,还有一种Windows/Linux通用的方式,使用<io.h>. 2. 本文部分翻译自M ...

  3. SQL SERVER大话存储结构(6)_数据库数据文件

            数据库文件有两大类:数据文件跟日志文件,每一个数据库至少各有一个数据文件或者日志文件,数据文件用来存储数据,日志文件用来存储数据库的事务修改情况,可用于恢复数据库使用.     这里分 ...

  4. 【小练习02】CSS--网易产品

    要求用css和HTML实现下图效果: 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8& ...

  5. 基于查表的整数霍夫变换方法实现(matlab)

    暂时先用matlab把算法弄一下,这是基于查表的整数霍夫变换方法实现及解释. 接着再实现FPGA的霍夫变换. 霍夫变换原理和算法这里不多说,可参考以下链接: http://blog.csdn.net/ ...

  6. Ubuntu下解决解压zip文件中文文件名乱码问题

    在Ubuntu下解压Windows下压缩的zip文件时,会出现解压出的带中文文件名的文件名乱码,这是因为Ubuntu和Windows默认的编码不同,Ubuntu下默认的编码是UTF-8,而Window ...

  7. 手动ecache处理

    手动ecache处理: import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.E ...

  8. 将百度坐标转换的javascript api官方示例改写成传统的回调函数形式

    改写前: 百度地图中坐标转换的JavaScript API示例官方示例如下: var points = [new BMap.Point(116.3786889372559,39.90762965106 ...

  9. Selenium chrome配置不加载图片Python版

    环境: windows 7 + Python 3.5.2 + Selenium 3.4.2 + Chrome Driver 2.29 + Chrome 58.0.3029.110 (64-bit) f ...

  10. 【Android Developers Training】 98. 获取联系人列表

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...