【ALB学习笔记】基于事件触发方式的串行通信接口数据接收案例
基于事件触发方式的串行通信接口数据接收案例
广东职业技术学院 欧浩源
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学习笔记】基于事件触发方式的串行通信接口数据接收案例的更多相关文章
- 【ALB学习笔记】基于多线程方式的串行通信接口数据接收案例
基于多线程方式的串行通信接口数据接收案例 广东职业技术技术学院 欧浩源 1.案例背景 在本博客的<[CC2530入门教程-06]CC2530的ADC工作原理与应用>中实现了电压数据采集的 ...
- 【ALB技术笔记】基于多线程方式的串行通信接口数据接收案例
基于多线程方式的串行通信接口数据接收案例 广东职业技术技术学院 欧浩源 1.案例背景 在本博客的<[CC2530入门教程-06]CC2530的ADC工作原理与应用>中实现了电压数据采集的 ...
- Linux学习笔记——基于鸟哥的Linux私房菜
Linux学习笔记--基于鸟哥的Linux私房菜 ***** ARM与嵌入式linux的入门建议 (1) 学习基本的裸机编程:ARM7或ARM9,理解硬件架构和控制原理 (这一步是绝对的根基) (2) ...
- 学习笔记---Javascript事件Event、IE浏览器下的拖拽效果
学习笔记---Javascript事件Event.IE浏览器下的拖拽效果 1. 关于event常用属性有returnValue(是否允许事件处理继续进行, false为停止继续操作).srcE ...
- JavaSE学习笔记(4)---抽象类和接口
JavaSE学习笔记(4)---抽象类和接口 抽象方法和抽象类 ·抽象方法 使用abstract修饰的方法,没有方法体,只有声明.定义的是一种"规范",就是告诉子类必须要给抽象方法 ...
- JavaWeb和WebGIS学习笔记(三)——GeoServer 发布shp数据地图
系列链接: Java web与web gis学习笔记(一)--Tomcat环境搭建 Java web与web gis学习笔记(二)--百度地图API调用 JavaWeb和WebGIS学习笔记(三)-- ...
- 【Spring学习笔记-MVC-3.1】SpringMVC返回Json数据-方式1-扩展
<Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...
- EF学习笔记(八):更新关联数据
学习笔记主目录链接:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 上一篇链接:EF学习笔记(七):读取关联数据 本篇原文链接:Updating Related Data 本篇主要考 ...
- 【EF6学习笔记】(八)更新关联数据
上一篇链接:EF学习笔记(七):读取关联数据 本篇原文链接:Updating Related Data 本篇主要考虑对于有关联的数据进行新增.删除.更新操作:比如Course .Instructor: ...
随机推荐
- Unix文化--RTFM
背景 从上个世纪70年代初unix被创建后的不久,它变得越来越流行起来,从最初的贝尔实验室,到后来的许多大学的计算机院系.这意味着越来越多的人需要学习如何使用unix. 可以预期的是,贝尔实验室的人都 ...
- spring annotation功能备注
@Autowired @Autowired 注释可以在 setter 方法中被用于自动连接 bean.以type方式进行匹配. 一个构造函数 @Autowired 说明当创建 bean 时,即使在 ...
- mysql 数据库优化要点
1尽可能使用更小的类型 2尽可能的定义字段为not null,除非这个字段需要设置成null 3如果没有可变长度的字段varchar,尽可使用char 4所有字段应该有默认值 5所有的数据应该在保存之 ...
- hdu4081
hdu4081 题意 给出n个点坐标,每个点有权值,要求得到一颗生成树,且其中有一条道路修建不需要花费,但是要求这条道路所连接的两点的权值之和除以剩下所有道路的距离花费最大. 分析 首先求最小生成树, ...
- JVM-3.内存
目录 一.运行时数据区 二.内存使用细节:以HotSpot的堆为例 三.实战:OutOfMemoryError异常 四.垃圾收集器(堆+方法区)与内存分配策略 一.运行时数据区 1.程序计 ...
- 一天搞定CSS: 浮动(float)及文档流--10
浮动(float),一个我们即爱又恨的属性.爱,因为通过浮动,我们能很方便地布局: 恨,浮动之后遗留下来太多的问题需要解决,特别是IE6-7(以下无特殊说明均指 windows 平台的 IE浏览器). ...
- Java阶段性测试--知识点:数组,面向对象,集合、线程,IO流
#Java基础测试 涉及知识点:数组,面向对象,重载,重写,继承,集合,排序,线程,文件流 一.多项选择题(可能是单选,也可能是多选) 1.下列标识符命名不合法的是( D ). A.$_Name ...
- Chapter2:Discrete-Time Signal Processing and Short-Time Fourier Analysis
作者:桂. 时间:2017-05-24 08:44:53 主要是<Speech enhancement: theory and practice>的读书笔记,全部内容可以点击这里. 这一 ...
- React + Redux + express+ antd 架构的认识
在过去的两周里,我使用这套技术栈进行项目页面的开发.下面是我个人的对于项目的一些看法: 首先:是项目的调试,我深表压力很大,项目是使用fibber去抓包调试的,也不知道我们项目的负责人,怎么能的我在每 ...
- (6)javascript的程序控制结构及语句-----(1)条件判断
程序控制结构及语句 编程就是将现实应用,转换为程序能够读得懂的语法语句.Javascript编程中对程序流程控制主要是通过条件判断语句.循环控制语句及continue.break来完成的,其中条件判断 ...