资源描述
简单的异步串行通信编程实验(上)
一、背景知识
在数据通信中,通常将待传送的每个字符的二进制代码按照由低位到高位的顺序依次发
送的方式成为串行通信。由于串行通信只需在发送方和接收方之间建立一条通信信道,因此
可以减小通信系统的造价。在远程通信中,一般采用串行通信方式。
同步就是要求通信的收发双方在时间基准上保持一致。在串行通信中,“异步”是同步
收发双方通信的重要方式。
在异步串行通信中,每个字符作为一个独立的整体进行发送,字符之间的时间间隔可以
是任意的。为了实现同步,需要在每个字符的第一位前加1位起始位(逻辑1),并在字符的最后一位后加1位、1.5位或2位停止位(逻辑0)。
常用的串行通信接口标准包括RS-232、RS-449、V.24、V.35等。其中,RS-232是最常用的串行通信标准之一。个人计算机及终端系统中配备的串行接口几乎都符合RS-232标准。在数据通信中,通常将数据终端设备简称为DTE(data terminal equipment),而将数据通信设备简称为DCE(data circuit equipment)。DTE是具有一定数据处理能力以及发送和接收数据能力的设备,而DCE的主要作用是在DTE和传输线路之间提供信号变换和实现编码功能,并且负责建立、保持和释放数据链路的连接。
RS-232是美国电子工业协会EIA推荐使用的串行通信标准,定义了DTE和DCE之间的接口标准。RS-232使用的连接器包括DB-25、DB-15、和DB-9等几种类型,不同类型连接器使用的引脚定义也各不相同。目前,个人计算机配备的RS-232连接器通常为DB-9,下图说明了RS-232在使用DB-9作为连接器时的引脚排列、信号名称和方向。
在Windows 平台下,利用系统自带的“超级终端”可测试RS-232电缆连接的正确性。首先用RS-232电缆将实验用的两台计算机连接起来,然后在这两台计算机上同时启动Windows 系统的“超级终端”串行口应用程序。在配置相同的情况下,如果两台计算机能够通过串行口正确通信,那么说明RS-232电缆以及两台计算机上的串行口都可以正常使用。
测试流程截图如下:
首先,新建一个超级终端。
选择文件选项中的属性,在连接到选项卡中修改连接时使用的端口为COM1或COM2。
修改端口配置数据,将其还原为默认值。
在连接属性的设置选项卡中修改ASCII码设置。
在ASCII码设置中选中ASCII码发送的两个选项:以换行符作为发送行末尾和本地回显键入的字符。
输入字符后显示效果如下:
二、开发环境
开发环境
本次实验所要求编写的简单的异步串行通信程序使用WindowsXP平台下的VC6作为开发环境来创建一个MFC应用程序项目。
首先,新建一个MFC AppWizard(exe)项目。
应用程序类型选择基于对话框式。
由于程序并不复杂,加入特征选项可将关于对话框适当取消。
选择MFC库作为静态链接库。
选择创建对话框的类。
在实验室中可以利用两台带有串口的计算机进行连接后的程序测试,但如果只有一台带有串口的计算机,异或是没有串口的笔记本电脑,则需要通过虚拟软件来创建若干串行口进行程序的测试。
我使用的是虚拟串行驱动程序VSPD,这是一个可在计算机Windows下操作的程序,此驱动程序会创造数个“虚拟”的串行埠。 由一般程序看来,这些虚拟的串行端口跟实体的串行端口相同,唯一不同于传统传输的地方是在于程序所送出的信息是透过TCP/IP局域网络送至虚拟串行端口,之后由EM100再将所收到的信息传达至串行设备。 当串行设备要回传信息时,要先将信息传至EM100,而后再藉由局域网络将信息传回至位于计算机端的虚拟串行驱动程序,当虚拟串行驱动程序收到信息后,又会将其传回给程序,就如同传统串行线的传输一般。所以不论串行设备或计算机程序都无法辨别真实串行与虚拟串行传输的不同。
配置流程如下:
在串行口管理选项卡中添加一对串口COM1和COM2。
添加之后如图所示。
当没有程序加载时,所有串口处于关闭状态;加载后,程序会打开目标串口,VSPD中的串口探测器会显示当前串口的状态。
三、 程序设计
本次实验的程序为MFC应用程序,主要编辑文件为对话框程序文件及其头文件。
程序本身主要可分为4个大模块,串行口打开模块、串行口状态值读取与属性设置模块、串行数据的发送与接收模块以及串行口关闭模块。
1、 打开串行口
在对串行口进行所有的操作之前,首先要将其打开。串行口的打开可以使用CreateFile函数,CreateFile函数将返回一个句柄,在随后与该串行口相关的各种操作中使用。
函数原型为:
HANDLE CreateFile (
LPCTSTR lpFileName, //要打开的串口逻辑名,即COM1或其他
DWORD dwDesiredAccess,//串口访问权限,GENERIC_WRITE或GENERIC_READ
DWORD dwShareMode, //串口共享属性,由于不可共享,须设为0
LPSECURITY_ATTRIBUTES lpSecurityAttributes,//安全属性,默认为NULL
DWORD dwCreationDisposition,//指定如何处理打不开的文件或设备,由于 //串口是实物,须设置为OPEN_EXISTING
DWORD dwFlagsAndAttributes, //串口的标志和属性,由于是异步处理,接 //收和发送数据在后台进行,须设置为 //FILE_FLAG_OVERFLAPPED
HANDLE hTemplateFile //模板文件的句柄,串口无模板,设置为0
);
如调用成功,则返回打开串口的句柄,否则返回INVALID_HANDLE_VALUE。
示例如下:
2、串行口的状态读取与属性设置
串口打开时,可对其属性进行设置,所以先读取当前串口状态值,再在其上进行修改。
获取串口当前状态的函数为GetCommState,其原型如下:
BOOL GetCommState (
HANDLE hFile, //由CreateFile函数返回的已打开的串口的句柄
LPDCB lpDCB //设备控制块DCB
);
设备控制块中包含串口的属性和状态,主要使用其中的波特率BaudRate,数据位数ByteSize,奇偶校验位Parity,是否进行奇偶校验fParity,停止位数StopBits。
调用成功返回非0值,否则返回0。
示例如下:
修改串口状态值用函数SetCommState,原型如下:
BOOL SetCommState (
HANDLE hFile,
LPDCB lpDCB
);
示例如下:
串口打开时,可为串口分配发送缓冲区和接收缓冲区,可使用SetupComm函数,原型如下:
BOOL SetupComm (
HANDLE hFile,
DWORD dwInQueue, //接收缓冲区大小
DWORD dwOutQueue, //发送缓冲区大小
);
示例如下:
在串口发送和接收数据前,要使用PurgeComm函数清除缓冲区数据。原型如下:
BOOL PurgeComm (
HANDLE hFile,
DWORD dwFlags //执行的动作,包括PURGE_RXCLEAR和PURGE_RXCLEAR
);
示例如下:
3、 串行数据的发送与接收
利用ReadFile函数可以读取串口接收到的数据,原型如下:
BOOL ReadFile (
HANDLE hFile,
LPVOID lpBuffer, //指向读取数据缓冲区
DWORD nNumberOfBytesToRead, //指定读取字节数
LPDWRD lpNumberOfBytesRead, //实际读取字节数
LPOVERLAPPED lpOverlapped //指向一个OVERLAPPED结构变量,该结构 //变量包含一个同步事件
);
如调用成功,则返回非0值,否则返回0。
示例如下:
利用WriteFile函数可以向串口写入数据。原型如下:
BOOL WriteFile (
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWRD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
示例如下:
4、关闭串行口
在用完串口后通常要关闭它,否则其他的应用程序就不能打开或使用它。
关闭串口可以使用函数CloseHandle。原型如下:
BOOL CloseHandle (
HANDLE hObject //该打开串口的句柄
);
示例如下:
由于串行口的接收通常可以放置在一个新的线程中进行,因此,需要调用创建并管理线程的头文件afxmt.h,然后在窗口的初始化例程OnInitDialog中需要启动一个用于读取接收信息的工作者线程。
工作者线程的启动可以调用AfxBeginThread函数。原型如下:
CWinThread* AfxBeginThread(
AFX_THREADPROC pfnThreadProc, //指向工作者线程的控制函数,不能为NULL
LPVOID pParam, //传给控制函数pfnThreadProc的参数
int nPriority = THREAD_PRIORITY_NORMAL,//指定线程的优先级,默认为 //THREAD_PRIORITY_NORMAL
UINT nStackSize = 0, //指定线程的堆栈大小
DWORD dwCreateFlags = 0, //控制线程创建的附加标志,默认为0
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL //指定线程的安全性
);
AfxBeginThread函数返回一个指向新创建线程对象的指针。利用该指针,可以访问该线程对象的成员函数。
示例如下:
程序流程:
四、 程序测试
计算机A
计算机B
结果分析:
程序通过Windows API函数将计算机的串行口打开,并对该串口进行设置,然后分配接收和发送信息的缓冲区并将其清空,之后启动一个用于读取接收信息的工作者进程等待对方计算机的信息传输过来,这样从计算机A和计算机B分别发送的信息经过各自的串口COM1和COM2传输到对方的计算机上并显示出正确的结果。
通过这个实验,我掌握了简单的异步串行通信的基本原理及其编程的方法,了解了串口等计算机硬件设备的工作机制,为以后的学习和编程实践打下了一定基础
展开阅读全文