2_串口设备数据的接收和处理
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
表2.2.1 SerialPort类的构造函数定义
功能说明 构造函数的接口定义 使用默认属性值创建SerialPort类的新实例,其中数据 位数的默认值为 8,校验位的默认值为 None,停止位 的默认值为 1,默认端口名称为 COM1。
public SerialPort();
工控程序设计
4
学习情景2.2 串口设备数据的接收和处理
工控程序设计
13
学习情景2.2 串口设备数据的接收和处理
6 数据帧片段的缓存方法 (1)使用集合类存储接收数据 在通信过程中,数据帧表示由多个字节构成的,具有一定格式,表 示完整语意的一组数据。例如,在和HSDZC电能综合测试仪进行通信 时,如果测试仪工作在测量方式1,则一帧数据的长度为46个字节( 包含起始标志和14个数值)。 在系统实际运行中,下位机向上位机发送数据时,可能会将数据帧 分为几个片段依次发送,或者在一次接收到的数据中包含了不止一帧 数据。上位机必须提供一个字节的集合来对接收到的数据进行缓存( 暂存),在确认接收完毕一帧数据后,再进行进一步的分析和处理。 .NET Framework 2.0以上版本提供了List类来实现集合元素管理。 List类支持泛型,在存取byte类型的集合元素时无需进行“装箱”和 “拆箱”操作,比使用ArrayList效率高。
SerialPort sp; private void btnStart_Click (object sender, EventArgs e) { byte firstByte; sp.ReadExisting(); //清空接收缓冲区,准备接收数据 sp.ReadTimeout = 10000; //10秒内没有收到回复数据,将捕获到异常 try { firstByte = (byte)sp.ReadByte(); //同步读取(程序在此被阻塞) t1.Text = firstByte.ToString("X2"); //显示在文本框t1中 } catch (TimeoutException ex) //捕获到接收超时异常 { t1.Text = ex.Message; //在t1中显示异常信息 } }
工控程序设计
3
学习情景2.2 串口设备数据的接收和处理
表2.2.1 SerialPort类的构造函数定义
2.2.3 相关知识 1 SerialPort类实例的构造 SerialPort类是从.NET Framework 2.0版本开始提供的一个串口控制类 ,该类包含在System.IO.Ports命名空间中,使用该类的实例可以打开串 口,并发送数据。 通过构造函数可以产生SerialPort类的实例,SerialPort类的构造函数 在定义时进行了重载,表2.2.1中列出了这些重载构造函数的接口定义:
ReadByte方法返回一个int类型的值,在实际应用时,要将返回值 强制转换为byte类型。 (2)Read方法 Read方法从串口接收缓冲区中读取多个字节,该方法的接口定义是: public int Read(byte[] buffer, int offset, int count); 该方法试图从接收缓冲区中读取count个字节,并写入字节数组 buffer中,写入的起始位置是offset,执行后返回实际读取的字节数 。例如,现在接收缓冲区中只有6个字节,但count参数值为10,则返 回值为6。 在实际应用时,通常先通过SerialPort对象的BytesToRead属性获 得接收缓冲区中已有的字节数,并根据该属性值来设置count参数。 和ReadByte方法不同的是,调用Read方法时,不管接收缓冲区中有无数 据,都不会对应用程序的当前线程造成阻塞。
int baudRate); public SerialPort(string portName, int baudRate,
化 SerialPort 类的新实例,其它参数采用默认值
int dataBits); public SerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits); 使用指定的端口名称、波特率、奇偶校验位、数据位 和停止位初始化SerialPort 类的新实例
工控程序设计
8
学习情景2.2 串口设备数据的接收和处理
4 接收超时异常处理 当使用ReadByte方法从接收缓冲区中读取一个字节时,如果下位机发 送过来的数据没有在ReadTimeout规定的时间内到达,则会引发 TimeoutException,应用程序可以捕获该异常,并作相应处理。下面 的测试程序说明了超时异常处理的方法:
{
B = -B; B3 = (byte)(B3 & 0x7F); //等价于B3=(byte)(B3-128) if ((B3 & 0x40) != 0) //如果D6为1 { B3 = (byte)(B3 & 0xBF); n = -B3; } else n = B3; f = B * (float)Math.Pow(2, n); //B乘以2的n次方 return f; }
工控程序设计
学习情景2.2 串口设备数据的接收和处理
学习情景2.2 串口设备数据的接收和处理
2.2.1 学习要点 1.知识点:SerialPort类实例的构造,接收串口数据的方法,接收超时 异常处理,HSDZC电能综合测试仪的数据格式,数据帧片段的缓存方 法 2.技能点:应用程序项目和SerialPort对象的创建,串口数据接收,接 收数据的缓存和数据帧的提取 2.2.2 任务描述 某些串口设备能够定时、主动地向上位机发送数据,处于上位机端 的工业控制程序,需要获取串口收到的数据并进行分析和处理。利用 .NET Framework 2.0及更高版本提供的SerialPort类可以比较方便地 在C#应用程序中实现串口通信功能。从编程的角度看,串口数据的接 收就是利用SerialPort对象的Read或ReadByte方法将操作系统存放在 串口输入缓冲区中的数据读入到一个字节数组中。 该教学情景通过串口数据接收、接收数据的缓存、数据帧的提取、 浮点数解码这几个实施步骤,达到使用SerialPort对象接收单个串口 设备(下位机)数据的目的。
工控程序设计
11
学习情景2.2 串口设备数据的接收和处理
构成浮点数值的3个字节含义是:第1字节(B1)为尾数低位,第2字节(B2)为 尾数高位,第3字节(B3)为阶码指数。其中阶码指数各位的含义如表 2.2.2所示: 表2.2.2 阶码指数字节中各位的含义
D7Baidu Nhomakorabea
数值符号:0为正, 1为负
D6
阶码符号:0为正,
工控程序设计
6
学习情景2.2 串口设备数据的接收和处理
(3)IsOpen属性 通过IsOpen属性可以获知串口当前是否为打开状态,返回一个bool类型 的值,该属性只读,接口定义如下: public bool IsOpen { get; } 串口不能重复进行打开和关闭操作,在打开或关闭串口前,都要 使用该属性检查串口是否已经处于打开或已经处于关闭状态,以免引 发异常。 3 接收串口数据的方法 (1)ReadByte方法 SerialPort类的ReadByte方法可以从串口接收缓冲区中读取一个字 节,该方 法的接口定义是: public int ReadByte();
工控程序设计
14
学习情景2.2 串口设备数据的接收和处理
List类提供了丰富的方法来对集合中的元素进行操作,表2.2.3列出 了List类的常用方法,表中的示例建立在如下定义的基础上: byte b; byte[] ba; List<byte> li = new List<byte>(); //创建List类的实例li,元 素类型为byte 表2.2.3 List类的常用方法
工控程序设计
10
学习情景2.2 串口设备数据的接收和处理
5 HSDZC电能综合测试仪的数据格式 HSDZC电能综合测试仪在钻机性能测试系统中用于输入功率、输出 功率以及功率因素(参见引言介绍)。该设备提供两种电脑测量方式 ,在仪表提示“测量方式”时,可以分别按“显示1”和“显示2”进 入。 在测量方式1的情况下测试仪每秒通过RS-232接口发送1组数据,长 度46字节。信号格式:开始4字节均为FFH,后续每三个字节构成一个 浮点数值,分别表示I1、U1、I2、U2、I3、U3,以及功率因数、视在 功率、效率、输入功率、无功功率、负载率、输出功率、转速,共14 个数据。 在测量方式2的情况下测试仪也是每秒通过RS-232接口发送1组数据 ,长度30字节。信号格式:开始3字节均为12H、34H、56H,后续每三 个字节构成一个浮点数值,分别表示I1、U1、P1、I2、U2、P2、I3、 U3、P3,共9个数据。 上位机在和HSDZC电能综合测试仪进行通信时,不需要向设备写入数 据,而是被动地读取设备发送过来的数据。下面的相关知识将进一步 介绍对已接收到数据的存储和处理方法。
D5-D0
阶码数值 1为负
工控程序设计
12
学习情景2.2 串口设备数据的接收和处理
尾数B的值在0到1之间,计算公式是:
B B 2 256 B1 65536
下面的HexToFloat函数描述了将3个字节转换为浮点数的算法:
private float HexToFloat(byte B1, byte B2, byte B3) { float f, B, n; //B:尾数 n:阶码指数 B = (B2 * 256 + B1) / 65536F; if ((B3 & 0x80) != 0) //如果D7为1,等价于 if(B3>=128)
工控程序设计
5
学习情景2.2 串口设备数据的接收和处理
除了在构造SerialPort类实例的时候可以对端口名称、波特率、 奇偶校验位、数据位和停止位进行设置外,构造好SerialPort类实例 后,还可以通过PortName、BaudRate、Parity、DataBits、StopBits 属性对这些参数进行修改,因此构造SerialPort类实例的程序书写形 式比较灵活。 2 串口的打开和关闭 SerialPort类中与串口打开和关闭相关的成员如下: (1)Open方法 Open方法打开新的串口连接,该方法不带参数,接口定义如下: public void Open() (2)Close方法 Close方法关闭已经打开的串口连接,该方法不带参数,接口定义如下: public void Close()
该方法从串口接收缓冲区中读取一个字节,要和ReadTimeout属性配合使用 。当调用ReadByte方法时,如果接收缓冲区中没有数据,则程序被阻塞,直 到缓冲区中有数据或到达ReadTimeout属性指定读取数据超时的毫秒数,程序 才能继续运行。
工控程序设计
7
学习情景2.2 串口设备数据的接收和处理
工控程序设计
9
学习情景2.2 串口设备数据的接收和处理
图2.2.1 接收超时异常测试 如上图所示,在点击“开始”按钮后,程序被阻塞,此时窗口 对鼠标和键盘的输入都不响应。为了有足够操作时间,SerialPort对 象sp的ReadTimeout属性为10000毫秒(10秒)。在10秒时间内,测试 者可以通过串口测试程序发送一个或多个字节过来,此时程序结束阻 塞状态继续运行,并在文本框中显示接收到的第1个字节;如果10秒 内没有数据到达,则引发TimeoutException。 若上位机程序要一直等待,可以把ReadTimeout属性的值设置为 -1,但在实际应用中一般不这样做。
使用指定的端口名称初始化 SerialPort 类的新实例 public SerialPort(string portName); ,其它参数采用默认值 public SerialPort(string portName, 使用指定的端口名称和波特率初始化 SerialPort 类 的新实例,其它参数采用默认值 使用指定的端口名称、波特率和奇偶校验位初始化 SerialPort 类的新实例,其它参数采用默认值 Parity parity); public SerialPort(string portName, int baudRate, Parity parity, 使用指定的端口名称、波特率、校验位和数据位初始
功能说明 构造函数的接口定义 使用默认属性值创建SerialPort类的新实例,其中数据 位数的默认值为 8,校验位的默认值为 None,停止位 的默认值为 1,默认端口名称为 COM1。
public SerialPort();
工控程序设计
4
学习情景2.2 串口设备数据的接收和处理
工控程序设计
13
学习情景2.2 串口设备数据的接收和处理
6 数据帧片段的缓存方法 (1)使用集合类存储接收数据 在通信过程中,数据帧表示由多个字节构成的,具有一定格式,表 示完整语意的一组数据。例如,在和HSDZC电能综合测试仪进行通信 时,如果测试仪工作在测量方式1,则一帧数据的长度为46个字节( 包含起始标志和14个数值)。 在系统实际运行中,下位机向上位机发送数据时,可能会将数据帧 分为几个片段依次发送,或者在一次接收到的数据中包含了不止一帧 数据。上位机必须提供一个字节的集合来对接收到的数据进行缓存( 暂存),在确认接收完毕一帧数据后,再进行进一步的分析和处理。 .NET Framework 2.0以上版本提供了List类来实现集合元素管理。 List类支持泛型,在存取byte类型的集合元素时无需进行“装箱”和 “拆箱”操作,比使用ArrayList效率高。
SerialPort sp; private void btnStart_Click (object sender, EventArgs e) { byte firstByte; sp.ReadExisting(); //清空接收缓冲区,准备接收数据 sp.ReadTimeout = 10000; //10秒内没有收到回复数据,将捕获到异常 try { firstByte = (byte)sp.ReadByte(); //同步读取(程序在此被阻塞) t1.Text = firstByte.ToString("X2"); //显示在文本框t1中 } catch (TimeoutException ex) //捕获到接收超时异常 { t1.Text = ex.Message; //在t1中显示异常信息 } }
工控程序设计
3
学习情景2.2 串口设备数据的接收和处理
表2.2.1 SerialPort类的构造函数定义
2.2.3 相关知识 1 SerialPort类实例的构造 SerialPort类是从.NET Framework 2.0版本开始提供的一个串口控制类 ,该类包含在System.IO.Ports命名空间中,使用该类的实例可以打开串 口,并发送数据。 通过构造函数可以产生SerialPort类的实例,SerialPort类的构造函数 在定义时进行了重载,表2.2.1中列出了这些重载构造函数的接口定义:
ReadByte方法返回一个int类型的值,在实际应用时,要将返回值 强制转换为byte类型。 (2)Read方法 Read方法从串口接收缓冲区中读取多个字节,该方法的接口定义是: public int Read(byte[] buffer, int offset, int count); 该方法试图从接收缓冲区中读取count个字节,并写入字节数组 buffer中,写入的起始位置是offset,执行后返回实际读取的字节数 。例如,现在接收缓冲区中只有6个字节,但count参数值为10,则返 回值为6。 在实际应用时,通常先通过SerialPort对象的BytesToRead属性获 得接收缓冲区中已有的字节数,并根据该属性值来设置count参数。 和ReadByte方法不同的是,调用Read方法时,不管接收缓冲区中有无数 据,都不会对应用程序的当前线程造成阻塞。
int baudRate); public SerialPort(string portName, int baudRate,
化 SerialPort 类的新实例,其它参数采用默认值
int dataBits); public SerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits); 使用指定的端口名称、波特率、奇偶校验位、数据位 和停止位初始化SerialPort 类的新实例
工控程序设计
8
学习情景2.2 串口设备数据的接收和处理
4 接收超时异常处理 当使用ReadByte方法从接收缓冲区中读取一个字节时,如果下位机发 送过来的数据没有在ReadTimeout规定的时间内到达,则会引发 TimeoutException,应用程序可以捕获该异常,并作相应处理。下面 的测试程序说明了超时异常处理的方法:
{
B = -B; B3 = (byte)(B3 & 0x7F); //等价于B3=(byte)(B3-128) if ((B3 & 0x40) != 0) //如果D6为1 { B3 = (byte)(B3 & 0xBF); n = -B3; } else n = B3; f = B * (float)Math.Pow(2, n); //B乘以2的n次方 return f; }
工控程序设计
学习情景2.2 串口设备数据的接收和处理
学习情景2.2 串口设备数据的接收和处理
2.2.1 学习要点 1.知识点:SerialPort类实例的构造,接收串口数据的方法,接收超时 异常处理,HSDZC电能综合测试仪的数据格式,数据帧片段的缓存方 法 2.技能点:应用程序项目和SerialPort对象的创建,串口数据接收,接 收数据的缓存和数据帧的提取 2.2.2 任务描述 某些串口设备能够定时、主动地向上位机发送数据,处于上位机端 的工业控制程序,需要获取串口收到的数据并进行分析和处理。利用 .NET Framework 2.0及更高版本提供的SerialPort类可以比较方便地 在C#应用程序中实现串口通信功能。从编程的角度看,串口数据的接 收就是利用SerialPort对象的Read或ReadByte方法将操作系统存放在 串口输入缓冲区中的数据读入到一个字节数组中。 该教学情景通过串口数据接收、接收数据的缓存、数据帧的提取、 浮点数解码这几个实施步骤,达到使用SerialPort对象接收单个串口 设备(下位机)数据的目的。
工控程序设计
11
学习情景2.2 串口设备数据的接收和处理
构成浮点数值的3个字节含义是:第1字节(B1)为尾数低位,第2字节(B2)为 尾数高位,第3字节(B3)为阶码指数。其中阶码指数各位的含义如表 2.2.2所示: 表2.2.2 阶码指数字节中各位的含义
D7Baidu Nhomakorabea
数值符号:0为正, 1为负
D6
阶码符号:0为正,
工控程序设计
6
学习情景2.2 串口设备数据的接收和处理
(3)IsOpen属性 通过IsOpen属性可以获知串口当前是否为打开状态,返回一个bool类型 的值,该属性只读,接口定义如下: public bool IsOpen { get; } 串口不能重复进行打开和关闭操作,在打开或关闭串口前,都要 使用该属性检查串口是否已经处于打开或已经处于关闭状态,以免引 发异常。 3 接收串口数据的方法 (1)ReadByte方法 SerialPort类的ReadByte方法可以从串口接收缓冲区中读取一个字 节,该方 法的接口定义是: public int ReadByte();
工控程序设计
14
学习情景2.2 串口设备数据的接收和处理
List类提供了丰富的方法来对集合中的元素进行操作,表2.2.3列出 了List类的常用方法,表中的示例建立在如下定义的基础上: byte b; byte[] ba; List<byte> li = new List<byte>(); //创建List类的实例li,元 素类型为byte 表2.2.3 List类的常用方法
工控程序设计
10
学习情景2.2 串口设备数据的接收和处理
5 HSDZC电能综合测试仪的数据格式 HSDZC电能综合测试仪在钻机性能测试系统中用于输入功率、输出 功率以及功率因素(参见引言介绍)。该设备提供两种电脑测量方式 ,在仪表提示“测量方式”时,可以分别按“显示1”和“显示2”进 入。 在测量方式1的情况下测试仪每秒通过RS-232接口发送1组数据,长 度46字节。信号格式:开始4字节均为FFH,后续每三个字节构成一个 浮点数值,分别表示I1、U1、I2、U2、I3、U3,以及功率因数、视在 功率、效率、输入功率、无功功率、负载率、输出功率、转速,共14 个数据。 在测量方式2的情况下测试仪也是每秒通过RS-232接口发送1组数据 ,长度30字节。信号格式:开始3字节均为12H、34H、56H,后续每三 个字节构成一个浮点数值,分别表示I1、U1、P1、I2、U2、P2、I3、 U3、P3,共9个数据。 上位机在和HSDZC电能综合测试仪进行通信时,不需要向设备写入数 据,而是被动地读取设备发送过来的数据。下面的相关知识将进一步 介绍对已接收到数据的存储和处理方法。
D5-D0
阶码数值 1为负
工控程序设计
12
学习情景2.2 串口设备数据的接收和处理
尾数B的值在0到1之间,计算公式是:
B B 2 256 B1 65536
下面的HexToFloat函数描述了将3个字节转换为浮点数的算法:
private float HexToFloat(byte B1, byte B2, byte B3) { float f, B, n; //B:尾数 n:阶码指数 B = (B2 * 256 + B1) / 65536F; if ((B3 & 0x80) != 0) //如果D7为1,等价于 if(B3>=128)
工控程序设计
5
学习情景2.2 串口设备数据的接收和处理
除了在构造SerialPort类实例的时候可以对端口名称、波特率、 奇偶校验位、数据位和停止位进行设置外,构造好SerialPort类实例 后,还可以通过PortName、BaudRate、Parity、DataBits、StopBits 属性对这些参数进行修改,因此构造SerialPort类实例的程序书写形 式比较灵活。 2 串口的打开和关闭 SerialPort类中与串口打开和关闭相关的成员如下: (1)Open方法 Open方法打开新的串口连接,该方法不带参数,接口定义如下: public void Open() (2)Close方法 Close方法关闭已经打开的串口连接,该方法不带参数,接口定义如下: public void Close()
该方法从串口接收缓冲区中读取一个字节,要和ReadTimeout属性配合使用 。当调用ReadByte方法时,如果接收缓冲区中没有数据,则程序被阻塞,直 到缓冲区中有数据或到达ReadTimeout属性指定读取数据超时的毫秒数,程序 才能继续运行。
工控程序设计
7
学习情景2.2 串口设备数据的接收和处理
工控程序设计
9
学习情景2.2 串口设备数据的接收和处理
图2.2.1 接收超时异常测试 如上图所示,在点击“开始”按钮后,程序被阻塞,此时窗口 对鼠标和键盘的输入都不响应。为了有足够操作时间,SerialPort对 象sp的ReadTimeout属性为10000毫秒(10秒)。在10秒时间内,测试 者可以通过串口测试程序发送一个或多个字节过来,此时程序结束阻 塞状态继续运行,并在文本框中显示接收到的第1个字节;如果10秒 内没有数据到达,则引发TimeoutException。 若上位机程序要一直等待,可以把ReadTimeout属性的值设置为 -1,但在实际应用中一般不这样做。
使用指定的端口名称初始化 SerialPort 类的新实例 public SerialPort(string portName); ,其它参数采用默认值 public SerialPort(string portName, 使用指定的端口名称和波特率初始化 SerialPort 类 的新实例,其它参数采用默认值 使用指定的端口名称、波特率和奇偶校验位初始化 SerialPort 类的新实例,其它参数采用默认值 Parity parity); public SerialPort(string portName, int baudRate, Parity parity, 使用指定的端口名称、波特率、校验位和数据位初始