C# 通过SerialPort简单调用串口
问题
最近比较经常使用串口进行发送以及传输数据,但是笔者在刚开始接触SerialPort类时,对于Write之后去Read数据的时候,由于设备上面还没有返回数据,读取到的只能是空值。然而,再进行下一次Write操作的时候,可能返回上一次数据和这一次数据。这样使得笔者得到的数据难以保持准确性。
1、解决思路
对于上面的问题,由于数据要实时的进行返回。所以笔者想法就是在Write之后,使用线程等待(Thread.Sleep)去等待数据返回。但是最终等待多久,根据串口传输以及设备返回命令所决定。这个等待的时间是个纠结的事情。笔者就考虑:“可以通过重复相应的次数进行等待,如果等待之后还是没有获取到数据,直接舍去这个数据”。不知道园内有没有更好的解决方案。
2、解决源码
这个插入一个题外话:对于串口的编程,要注意及时的开关,但是笔者要实时获取数据使数据保持一种常开的状态,所以笔者所能想到的就是实现IDisposable接口进行清理。
笔者对于写入与获取数据的核心编码就是在串口数据获取类指定一个内部变量(_isWorking),如果_isWorking 正在工作,就让接下来的Write命令进行等待(等待时长必须长于重复次数的总时长),获取到数据之后,将_isWorking 设置为false。【这里存在一个问题,如果高数据命令情况下,会阻塞!!笔者还未找到好的解决方法】。
好了又扯了这么多,上主要的代码,这里有一点特别注意的,以下代码只能够解决的串口接收单个byte数据的内容,具有缺陷,不推荐多数据使用。
/// <summary>
/// 串口写入数据,并且等待返回值
/// </summary>
/// <param name="writeCommandByte">写入命令</param>
/// <param name="replyData">返回数据</param>
/// <returns>返回数据偏移位</returns>
protected int WriteWithReplyData(byte[] writeCommandByte, out byte[] replyData)
{
if (writeCommandByte == null)
{
throw new ArgumentNullException("writeCommandByte");
}
//等待其他发送数据的完成
var waitTimes = 0;
while (waitTimes < 4 && _isWorking)
{
waitTimes++;
Thread.Sleep(40);
} //如果超时还是没有等待到,就直接返回
if (_isWorking)
{
replyData = null;
return 0;
}
//开始工作,设置串口工作状态未true
_isWorking = true;
_port.Write(writeCommandByte, 0, writeCommandByte.Length);
replyData = new byte[_port.ReadBufferSize];
int count = 0;
var times = 0;
//等待数据返回,并限制等待时间100ms
while (times < 5 && count <= 0)
{
times++;
count = _port.Read(replyData, 0, _port.ReadBufferSize);
if (count <= 0)
{
Thread.Sleep(20);
}
}
//等待得到数据,将工作状态设为false
_isWorking = false;
return count; }
3、最终解决方案
1)通过串口SerialPort 订阅DataReceived事件进行获取串口数据
2)当然也可以使用线程实时读串口数据(用容器收集起来)
具体的代码如下:
/// <summary>
/// 串口数据接收时间
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void _port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var byteCount = _port.BytesToRead;
if (byteCount > 0 )
{
byte[] reciveByteArr = new byte[byteCount]; int offsetCount = _port.Read(reciveByteArr, 0, byteCount); //接收字节集合
_recivedDataList.AddRange(reciveByteArr);
//验证数据包是否完整,虚方法可以继承进行重写
while (CheckPortPackageComplete())
{
//获取数据接收包的总长度,虚方法可以继承进行重写
int packageLength = GetCompletePackageLength(); var packageList = _recivedDataList.GetRange(0, packageLength); _recivedDataList.RemoveRange(0, packageLength); var packageArray = packageList.ToArray(); //解析算法,通过外部进行添加解析算法,可以保持解析的扩展性
foreach (var analyticalItem in _analyticalDic)
{
var obj = analyticalItem.Value(packageArray);
if (obj != null)
{
//事件通知数据
OnReciveDataNotice(obj, analyticalItem.Key);
break;
}
}
}
}
}
(如果觉得不错请点赞下,有误的话请指出,卤鸽在此感谢)
C# 通过SerialPort简单调用串口的更多相关文章
- C#实现简单的串口通信
前言 本着学习研究的态度,用c#语言实现简单的串口通信工具. 一.串口通信原理 串口通信 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节.尽管比 ...
- C#--简单的串口通信程序
前几天做毕业设计,其中要用到串口和下位机进行通信,于是自己捣鼓了一个简单的串口通信程序. 在做通信之前要先弄一个SerialPort组件出来,当然也可以通过程序来创建.本次设计中采用的是拖的winfo ...
- DSAPI 调用串口选择界面
在DSAPI中,可以通过简单的代码调用串口选择界面,当用户选择了其中一个串口时,将返回选择的串口名称(或序号). Dim 串口名称 As String = DSAPI.串口通讯.显示串口选择界面.选择 ...
- loadrunner做webservice接口之简单调用
今天听大神讲了webservice做接口,我按照他大概讲的意思自己模拟实战了下,可能还有很多不对,一般使用webservice做接口,会使用到soapui,但是用了loadrunner以后发现lr很快 ...
- 【Android进阶】Android程序与JavaScript之间的简单调用
本篇将讲解一个简单的Android与JavaScript之间的简单调用的小程序 效果图 工程结构 HTMLActivity.java代码 package com.example.javatojs; i ...
- 原生js简单调用百度翻译API实现的翻译工具
先来个在线demo: js翻译工具 或者百度搜索js简单调用百度翻译API工具(不过有个小小的界面显示bug,我想细心的人应该会发现) 或者直接前往该网址:js翻译工具 或者前往我的github:gi ...
- StreamReader 和 StreamWriter 简单调用
/* ######### ############ ############# ## ########### ### ###### ##### ### ####### #### ### ####### ...
- 经测试稳定可用的蓝牙链接通信Demo,记录过程中遇到的问题的思考和解决办法,并整理后给出一个Utils类可以简单调用来实现蓝牙功能
说明:这是本人在蓝牙开发过程中遇到过的问题记录和分析,以及解决办法. 在研究过程中,许多的前人给出的解决方案和思路指导对我相当有帮助,但并非都是可采取的解决方法, 经过本人对这些方法的测试和使用过后, ...
- jQuery懒加载插件 – jquery.lazyload.js简单调用
Lazy Load 是一个用 JavaScript 编写的 jQuery 插件. 它可以延迟加载长页面中的图片. 在浏览器可视区域外的图片不会被载入, 直到用户将页面滚动到它们所在的位置. 这与图片预 ...
随机推荐
- 动态生成dropdownlist
<td colspan=" id="td_ddl" runat="server"> </td> 后台代码: #region 动 ...
- 记一次未解决的异常:java.lang.NoClassDefFoundError: net/sf/json/JSONObject
原因:Jetty会导致这个问题,Tomcat可以正常启动 一.异常产生现象 使用json-lib转换实体类/字符串,跑单元测试没问题,但是启动jetty后调用JSONArray.fromObjec ...
- iOS相关思考题
1.iOS如何应对APP版本升级,数据结构随之变化? 一般程序app升级时,数据库有可能发生改变,如增加表字段,增加表等. 此时有两种操作: 1 就是毫无留情的把本地旧数据库直接删掉,重新建立新的数据 ...
- Warchall: Live RCE
具体漏洞是:CVE-2012-1823(PHP-CGI RCE) 在地址后面加进参数运行对应的php-cgi 参数的行为 例如 index.php?-s 相参于/usr/bin/php53-cgi/p ...
- linux crontab命令参数及用法详解--linux自动化定时任务cron
声明:本文转自Linux 安全网,在此基础上加上自己的体会! crontab 命令 如果发现您的系统里没有这个命令,在ubuntu server 中用的是 sudo apt-get install c ...
- (七) 一起学 Unix 环境高级编程(APUE) 之 进程关系 和 守护进程
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- [原创]Matlab获取当前时间信息
本文主要介绍下Matlab中如何获取当前时间的一些方法. 基本变量date.now.clock date 按照日期字符串返回当前系统时间 now 按照连续的日期数值返回当前系统时间 clock按照日期 ...
- python 小知识
PYTHONPATH是Python搜索路径,默认我们import的模块都会从PYTHONPATH里面寻找. 使用下面的代码可以打印PYTHONPATH: print(os.sys.path) impr ...
- Linux下守护进程初探
守护进程一直后台运行,与终端脱离,一般负责周期性地执行系统任务,服务器应用一般以守护进程进行运行.实现一个守护进程主要分为5部: 1.脱离父进程 2.setsid(可以选择再次fork) 3.umas ...
- 用函数datepart获取当前日期、周数、季度
用函数datepart处理就可以了,示例:select datepart(weekday,getdate()) as 周内的第几日select datepart(week,getdate()) as ...