VS_MFC:CSerialPort串口通信

参考链接: 
Afx全局函数及MFC常见数据类型 
CSerialport类开源地址(国人在github上托管的) 
CSerialPort串口类最新修正版及源码简单分析 
Remon提供的串口类网址(英文) 
[MFC]使用强大的第三方串口类 CSerialPort


什么是串口通信

串口是计算机与外围设备之间的数据传输通道,由于使用其进行通信非常方便,并且能够实现数据的长距离传输,因此它的使用非常广泛。在 Windows 环境下,串口是系统资源的一部分。应用程序要使用串口进行通信,必须在使用之前向操作系统提出资源申请要求(打开串口),通信完成后必须释放资源,即关闭串口。串口通信最重要的参数是率、数据位、停止位和奇偶校验。

- 串口通信的数据格式

这里写图片描述 
一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以“起始位”开始,以“停止位”结束,字符之间没有固定的时间间隔要求。

每一个字符的前面都有一位起始位(低电平),字符本身由7位数据位组成,接着字符后面是一位校验位(检验位可以是奇校验、偶校验或无校验位),最后是一位或一位半或二位停止位,停止位后面是不定长的空闲位,停止位和空闲位都规定为高电平。实际传输时每一位的信号宽度与波特率有关,波特率越高,宽度越小,在进行传输之前,双方一定要使用同一个波特率设置。

  • 偶校验与奇校验

在标准ASCII码中,其最高位(b7)用作奇偶校验位。所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。

  • 停止位

停止位是按长度来算的。串行异步通信从计时开始,以单位时间为间隔(一个单位时间就是波特率的倒数),依次接受所规定的数据位和奇偶校验位,并拼装成一个字符的并行字节;此后应接收到规定长度的停止位“1”。所以说,停止位都是“1”,1.5是它的长度,即停止位的高电平保持1.5个单位时间长度。一般来讲,停止位有1,1.5,2个单位时间三种长度。

  • 波特率

波特率就是每秒钟传输的数据位数。波特率的单位是每秒比特数(bps),常用的单位还有:每秒千比特数Kbps,每秒兆比特数Mbps。串口典型的传输波特率600bps,1200bps,2400bps,4800bps,9600bps,19200bps,38400bps。 
PLC/PC与称重仪表通讯时,最常用的波特率是9600bps,19200bps。PLC/PC或仪表与大屏幕通讯时,最常用的波特率是600bps。

- 串口通信的通信方式

单工模式(Simplex Communication)的数据传输是单向的。通信双方中,一方固定为发送端,一方则固定为接收端。信息只能沿一个方向传输,使用一根传输线。

半双工模式(HalfDuplex)通信使用同一根传输线,既可以发送数据又可以接收数据,但不能同时进行发送和接收。数据传输允许数据在两个方向上传输,但是,在任何时刻只能由其中的一方发送数据,另一方接收数据。因此半双工模式既可以使用一条数据线,也可以使用两条数据线。半双工通信中每端需有一个收发切换电子开关,通过切换来决定数据向哪个方向传输。因为有切换,所以会产生时间延迟,信息传输效率低些。

全双工模式(FullDuplex)通信允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。在全双工模式中,每一端都有发送器和接收器,有两条传输线,信息传输效率高。

显然,在其它参数都一样的情况下,全双工比半双工传输速度要快,效率要高。

  • 典型的串口通信标准

①EIA RS232(通常简称“RS232”): 1962年由美国电子工业协会(EIA)制定。 
②EIA RS485(通常简称“RS485”): 1983年由美国电子工业协会(EIA)制定。

项目所用的串口是RS232串口。

RS232串口

RS232是计算机与通信工业应用中最广泛一种串行接口。它以全双工方式工作,需要地线、发送线和接收线三条线。RS232只能实现点对点的通信方式。

RS232串口接口定义: 
RXD:接收数据; 
TXD:发送数据; 
GND/SG:信号地。 
电脑DB9针接口定义: 
RS232串口缺点电脑DB9针接口是常见的RS232串口(如图),其引脚定义如下: 
2号脚:RXD(接收数据) 
3号脚:TXD(发送数据) 
5号脚:SG或GND(信号地) 
其它脚:我们不用 
这里写图片描述

RS232串口缺点: 
接口信号电平值较高,接口电路芯片容易损坏。 
● 传输速率低,最高波特率19200bps。 
● 抗干扰能力较差。 
● 传输距离有限,一般在15m以内。 
● 只能实现点对点的通讯方式。

- VS2013 下串口通信的实现

在 VS2013 下, 实现串口通信的方法有以下几种:

1) 使用 API 通信函数; 
2) 使用串口通信控件 MScomm; 
3) 使用微软提供的串口通信类 SerialPort类; 
4) 使用Remon Spekreijse写的开源类CSerialPort类; 
项目主要用CSerialPort类进行串口通信编程,接下来就以CSerialPort 介绍串口通信的实现。

CSerialPort类的简述

CSerialPort类是一名名叫Remon Spekreijse的所写的开源串口类,功能十分强大。

CSerialPort工作流程

首先设置好串口参数,再开启串口检测工作线程,串口检测工作线程检测到串口接收到的数据、流控制事件或其他串口事件后,就以消息方式通知主程序,激发消息处理函数来进行数据处理,这是对接受数据而言的,发送数据可直接向串口发送。

CSerialPort类定义的消息

消息如下表:

消息名称 消息号 功能说明
WM_COMM_BREAK_DETECTED WM_USER+1 检测到输入中断
WM_COMM_CTS_DETECTED WM_USER+2 检测到CTS(清除发送)信号状态改变
WM_COMM_DSR_DETECTED WM_USER+3 检测到DSR(数据设备准备就绪)信号状态改变
WM_COMM_ERR_DETECTED WM_USER+4 发生线状态错误(包括CE_FRAMECE_OVERRUN,和CE_RXPARITY)
WM_COMM_RING_DETECTED WM_USER+5 检测到响铃指示信号
WM_COMM_RLSD_DETECTED WM_USER+6 检测到RLSD(接收线信号)状态改变
WM_COMM_RXCHAR WM_USER+7 接收到一个字符并已放入接受缓冲区
WM_COMM_RXFLAG_DETECTED WM_USER+8 检测到接受到字符(该字符已放入接受缓冲区)事件
WM_COMM_TXEMPTY_DETECTED WM_USER+9 检测到发送缓冲区最后一个字符已经被发送

端口初始化

首先, 设置几个主要参数: 
(1) BaudRate(波特率)波特率是模拟线路信号的速率,是以波形每秒的震荡数来衡量,波特率主要有以下几种频率: 2400, 4800, 9600, 14400。 
(2) PortName PortName是串口设备所使用的串口名称,在设计串口通信程序时,必须找到这个串口名称, 否则无法和串口设备建立连接进行通信 。 
(3) ReceivedBytesThreshold这个参数主要是用来触发数据接收事件 DataReceived,当输入缓冲区中的数据量达到所设的数值时就触发, 否则就一直等待。

这些设置根据具体使用的串口设备, 本文设置为 9600,com1,1, 2048/4096。参数设置完后就调用串口打开函数, SerialPort1.InitPort ()。

串口读写操作

(1)初始化串口 
流程:检查参数–>检测线程–>创建事件(监视线程)–>打开端口–>设置异步IO结构参数。 
(2)监视线程的控制 
即线程控制吧,主要有开启线程,复位和停止。 
(3)监视线程 
我们把读写串口的操作全部交给监视线程,现在简单看一下监视线程的大致流程: 
检查串口–>进入循环{WaitCommEvent(不阻塞询问)询问事件–>如果有事件来到–>到相应处理(关闭\读\写)} 
(4)读取数据操作 
读取数据是一个异步操作,当有数据发来时,会触发读事件m_ov.hEvent,监视线程捕捉到事件后并获知是读事件,进入相关读处理,这里调用函数ReceiveChar,ReceiveChar中调用ReadFile函数将串口数据读到Buffer缓冲中。 
(5)写数据操作 
也是由监视线程操作,不过触发事件交给主线程来触发,函数是WriteToPort(),将数据写入缓冲区中,然后由线程调用的函数WriteChar(),把缓冲里的数据写到串口中,期间调用WriteFile().

关闭串口

当使用串口完毕后,关闭串口,该函数为:ClosePort()。

串口通信实例分析

项目基于CSerialPort类进行串口通信,实现下位机PLC与上位机PC机之间进行通信。 
1)设计思想 
在项目中,上下位机之间通信主要是角度传感器的角度值,故而以下就以角度传输来进行分析。 
2)关键代码分析 
①数据读取 
当有数据发来后,触发读事件m_ov.hEvent,而后满足CserialPort类定义的WM_COMM_RXCHAR事件触发条件后,触发MFC里面的一个自定义消息映射宏ON_MESSAGE ,由此触发函数OnComm()进行缓冲区数据读取。

ON_MESSAGE(WM_COMM_RXCHAR, OnComm)
LONG CSerial_classDlg::OnComm(WPARAM ch, LPARAM port)
{
    ……
    m_recv = ch; 
    ……
}   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

②数据写入 
写数据相对而言比较简单,无须监控事件操作。准备好需要的数据后,直接调用函数WriteToPort()即可

void CSerial_classDlg::OnSend()
{
    ……
    m_SerialPort.WriteToPort(buf);       //发送数据
}

猜你喜欢

转载自blog.csdn.net/qq_25241325/article/details/80055096