命名空间:using System.IO.Ports;
该类提供了同步 I/O 和事件驱动的 I/O、对管脚和中断状态的访问以及对串行驱动程序属性的访问。

操作类声明: SerialPort sp = null;

/// <summary>
/// 打开串口
/// </summary>
/// <param name="protName">串口号</param>
/// <param name="baudRate">波特率</param>
/// <param name="dataBit">数据位</param>
/// <param name="stopBits">停止位</param>
/// /// <param name="parity">校验位</param>
/// <returns></returns>
public bool OpenCom(string protName, int baudRate, int dataBit, float stopBits, int parity)
{
bool flag = true;
if (sp == null)
{
sp = new SerialPort();
}
sp.PortName = protName;//串口号
sp.BaudRate = baudRate;//波特率
float f = stopBits;//停止位
if (f == )
{
sp.StopBits = StopBits.None;
}
else if (f == 1.5)
{
sp.StopBits = StopBits.OnePointFive;
}
else if (f == )
{
sp.StopBits = StopBits.One;
}
else
{
sp.StopBits = StopBits.Two;
} sp.DataBits = dataBit;//数据位 if (parity == )
{
sp.Parity = Parity.None;
}
else if (parity == )
{
sp.Parity = Parity.Odd;
}
else if (parity == )
{
sp.Parity = Parity.Even;
}
else
{
sp.Parity = Parity.None;
} // sp.ReadTimeout = 1000;//设置超时读取时间
// sp.WriteTimeout = 1000;//超时写入时间
try
{
if (!sp.IsOpen)
{
sp.Open(); }
}
catch (Exception)
{
flag = false;
}
return flag;
}
/// <summary>
/// 关闭端口
/// </summary>
/// <returns></returns>
public bool CloseCom()
{
try
{
if (sp.IsOpen)
{
sp.Close();
}
return true;
}
catch
{
return false;
}
}

串口的打开和关闭

在串口的打开方法中 SerialPort类对分别用[BaudRate]、[Parity]、[DataBits]、[StopBits]属性设置通讯格式中的波特率、校验位、数据位、停止位,其中[Parity]和[StopBits]分别是枚举类型Parity、StopBits,Parity类型中枚举了Odd(奇)、Even(偶)、Mark、None、Space,Parity枚举了None、One、OnePointFive、Two。

项目中遇到一个问题是,一个界面开关几次后,再次关闭,要等到很长时间才能退出,等再次打开窗口,串口类接收数据的效率明显降低。

原因是 当串口正在进行大量的数据处理和页面更新的时候,如何强制关闭串口,会造成串口死掉。

解决方法是在串口方法接收数据的时候加入一个变量,先控制停止串口数据的接收,然后关闭串口,这样就不会串口死掉很长时间后才关闭的现象。

public bool SwitchDeviceState(int StateNum)
{
if (sp == null)
{
return false;
} byte[] data = new byte[];
data[] = 0x55;//帧头
data[] = 0xAA;//帧头
data[] = 0x06;//帧长度
data[] = 0x02;//设备地址
data[] = 0x00;//通道号(改变设备状态时,通道号为0,表示整个设备)
data[] = 0x02;//命令码
switch (StateNum)
{
//命令数据
case : data[] = 0x00; break;//空闲
case : data[] = 0x01; break;//循环刺激
case : data[] = 0x02; break;//肌电反馈
case : data[] = 0x04; break;//抓握采集
case : data[] = 0x05; break;//电流标定
}
return DataWrite(, data); }
/// <summary>
/// 向模拟板发送数据命令
/// </summary>
/// <param name="verifyIndex">开始计算校验位的位置</param>
/// <param name="b"></param>
/// <returns></returns>
public bool DataWrite(int verifyIndex, byte[] b)
{
bool flag = true;
try
{
int numAdjust = ; for (; verifyIndex < b.Length - ; verifyIndex++)
{
numAdjust += Convert.ToInt32(b[verifyIndex].ToString());
}
if (numAdjust > 0xff)
{
string strAdjust = Convert.ToString(numAdjust, );
numAdjust = Convert.ToInt32(strAdjust.Substring(strAdjust.Length - ), );
}
b[b.Length - ] = (byte)numAdjust;
sp.Write(b, , b.Length);
}
catch
{
flag = false;
}
return flag;
}

数据的发送和读取

在此方面中C++语言有比较好的封装方法,C#语言我自身没有找到之前比较好的示例,于是自己写了一些简单的方法,已经可以成功向下位机模拟板进行数据发送
DataWrite方法中首先由verifyIndex位开始计算校验数据,c#中先把十六进制的byte转换为Int32类型相加减,然后再转换为byte类型得到校验位。最后使用 sp.Write(b, 0, b.Length)方法把整个byte数组发送出去,这里要注意的是发送的数据一定要使用byte[] 数组的形式,且发送的都必须时十六进制的数据,以后在接收模拟板的数据时也是一样。其中原因有待查看。
Serial发送数据的方法有Write和WriteLine,其中WriteLine可发送字符串并在字符串末尾加入换行符。此处采用的是Write方式

3.注册对象的数据接收事件的方法(可以在串口操作类的构造函数中注册)
SerialPort中串口数据的读取与写入有较大的不同。由于串口不知道数据何时到达,因此有两种方法可以实现串口数据的读取。一、线程实时读串口,即每个一段时间抓取串口缓冲区的数据;二、事件触发方式实现。由于线程实时读串口的效率不是十分高效,因此比较好的方法是事件触发的方式。在SerialPort类中有DataReceived事件,当串口的读缓存有数据到达时则触发DataReceived事件,其中SerialPort.ReceivedBytesThreshold属性决定了当串口读缓存中数据多少个时才触发DataReceived事件,默认为1。
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sp.ReceivedBytesThreshold = 1;//事件发生前内部输入缓冲区的字节数,每当缓冲区的字节达到此设定的值,就会触发对象的数据接收事件

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] Resoursedata = new byte[sp.BytesToRead];
sp.Read(Resoursedata, 0, Resoursedata.Length);//在此就可以读取到当前缓冲区内的数据
//执行数据操作
sp.DiscardInBuffer();//丢弃传输缓冲区数据
sp.DiscardOutBuffer();//每次丢弃接收缓冲区的数据
}

首先SerialPort类读取数据的方法有多种,但是有的读是同步,有的是异步,同步就是和主程序保持一致,只有运行完了ReadByte之后才能运行程序之后的代码,异步就是重新开启一个线程来处理这些问题,主程序不受到干扰,继续运行。
serialPort中有6个读的方法:
Read();ReadLine(); ReadByte();ReadChar();ReadExisting();ReadTo();

ReadTo和ReadExisting是异步读取,剩下的都是同步读取。
我在程序测试中使用ReadTo和ReadExisting获取缓冲区的数据,由于这两个方法的接收类型都是String类型,并且显示出来都是一些编码混乱的字符,需要进一步编码格式转换。因此此处选择的是Read同步读取数据,接收数据的类型是一个byte数据,接下来更容易对数据进行下一步的处理和操作。如何考虑系统运行效率的问题(在没秒钟内模拟板可能向上位机发送非常庞大的数据量),可以考虑在开一个线程来控制模拟板数据的读取,然后仍然使用Read方法进行数据的读取。

4.部分c#数据类型转换
//十进制转二进制
Console.WriteLine(Convert.ToString(69, 2));
//十进制转八进制
Console.WriteLine(Convert.ToString(69, 8));
//十进制转十六进制
Console.WriteLine(Convert.ToString(69, 16));
//二进制转十进制
Console.WriteLine(Convert.ToInt32(”100111101″, 2));
//八进制转十进制
Console.WriteLine(Convert.ToInt32(”76″, 8));
//C# 16进制转换10进制
Console.WriteLine(Convert.ToInt32(”FF”, 16));

c#实现串口操作 SerialPort的更多相关文章

  1. C# 串口操作系列(3) -- 协议篇,二进制协议数据解析

    原文地址:http://blog.csdn.net/wuyazhe/article/details/5627253 我们的串口程序,除了通用的,进行串口监听收发的简单工具,大多都和下位机有关,这就需要 ...

  2. C# 串口操作 ---- 系列文章

    C# 串口操作系列(5)--通讯库雏形 通讯库雏形的建立. 串口通讯介绍的高级篇,介绍更高级的抽象,为扩展为通用的客户端通讯库做铺垫,扩展性的考虑,能支持任意类型的流设备. ... 2010-08-0 ...

  3. C# 串口操作系列(5)--通讯库雏形

    C# 串口操作系列(5)--通讯库雏形 标签: 通讯c#数据分析byteclassstring 2010-08-09 00:07 21378人阅读 评论(73) 收藏 举报  分类: 通讯类库设计(4 ...

  4. 【转】C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子。

    C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子. 标签: c#objectnewlineexceptionbytestring 2010-05-17 01:10 117109人阅读 ...

  5. 【C#】串口操作实用类

    做工业通 信有很长时间了,特别是串口(232/485),有VB/VC/C各种版本的串口操作代码,这些代码也经过了多年的现场考验,应该说是比较健壮的代码,但 是目前却没有C#相对成熟的串口操作代码,最近 ...

  6. Android串口操作,简化android-serialport-api的demo(转载)

    原帖地址:点击打开 最近在做android串口的开发,找到一个开源的串口类android-serialport-api.其主页在这里http://code.google.com/p/android-s ...

  7. Arduino - 串口操作函数与示例代码大全

    来源:https://blog.csdn.net/iracer/article/details/50334041 Arduino - 串口操作函数与示例代码大全 本文总结了Arduino常用串口操作函 ...

  8. C# 串口操作系列(4) -- 协议篇,文本协议数据解析

    C# 串口操作系列(4) -- 协议篇,文本协议数据解析 标签: c#uiobjectstringbyte 2010-06-09 01:50 19739人阅读 评论(26) 收藏 举报  分类: 通讯 ...

  9. C# 串口类SerialPort的使用方法

    序言:最近做了一个智能体育项目——跆拳道积分系统,硬件部分会向软件传入振动值等数据,链接方式为串口,所以用到SerialPort类. 值得注意的是: DataReceived 方法,当串口缓冲区有数据 ...

随机推荐

  1. django-url调度器-中级篇

    在初级篇中,我们接触了: 1.url 的简单编写 2.两种传参的方式 3.捕获的参数总是字符串 4.为视图设置默认参数 …… 在中级篇中将更进一步. 包含其它的URLconfs 当网站非常大的时候,将 ...

  2. EMVTag系列1《数据分组》

    数据分组的设计在个人化过程中承担着重要的作用.数据分组标识符(DGI)是两字节十六进制数.数据分组标识的第一个字节等于'01'到'1E',表明数据存储的SFI.第二个字节表明SFI记录的记录编号.其他 ...

  3. 向plsql中导入数据

    1.TOOLS-->ODBC IMPORTER 2.TOOLS-->TEXT IMPORTER3.sqlldr userid=zj/zj@orcl control=D:\test.ctl ...

  4. Oracle连乘聚合函数 MUL

    Oracle提供了求和(SUM),平均值(AVG)等聚合函数,但没有提供连乘的聚合函数. 比如有一个表如下: ID NUM 1 4 2 2 3 2 如果要求NUM列的连乘数,即求: 4*2*2 ,目前 ...

  5. 联想Z470安装10.11懒人版成功!!特此分享!!

    折腾黑苹果也断断续续好几个月了,在远景也爬了好多贴,遇到问题基本上靠自己解决,自己组的台式机已基本完美,大学期间买的联想Z470现在是“食之无味,弃之可惜”,想想也来试试装个黑苹果玩玩,之前装过10. ...

  6. mac os x 系统安装 genymotion android 模拟器

    如果你有 apk 文件 想 运行一下看看 ,但是又没有  android 设备 ,那么 genymotion 将会是一个  很好的解决方案. 1.安装 下载链接: https://cloud.geny ...

  7. [转]Reed Solomon纠删码

    [转]Reed Solomon纠删码    http://peterylh.blog.163.com/blog/static/12033201371375050233/     纠删码是存储领域常用的 ...

  8. 如何设置电脑的IP

    先找到自己的ip,在设置ip. 图1 图2 图3 图4 图5 图6

  9. 45.modelsim仿真include文件

    modelsim仿真include文件会出现找不到文件的情况,这是因为include文件路径有两种,一种是相对路径,另一种是绝对路径. 相对路径: 如果 ‘include "primitiv ...

  10. Hibernate从入门到精通(十)多对多单向关联映射

    上一篇文章Hibernate从入门到精通(九)一对多双向关联映射中我们讲解了一下关于一对多关联映射的相关内容,这次我们继续多对多单向关联映射. 多对多单向关联映射 在讲解多对多单向关联映射之前,首先看 ...