【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: ...
随机推荐
- css浮动--float/clear通俗讲解(转载)
本文为转载 (出处:http://www.cnblogs.com/iyangyuan/archive/2013/03/27/2983813.html) 教程开始: 首先要知道,div是块级元素,在页面 ...
- Comparing the contribution of NBA draft picks(转)
When it comes to the NBA draft, experts tend to argue about a number of things: at which position wi ...
- springboot redis 缓存对象
只要加入spring-boot-starter-data-redis , springboot 会自动识别并使用redis作为缓存容器,使用方式如下 gradle加入依赖 compile(" ...
- python基础学习笔记
#!/usr/bin/env python #coding=utf-8 def login(username): if username=='bill': return 1 else: return ...
- [rctf](web)rcdn 解题分析,知识点总结
比赛平台关闭了,没有截图,见谅. 解题思路流程: 分析网站结构,看源码,元素审计.发现以下信息. 要得到flag要获得一个pro cdn pro 子域名长度为3到6个字符 存在一个提交ticke页 ...
- Java之FilenameFilter接口
FilenameFilter接口:是用于过滤文件的 要实现的是accept方法 实例代码: 1,匿名类实现FilenameFilter-–过滤指定类型文件 package File类过滤器; impo ...
- C++函数调用的反汇编过程及Thunk应用
x86汇编基础知识 1. 汇编常用寄存器 esp,(Extended stack pointer)栈顶指针.因为x86的栈内存是向下扩展的,因此当push入栈时,esp–.pop出栈时,esp++.e ...
- 小白审计JACKSON反序列化漏洞
1. JACKSON漏洞解析 poc代码:main.java import com.fasterxml.jackson.databind.ObjectMapper; import com.sun.or ...
- Webpack 开发工具与模块热替换
Webpack 开发工具与模块热替换 ⚠️ 注意: 永远不要在生产环境中使用这些工具,永远不要. devtool 当 JavaScript 异常抛出时,你常会想知道这个错误发生在哪个文件的哪一行.然 ...
- Hibernate入门(二)
一 Hibernate使用注解 可以使用注解创建Hibernate程序,使用注解的优点是不用创建映射文件,直接创建对象的关联. 使用hibernate注解需要导入注解相关的JAR包. 1.下载JAR包 ...