问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

vb.net 怎么用事件触发的方式读取串口数据

发布网友 发布时间:2022-04-27 17:51

我来回答

2个回答

懂视网 时间:2022-04-27 22:12

  以前学过MFC,我用过的它里面的包装Winsock的两个类CSocket和CAsyncSocket,我一直觉得它哪个事件通知的功能比较不错,特别是在连接的两方收发数据没有一定的规律的时候比较有用,虽然不用它的事件通知也可以实现功能,但是你需要循环检测套接字的状态或者阻塞等待,如果每次都要做这些琐碎的工作岂不是很麻烦,于是我就想对这些功能作一次封装。当然在.net里面采用delegate和event是最好的选择了。下面就是我实现的一些细节:

  先讲一下思路:其实这个还是很简单了,估计高手们会不屑一顾了^_^。当套接字开始工作,比如开始监听、开始连接的时候,启动一个线程不停的检测套接字的状态,当某一事件的状态条件满足时就触发此事件,要知道具体检测套接字状态的方法,请往下看。

  平常用套接字编成的时候可能需要用到的功能就是:连接成功或者失败的通知、在监听的套接字上有挂起的连接的通知、有数据可以接受的通知、套接字关闭的通知、还有套接字空闲可以发送数据的通知等,我也就使对上面几个功能作了封装,不过我觉得最后面一个功能用处不大???

  我的Socket类是从System.Net.Sockets.Socket继承下来的,类名TcpEventSocket,实现如下:

  先申明事件的委托类型,具体看代码

  public delegate void AcceptConnectionHandler();

  public delegate void ConnectCompletedHandler(bool connected); //connected表明连接成功与否

  public delegate void DataCanSendHandler();

  public delegate void DataCanReceiveHandler(int buffersize); //当前可以接受的数据量

  public delegate void SocketClosedHandler();

  这些类型具体什么意思应该能看出来吧,另外还要申明对应的事件

  public event AcceptConnectionHandler AcceptConnection;

  public event ConnectCompletedHandler ConnectCompleted;

  public event DataCanSendHandler DataCanSend;

  public event DataCanReceiveHandler DataCanReceive;

  public event SocketClosedHandler SocketClosed;

  另外加了几个虚方法,这几个方法用来触发事件

  protected virtual void OnAcceptConnection();
  protected virtual void OnConnectCompleted(bool connected)

  protected virtual void OnDataCanSend()
  protected virtual void OnDataCanReceive(int buffersize)

  protected virtual void OnSocketClosed()

  为了在适当的事机启动检测线程,我重写了几个基类的方法:

  new public void Listen(int backlog)

  {

  base.Listen(backlog);

  sockState = SocketState.Listenning;

  if (!checkThread.IsAlive)

  checkThread.Start();

  }

  new public void Connect(EndPoint remoteEP)

  {

  try

  {

  base.Connect(remoteEP);

  this.Blocking = false; //设置非阻塞状态,以便事件通知的效率

  if (!checkThread.IsAlive)

  checkThread.Start();

  }

  catch(SocketException)

  {

  OnConnectCompleted(false);

  }

  }

  这两个方法实际编成中都应该首先被调用的,所以有他们启动检测线程比较合适,另外线程启动了必然也要中止,于是我重写了Close方法

  new public void Close()

  {

  if(checkThread.IsAlive) //先中止线程再关闭连接

  checkThread.Abort();

  base.Close();

  sockState = SocketState.Disconnected;

  OnSocketClosed();

  }

  于是剩下的工作就是怎么检测套接字了,Socket类有个Select的静态方法,它可以检测很多套接字的状态,不过这里只需要检测一个,所以直接用Socket的Poll方法,Poll的具体用法可以看MSDN,我这里用代码说明我对套接字的检测方法

  while(true) //循环检查

  {

  if (sockState == SocketState.Disconnected) //如果当前没有连接

  {

  if (Poll(500, SelectMode.SelectWrite))

  OnConnectCompleted(true); //如果为可写状态,则表示连接成功

  }

  else if(sockState == SocketState.Listenning)

  {

  if (Poll(500, SelectMode.SelectRead)) //如果在监听状态发现套接字有数据可读则表示已经有人连接上来可以调用Accept接受连接

  OnAcceptConnection();

  }

  else //这里sockState = SocketState.Connected

  {

  if (Poll(500, SelectMode.SelectWrite)) //如果有可写状态则表示可以发送数据

  OnDataCanSend();

  if (Poll(500, SelectMode.SelectRead)) //如果有可读状态

  {

  if (Available > 0) //如果有数据可读表示可以调用Receive接受数据

  OnDataCanReceive(Available);

  else

  {

  OnSocketClosed(); //没数据可读表示连接已经关闭

  break;

  }

  }

  }

  //如果没有连接并且有错误状态,则连接失败

  if (sockState == SocketState.Disconnected && Poll(500, SelectMode.SelectError))

  OnConnectCompleted(false);

  }

  这里的OnXXX方法就是执行事件通知的方法,并且派生类中可以重载这些方法直接获得事件通知而不需要挂界别的事件通知处理函数(类似于MFC的OnAccept等虚函数)。不过派生的函数集的调用基类的相应方法哦。很可惜没有重写Socket.Accept方法,让它返回一个TcpEventSocket,这样应该就比较完整了,只可惜我不知道怎么做^_^,如果谁知道的话欢迎指教。

  事件通知机制已经基本完成,所缺乏的只是大量的测试(我做了几下最简单的测试,惭愧!!^_^)

  如果有问题请联系 yzx110@bit.edu.cn

热心网友 时间:2022-04-27 19:20

首先:
textbox里没有显示,是因为SerialPort1和TextBox2不是同一线程创建的,需要跨线程操作。需要用到委托,这样才能显示出来。
其次:
我觉得用串口的接收数据事件更好一些。
下面代码供参考:
'----------------------
'串口接收数据事件,其实比用定时器更好,
'触发事件的条件可以自己在form_load中设置ReceivedBytesThreshold属性数值,默认为ReceivedBytesThreshold=1
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim strRecvData As String = ""
strRecvData = SerialPort1.ReadExisting
Call disPlayComData(strRecvData)
End Sub
Delegate Sub callback(ByVal strT As String) '定义委托
Sub showString(ByVal comdata As String) '显示结果
Me.TextBox1.Text = "结果:" & comdata
End Sub
Sub disPlayComData(ByVal strTmp As String) '判定是否为跨线程
If Me.TextBox1.InvokeRequired Then
Dim d As New callback(AddressOf showString)
Me.Invoke(d, New Object() {strTmp})
Else
Me.TextBox1.Text = strTmp
End If
End Sub追问我是新手 有些东西不太清楚 SerialPort1_DataReceived这个过程怎么调用,调用时参数sender和e写什么
还有多个线程同时向这一个串口发送不同请求 会不会产生数据传送问题?会的话怎么解决呢?

追答SerialPort1_DataReceived 是SerialPort1的一个事件,就像Button1_Click是按钮的鼠标单击事件。每个事件都与自己的触发条件。如Button1_Click就是鼠标左键单击,就会触发这个事件,如果你想单击鼠标左键是打开串口,那么在Button1_Click里添加打开串口的代码就可以了。SerialPort1_DataReceived是在设置串口接收缓冲区到达一定字节后会触发的事件(假设为8个字节),就是说,我们希望串口接收到8个字节时告诉我,系统就通过SerialPort1_DataReceived事件通知我们了,只需要在SerialPort1_DataReceived中添加处理接收缓冲区字节的代码就行了,参数不用管。
另外,多线程同时对同一个串口操作会出错的。
上面的代码并不是多个线程对同一个串口操作,而是把串口的数据读取出来后,委托给其他线程处理。这个是.net的机制,建议你看看基础的东西

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
...防御里的4个都开不起来 错误的代码是80020002 80010007 煎牛排用什么肉好 茄子怎么做比较好吃呢? English tabloid手抄报 English tabloid手抄报怎么画 邓小平“南方讲话”关于发展问题最著名的观点是( )。 电脑电源输出12V、5V的作用是什么? win10手机能玩电脑游戏win10系统的手机难道可以安装和电脑一样的软件... 如何设置才能做到只能通过远程桌面访问server2003 怎样解电脑开机密码?且要保住电脑资料,请各位高手赐教,谢谢! 糖友荟糖友荟简介 东风本田思域和一汽大众速腾哪个好? 本田思域加什么机油好? 东风本田思域两厢版亮相 配备运动套件 本田思域油箱多少升? 我的车是本田思域,一直加的是93号汽油,现在92的能加吗 表面平淡无奇,但个个都是狠角色,这3款车可别小看了 十代本田思域用92还是95油 本田思域的动力强劲吗?它的风噪大吗? 思域加92还是95 思域加什么油啊,92还是95? 思域加什么油啊,92还是95 思域车加92的油还是95的油? 朋友的意义? 求特别病栋2 的种子 求各位收藏家 发一下有悬赏哦!! c#.net 套接字简单聊天 hellokitty限量包包 我是一个男生,性格像女生,喜欢女生的很多爱好,特别喜欢HelloKitty,从小就这样,不爱打打闹 代理药品,需要什么资质,成立一个公司,要办理什么,需要多少钱大概, 办理食品经营许可证需要多少钱 苹果新照片为什么倒着排序 佳能e470打印机时间长了会自动关机? 联想笔记本E470重装系统之后,重启出现 联想s1触摸黑屏再触摸恢复 求教,从新装了WIN7系统,E470C的无线网卡装 今年华为旗舰机什么时候岀? 瘦羊肉高压锅能压烂吗 梦见海上四个太阳快落山几搜大轮船像我史来一个大浪地上全是鱼? 农村生活污水需要领导强调的问题 这份公文的标题该用“上报”还是“发送”? 在西安哪里可以给公交卡充值,是在西安银行吗? 酒店客房部门是干嘛的? 酒店客房部的相关知识 KTV需要什么证件 客房部的介绍 开Ktv要什么证件 谈谈你的对客房及客房部的认识 开ktv需要什么证件 如何理解客房部房态的重要性 请问,ktv营业执照好办?要办些什么照?急用,谢谢! 客房部基本职能 是什么 ?能有人回答吗。谢谢