.Net Core的CustomSerialPort()怎么用(core,开发技术)

时间:2024-05-05 06:43:54 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    摘要

    在使用SerialPort进行串口协议解析过程中,经常遇到接收单帧协议数据串口接收事件多次触发,协议解析麻烦的问题。针对此情况,基于开源跨平台串口类库SerialPortStrem进行了进一步封装,实现了一种接收超时响应事件机制,简化串口通讯的使用。

    引言

    最近,写了一篇博文《.net core跨平台应用研究-串口篇》得到了一些园友的好评,文中介绍了在跨平台应用研究过程中,在dotnet core下使用SerialPort类库在linux下不能支持的踩坑经历及解决办法。

    因网上关于SerialPort类库使用的相关文章较多,在该文中,对串口类库的使用,一笔带过。但在实际使用,使用过SerialPort类库的同学,可能遇到过在数据接收时,由于数据接收事件的触发具有不确定性,很多时候,一帧通讯协议数据,会多次触发,造成程序处理协议数据较为麻烦的问题。

    为简化串口通讯类库的使用,笔者结合自己的相关经验,封装了一个自定义增强型跨平台串口类库,以解决一帧协议数据,多次触发的问题。

    基础类库的选择

    由于考虑的是跨平台应用,SerialPort类库并不支持linux系统(在前一篇文章中已介绍过踩坑经历),笔者选用了SerialPortStream类库进行封装。

    该类库支持windows系统和Linux系统,但在Linux系统下运行,需要额外编译目标平台支持库并进行相关环境配置。

    相关编译配置说明在https://github.com/jcurl/SerialPortStream已有介绍,也可参考本人的拙作《.net core跨平台应用研究-串口篇》

    类库的实现

    创建跨平台类库

    为了支持跨平台,我们使用Visual Studio 2017创建一个基于.NET Standard的类库。

    .Net Core的CustomSerialPort()怎么用

    NET Standard是一项API规范,每一个特定的版本,都定义了必须实现的基类库。

    .NET Core是一个托管框架,针对构建控制台、云、ASP.NET Core和UWP应用程序进行了优化。

    每一种托管实现(如.NET Core、.NET Framework或Xamarin)都必须遵循.NET Standard实现基类库(BCL)。

    关于NET Standard和跨平台的详细说明在此:

    //www.yisu.com/article/234699.htm

    笔者也不再啰嗦呵。

    实现机制/条件

    通常串口通讯中,发送数据后,会有一段时间用于等待接收方应答,如此一来,两次数据发送之间,必然会有一定的时间间隔。如ModbusRTU协议就规定,两次数据报文发送之间,需要等待超过发送4个字节以上的间隔时间。

    笔者在单片机以及实时性较高的嵌入式系统中,为处理串口接收与协议的无关性,通常采用数据帧接收超时来处理数据帧的接收。根据串口通讯的速率计算出两次通讯之间所需要超时间隔,取两倍超时间隔时间作为超时参数,每接收到一个字节,将数据放入缓冲区并进行计时,当最后一个字节的接收时间超过超时时间,返回接收数据并清空缓存,一次完整接收完成(DMA接收方式不在此讨论)。

    .net core跨平台实现

    在自定义的串口类中,订阅基础串口类数据接收事件,在接收事件每次触发后,读出当前可用的缓冲数据到自定义缓冲区,同时,标记最后接收时间Tick为当前系统Tick。判断是否开启了接收超时处理线程,如未开启,则开启一个接收超时处理线程。

    接收超时处理线程中,以一个较小的时间间隔进行判断,如果最后接收时间与当前时间之间的间隔小于设置值(默认128ms),休眠一段时间(默认16ms)后循环检查。如间隔时间大于设定值,触发外部接收订阅事件,传出接收到的数据,退出超时处理线程。

    此处应有流程图。呵呵,懒得画了,大家自行脑补吧。 ^_^

    在windows系统或linux系统中,因系统的多任务处理的特性,系统实时性较差,通常50ms以下时间间隔的定时任务,较大程度会出现不可靠的情况(任务执行时间都有可能超过调用间隔时间)。

    因此,默认超时时间间隔设置为128ms。也可根据实际使用情况调整,但最小间隔不宜低于64ms。

    注:此处为个人经验和理解,如不认同,请直接忽视。

    主要代码

    串口接收事件代码:

    protectedvoidSp_DataReceived(objectsender,SerialDataReceivedEventArgse){intcanReadBytesLen=0;if(ReceiveTimeoutEnable){while(sp.BytesToRead>0){canReadBytesLen=sp.BytesToRead;if(receiveDatalen+canReadBytesLen>BufSize){receiveDatalen=0;thrownewException("Serialportreceivesbufferoverflow!");}varreceiveLen=sp.Read(recviceBuffer,receiveDatalen,canReadBytesLen);if(receiveLen!=canReadBytesLen){receiveDatalen=0;thrownewException("Serialportreceivesexception!");}//Array.Copy(recviceBuffer,0,receivedBytes,receiveDatalen,receiveLen);receiveDatalen+=receiveLen;lastReceiveTick=Environment.TickCount;if(!TimeoutCheckThreadIsWork){TimeoutCheckThreadIsWork=true;Threadthread=newThread(ReceiveTimeoutCheckFunc){Name="ComReceiveTimeoutCheckThread"};thread.Start();}}}else{if(ReceivedEvent!=null){//获取字节长度intbytesNum=sp.BytesToRead;if(bytesNum==0)return;//创建字节数组byte[]resultBuffer=newbyte[bytesNum];inti=0;while(i<bytesNum){//读取数据到缓冲区intj=sp.Read(recviceBuffer,i,bytesNum-i);i+=j;}Array.Copy(recviceBuffer,0,resultBuffer,0,i);ReceivedEvent(this,resultBuffer);//System.Diagnostics.Debug.WriteLine("len"+i.ToString()+""+ByteToHexStr(resultBuffer));}//Array.Clear(receivedBytes,0,receivedBytes.Length);receiveDatalen=0;}}

    接收超时处理线程代码:

    ///<summary>///超时返回数据处理线程方法///</summary>protectedvoidReceiveTimeoutCheckFunc(){while(TimeoutCheckThreadIsWork){if(Environment.TickCount-lastReceiveTick>ReceiveTimeout){if(ReceivedEvent!=null){byte[]returnBytes=newbyte[receiveDatalen];Array.Copy(recviceBuffer,0,returnBytes,0,receiveDatalen);ReceivedEvent(this,returnBytes);}//Array.Clear(receivedBytes,0,receivedBytes.Length);receiveDatalen=0;TimeoutCheckThreadIsWork=false;}elseThread.Sleep(16);}}

    创建.net core控制台程序

    为验证我们的类库是否能够正常工作,我们创建一个使用类库的.net core控制台程序。

    为啥选择dotnet core,原因很简单,跨平台。本程序分别需在windows和linux系统下进行运行测试。

    • 显示系统信息(系统标识、程序标识等)

    • 列举系统可用串口资源

    • 选择串口

    • 打开串口/关闭串口

    • 串口测试(打开/发送/关闭)

    staticvoidMain(string[]args){SetLibPath();ShowWelcome();GetPortNames();ShowPortNames();if(serailports.Length==0){Console.WriteLine($"Pressanykeytoexit");Console.ReadKey();return;}#ifRunIsServiceRunService();#endifboolquit=false;while(!quit){Console.WriteLine("\r\nPleaseInputcommandKey\r\n");Console.WriteLine("p:ShowSerialPortList");Console.WriteLine($"t:TestUart:\"{selectedComPort}\"");Console.WriteLine($"o:OpenUart:\"{selectedComPort}\"");Console.WriteLine($"c:CloseUart:\"{selectedComPort}\"");Console.WriteLine("n:selectnextserialport");Console.WriteLine("q:exitapp");Console.WriteLine();varkey=Console.ReadKey().KeyChar;Console.WriteLine();switch(key){case(Char)27:case'q':case'Q':quit=true;break;case's':ShowWelcome();break;case'p':ShowPortNames();break;case'n':SelectSerialPort();break;case't':TestUart(selectedComPort);break;case'w':TestWinUart(selectedComPort);break;case'o':OpenUart(selectedComPort);break;case'c':CloseUart();break;}}}

    笔者使用类库是直接引用类库项目,大家需要使用的话,可在解决方案资源管理器中,项目的依赖项上点击右键

    .Net Core的CustomSerialPort()怎么用

    在NuGet包管理器中,搜索SerialPort或flyfire即可找到并安装本类库。

    .Net Core的CustomSerialPort()怎么用

    类库地址

    类库地址:https://www.nuget.org/packages/flyfire.CustomSerialPort

    .Net Core的CustomSerialPort()怎么用

    跨平台测试

    Windows测试输出界面

    .Net Core的CustomSerialPort()怎么用

    .Net Core的CustomSerialPort()怎么用

    ubuntu测试输出界面

    .Net Core的CustomSerialPort()怎么用

     </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
    本文:.Net Core的CustomSerialPort()怎么用的详细内容,希望对您有所帮助,信息来源于网络。
    上一篇:python自动化的re模块怎么用下一篇:

    10 人围观 / 0 条评论 ↓快速评论↓

    (必须)

    (必须,保密)

    阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18