串行通信机理 与 应用

43
1 串串串串串串串串 tonghuasu @hit.edu. cn May 5, 2006

description

串行通信机理 与 应用. 苏统华 [email protected] May 5, 2006. 概要. 背景介绍 串行通信系统模型 串行接口配置 串行通信机理简介 多线程串行通信的编程 扩展的串行通信编程. 背景介绍. 串行通信是指计算机与其它外围设备以 “ 位 ” 为单位进行信息交换的过程。 串行通信应用的领域 : 数据的采集与智能诊断 工业的检测及自动控制 ,eg. 控制单片机、采集核探测数据、接收 GPS 数据等 集散控制环境( DCS : Distributed Control System ) 无线调制环境 3D 空间定位器 - PowerPoint PPT Presentation

Transcript of 串行通信机理 与 应用

Page 1: 串行通信机理 与 应用

1

串行通信机理与应用

苏统华[email protected]

May 5, 2006

Page 2: 串行通信机理 与 应用

2

概要

背景介绍 串行通信系统模型 串行接口配置 串行通信机理简介 多线程串行通信的编程 扩展的串行通信编程

Page 3: 串行通信机理 与 应用

3

背景介绍 串行通信是指计算机与其它外围设备以“位”为

单位进行信息交换的过程。 串行通信应用的领域 :

1. 数据的采集与智能诊断2. 工业的检测及自动控制 ,eg. 控制单片机、采集核探测数据、接收

GPS 数据等3. 集散控制环境( DCS : Distributed Control System )4. 无线调制环境5. 3D空间定位器6. 数据手套的发射器和接收器

Page 4: 串行通信机理 与 应用

4

串行通信系统模型串行通信系统是一种典型的计算机数据通信系统。抽象化的点 -点计算机数据通信系统框图 :

Page 5: 串行通信机理 与 应用

5

串行接口配置 RS-232C 标准:它对串行通信接口的有关问题,如连接电

缆和机械、电气特性、信号功能及传送过程都作了明确规定。

COM 口一般是 9 脚的连接器,分成插针 (Male) 和插孔 (Female) 两类:

1 5

6 9

5 1

9 6

9 脚的 RS-232C 插针

9 脚的 RS-232C 插孔

Page 6: 串行通信机理 与 应用

6

串行接口配置 DTE 与 DCE 间的通信连接模型通常有 3 种,分

别为:

1. 最简 3 线交叉连接模型2. 近距 7 线交叉连接模型3. 远距 7 线对应模型

Page 7: 串行通信机理 与 应用

7

串行接口配置 最简 3 线交叉连接模型:应用于控制信号较少的场合

优点:1. 控制简单2. 节省线路

计算机 单片机

TxD

RxDRxD

TxD

GNDGND

Page 8: 串行通信机理 与 应用

8

串行接口配置 近距 7 线交叉连接模型:用于控制信号较丰富的

近距离通信场合 优点:这种方式省去了 DCE

Page 9: 串行通信机理 与 应用

9

串行接口配置 远距 7 线对应模型:“豪华”配置,包含通信设

备 MODEM 或其它数传设备 优点:适合远距离的通信任务

Page 10: 串行通信机理 与 应用

10

一个简单应用例子: 系统中采用 PIC16C73 单片机作为下位机,工业控制 PC 机为上位机,

二者通过 RS-232C 串行口接收或上传数据和指令。 RS-232C 信号的电平和单片机串口信号的电平不一致,必须进行二者之间的电平转换。在此使用 MAXIM 公司的集成电平转换芯片 MAX202E 作为 RS-232C和 TTL 间的电平转换芯片。

Page 11: 串行通信机理 与 应用

11

串行通信机理 目前, Windows 系统下通过 VC 开发串行通信的常用方

法可分成如下 6 类:1. 利用 Windows API 函数进行串行通信编程;2. 利用开发环境自带的 ActiveX 通信控件来构建串行通信应用:3. 利用 VC 的标准通信函数 _inp , _outp 等进行串行通信操作;4. 利用第三方提供的通信类 ( 如 Cserial 类 ) 、通信库 ( 如 DLL) ;5. 利用内嵌汇编直接操作通信端口来实现 ( 只限Win9x 下 ) ;6. 通过编写 VxD(Virtual Device Driver) 来实现。

Page 12: 串行通信机理 与 应用

12

串行通信机理 可编程通用异步收发器 (UART : Universal Asynchrono

us Receiver and Transmitter) 是 PC 内部一块单独的芯片,是实现数据“串 -并”转换功能的电路。

发送数据时, UART会把 CPU经由数据总线送来的字符数据保存到“数据输出寄存器”;随后, UART再按顺序把“数据输出寄存器”的内容送到“发送移位寄存器”转换成连续的串行位流,并在其中插入奇偶检验位、起始位和停止位;最后将位流传送出去。

接收数据的过程与上相反。串行的位流通过串口时,送入UART 的“接收移位寄存器”;当“接收移位寄存器”中己接收完 1个字符的各位后,数据就从“接收移位寄存器”进入“数据输入寄存器”,成为了一个字符大小的并行数据;最后就是数据经由数据总线上传给 CPU。

Page 13: 串行通信机理 与 应用

13

串行通信机理 Windows 系统为每个通信设备开辟了用户定义大小的接收和发送缓冲区,应用程序只需完成对接收和发送缓冲区操作就可以了。

通信的实际过程是每接收一个字符就产生一个低级硬件中断, Windows 系统中的串行 VxD取得控制权,将接收到的字符放入接收缓冲区,然后将控制权返给正在运行的应用程序.

在定义了硬件流控制的条件下,如果接收缓冲区数据已满,串行驱动程序用定义的流控制机制通知发送方停止发送数据。缓冲区内的数据按 FIFO方式处理。

Page 14: 串行通信机理 与 应用

14

串行通信机理 Win32 环境下的通信应用服务要依赖于虚拟通信驱动程序 VCOMM 。 VCOMM 提供一条应用程序到硬件的保护模式代码通路,以实现可靠

的高速数据传输。 VCOMM 实质是一个 VxD ,它总是在 Win32启动时载入。 Win32 为

串口提供了端口驱动程序,端口驱动程序是动态装入 VxD 的,可由 VCOMM 调用来操作串口。

Page 15: 串行通信机理 与 应用

15

串行通信机理 通信 API 有一组基本的函数,它们为应用程序的

编制提供了一个适于串行通信的接口,处理通信资源的打开、关闭、读写等操作。

通信 API 的扩展函数可为那些不为标准函数所支持的服务提供接口,这组扩展的函数允许用户使用仅为驱动程序专用的参数来配置,也允许用户调用驱动程序的专用函数。

Page 16: 串行通信机理 与 应用

16

串行通信机理 串行通信的公有的操作流程,大致四步:

1. 打开串行口。这样做就是通知Windows本应用程序需要这个串口,并封锁之,使其它应用程序在该串口释放前不能使用它。

2. 通信前,初始化这个串行口。如配置 BAUD ,数据位等各种参数。3. 进行串口数据传输。有时要进行数据的检错或纠错。4. 通信完成时,关闭串口。即释放串口资源以供其它应用程序使用。

Page 17: 串行通信机理 与 应用

17

多线程与串行通信的示例 在串行通信系统的应用中,一般要求系统能较快响应系统事件同时还

不能丢数据。如果把监视通信事件的功能单独作为一个线程来执行,即使主线程阻塞,也不影响系统对外来信息的接收。

主线程和监视线程各司其职又相互协调:主线程主要完成串口的初始化、串口的资源获取、启动监视事件、关闭串口句柄和发送信息等操作,监视线程则用于发现串口事件并进行相应事件的处理。

Page 18: 串行通信机理 与 应用

18

多线程与串行通信的示例 Win32 中禁止应用程序直接和硬件交互,开发者只能通过

系统提供的各类 Vxd 来管理硬件。在这种情况下, Windows 系统充当了应用程序与硬件之间的中介,而留给开发者的则是高级、统一的接口。 Windows 系统对串口硬件资源的管理类似于对普通文件的操作。

多线程串行通信系统的开发流程:

Page 19: 串行通信机理 与 应用

19

多线程与串行通信的示例 打开串口 Windows 通过调用 CreateFile() 以操作文件的方式来指定和获得串行

口资源。函数成功执行后,将返回串行口的内存句柄,该句柄是随后操作(如读、写,参数设置等)的指向对象。

下面是一个获取串行口资源的例子:HANDLE m_pComm;m_pComm=CreateFile(“COM1”,GENERIC_READ|GENERIC_WRITE,

0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);

if(m_hComm==INVALID_HANDLE_VALUE){// 错误处理return FALSE;}

Page 20: 串行通信机理 与 应用

20

多线程与串行通信的示例 串口初始化 初始化的内容有设置缓冲区、设置超时、配置通信参数几个过程。1.  设置缓冲区 串行口拥有发送和接收缓冲区,调用 SetupComm() 可以根据需要设置

串行口发送和接收缓冲区的大小。得到缓冲区之后应该首先清除缓冲区中原来的数据内容,调用的函数为 PurgeComm() 。

下面的语句将设置接收缓冲区大小为 512字节,发送缓冲区为 1024字节,并清空缓冲区:

SetupComm(m_pComm,512,1024); PurgeComm(m_pComm,PURGE_TXABORT|PURGE_RXABORT|PURG

E_TXCLEAR|PURGE_RXCLEAR);

Page 21: 串行通信机理 与 应用

21

多线程与串行通信的示例 设置超时 由于在进行串行通信过程中,可能发生一些无法预测的事件,在进行

串行口操作前,最好设置超时,以保障通信的安全性。通过函数 SetCommTimeouts() 可以设置所有读写操作的超时时间。 SetCommTimeouts() 的原型如下。

BOOL SetCommTimeouts( HANDLE hFile, //串行口句柄 LPCOMMTIMEOUTS lpCommTimeouts //指向超时结构 COMMTIMEOUTS);

一个设置超时的例子:

Page 22: 串行通信机理 与 应用

22

多线程与串行通信的示例 配置通信参数 常调用 SetCommState() 来配置串行口本次通信过程中的参数,如波特率( Baud )、数据位数、停止位数、校验情况等,这些参数的修改是通过对一个 DCB结构的配置来实现的。 DCB结构是一个拥有 30个成员的大数据结构。由于一般要修改的参数很有限,故经常在 SetCommState() 之前调用 GetCommState() 来获得系统的缺省设备控制块值,然后在缺省值基础上进行一定的修改,再把修改后的 DCB 结构传送给 SetCommState() 。对于 SetCommState() 和 GetCommState()的原型如下:

BOOL SetCommState( HANDLE hFile, //串行口句柄 LPDCB lpDCB //指向 DCB结构的指针);BOOL GetCommState( HANDLE hFile , //串行口句柄 LPDCB lpDCB //指向 DCB结构的指针);一个符合上述描述的示例如下:DCB m_dcbm_dcb.DCBlength=sizeof(DCB);

GetCommState(m_pComm,&m_dcb);m_dcb.fBinary=TRUE;//…

if(!SetCommState(m_pComm,&m_dcb)){// 出错处理

}

Page 23: 串行通信机理 与 应用

23

多线程与串行通信的示例 创建 I/O重叠结构 要支持重叠 I/O 操作,必须声明重叠结构并为该重叠结构生成 I/O重叠事件。以重叠方式调用的函数可以立即返回,即使操作还没有完成,这样能使费时的 I/O 操作以后台运行而调用线程仍可自由执行别的任务。重叠操作要求在获得通信设备时用 FILE-FLAG-OVERLAPPED 标志建立,并且重叠函数要指定 OVERLAPPED结构的指针。重叠事件的生成可用 CreateEvent() 。

为读操作分配 I/O重叠结构的例程如下:OVERLAPPED m_rdOL;memset(&m_rdOL,0,sizeof(OVERLAPPED));

m_rdOL.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); if (m_rdOL.hEvent==NULL) {

// 出错处理return FALSE;}

Page 24: 串行通信机理 与 应用

24

多线程与串行通信的示例 设置监视事件 Windows 系统是一个基于消息驱动的操作系统,它的许

多事件来源于硬件设备, Windows 设备驱动程序只是把这些事件进行简单处理,转换成相应的消息放到Windows消息队列中去。 Win9x 之后取消了串行通信的专用消息WM_COMMNOTIFY,使得用户进程要主动监视串口状态,并对相应事件作出响应。串口监视事件的设置是由 SetCommMask() 来完成,串口监视事件的捕获由WaitCommEvent() 实现,对串口监视事件的捕获请见下文的串口读部分。 SetCommMask() 的原型如下:

BOOL SetCommMask( HANDLE hFile,//串行口句柄 DWORD dwEvtMask// 监视事件掩码);

Page 25: 串行通信机理 与 应用

25

多线程与串行通信的示例

Page 26: 串行通信机理 与 应用

26

多线程与串行通信的示例 下面是一个设置监视事件的例程:

/* 为串口设置监视事件 , 包括接受到数据、输出缓冲区空、错误事件*/

if (!SetCommMask(m_pComm,EV_RXCHAR|EV_TXEMPTY|EV_ERR)) {

//出错处理return FALSE; }

Page 27: 串行通信机理 与 应用

27

多线程与串行通信的示例 l 启动监视线程 读串口时,我们并不知道数据什么时候到来,所以要建立

一个在后台运行的专门负责读数据的工作线程( worker thread )。读监视线程的启动常通过调用 AfxBeginThread()完成。 AfxBeginThread() 的原型如下:

CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,LPVOID pParam,int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0,DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

Page 28: 串行通信机理 与 应用

28

多线程与串行通信的示例启动一个读监视工作线程的示例如下:// 启动一个负责串口读操作的监视线程CWinThread* m_Thread;

if (!m_Thread){

if(!(m_Thread=AfxBeginThread(CommWatchProc,this))) {

// 出错处理return FALSE; }

}

Page 29: 串行通信机理 与 应用

29

多线程与串行通信的示例 在监视线程的执行函数中,可通过 WaitCommEvent()捕获串口事件, Wait

CommEvent() 的原型如下:BOOL WaitCommEvent( HANDLE hFile,//串行口句柄 LPDWORD lpEvtMask,//指向一个存储事件组的变量 LPOVERLAPPED lpOverlapped,//指向一个重叠结构);

在调用了 WaitCommEvent() 之后可通过对返回的 lpEvtMask 施行“ AND” 操作来进一步判定捕获到的串口事件类别,并可分别处理。示例如下

DWORD dwEvtMask;WaitCommEvent(m_pComm,&dwEvtMask,&m_rdOL);

if(dwEvtMask&EV_ERR) {

// 捕捉到通信错误}else if(dwEvtMask&EV_TXEMPTY) {

// 输出缓冲区的数据发送完} else if (dwEvtMask&EV_RXCHAR) {

// 输入缓冲区接收到数据}

Page 30: 串行通信机理 与 应用

30

多线程与串行通信的示例 进行通信—读写 在获得了串行口句柄并完成了准备工作后,即可对串行口进行读写操作了。

其中读操作的执行是调用 ReadFile() 函数,它可以以读取文件的方式从串行口的接收缓冲区 (也称为输入缓冲区 ) 中读取指定长度的数据(如果有足够的数据的话)。写操作的执行是调用 WriteFile() 函数,它完成与读操作相反的过程。在本文的串行口通信中,它们都是以重叠方式进行。 ReadFile() 和 WriteFile() 的原型分别如下:

BOOL ReadFile( HANDLE hFile,//串行口句柄 LPVOID lpBuffer, //指向接收数据的缓冲区 DWORD nNumberOfBytesToRead,// 读的任务量 LPDWORD lpNumberOfBytesRead,//指向实际读取完成的量 LPOVERLAPPED lpOverlapped //指向一个重叠结构);BOOL WriteFile( HANDLE hFile, //串行口句柄 LPCVOID lpBuffer, //指向源数据地址 DWORD nNumberOfBytesToWrite, // 写的任务量 LPDWORD lpNumberOfBytesWritten,//指向实际写的量 LPOVERLAPPED lpOverlapped //指向一个重叠结构);

Page 31: 串行通信机理 与 应用

31

多线程与串行通信的示例 以重叠方式操纵串口时,要求 ReadFile( 或 WriteFile) 函数必须指定了 OVERLAPPED结构,执行时,

ReadFile(WriteFile) 不必等到读(写)操作完成即可返回,返回值为 FALSE ,同时GetLastError 函数返回 ERROR_IO_PENDING 。串口重叠操作的结果由 GetOverlappedResult 函数返回,成功时为非零,失败时为零;如要得到进一步的扩展信息,则要再一次调用 GetLastError 函数,根据返回值进行必要处理。下面是重叠读的一个示例:BOOL bReadStat ;COMSTAT ComStat ;DWORD dwErrorFlags; DWORD dwLength; ClearCommError(m_pComm,&dwErrorFlags,&ComStat);if (ComStat.cbInQue>0){ bReadStat=ReadFile(m_pComm,lpszBlock,nMaxLength,&dwLength,&m_os);

if (!bReadStat) { // 当读操作未完成继续进行

if(GetLastError()==ERROR_IO_PENDING) { while(!GetOverlappedResult(m_pComm,&m_os,&dwL

ength,TRUE)) {if(GetLastError() == ERROR_IO_INCOMPLETE)

continue; }} else { dwLength=0;

ClearCommError(m_pComm,&dwErrorFlags,&ComStat); }} }

else dwLength=0;

Page 32: 串行通信机理 与 应用

32

多线程与串行通信的示例 结束串口通信 包括取消监视事件、中止读监视线程、清空缓冲区、关闭

串口等过程。 通信前,为串口设置了监视事件,那么在通信结束时就要取消这些监视。取消的方式是把 SetCommMask() 的掩码设置为 NULL 。通信结束,读监视线程的任务也就完成了,这时可调用 SuspendThread() 来中止该线程。通信结束与通信开始一样要清空缓冲区,并中止未竟的读写操作。PurgeComm() 的说明同前文。串口属于独占资源,所以在通信结束后应尽快调用 CloseHandle() 来关闭串口占用的内存句柄,释放资源。

Page 33: 串行通信机理 与 应用

33

扩展的串行通信编程 应用上述技术到如图 3所示的远程通信模型中,

两计算机能够有效实现扩展的串口通信,计算机与模块间能够正确区分数据和命令。目前,这种远程通信模型已成功应用于所开发虚拟现实系统的多机信息交换过程中,取得了较好效果。

Page 34: 串行通信机理 与 应用

34

扩展的串行通信编程 D22 无线数传模块通过天线可实现把从上位机(计算机)

接受的数据调制到特定频点而发射出去,同时,能把从空间接受到的某一频点的数据流放大解调成计算机能识别的二进制流,交由计算机处理。

D22 无线数传模块留有一个 DB-9 的插座,通过它可以与计算机连接,连接示意图如图 2示。

Page 35: 串行通信机理 与 应用

35

扩展的串行通信编程由于计算机需要对模块进行控制,而模块要对计

算机发出的命令作出响应,所以模块就要规定一种机制来区分数据和命令。这种机制在传送信息时通过信号线 DTR 或 DSR 的状态来标记信息的性质。协议的具体内容如表 2 。

Page 36: 串行通信机理 与 应用

36

扩展的串行通信编程 EscapeCommFunction 函数 EscapeCommFunction 可以驱使某一特定的通信设

备执行扩展功能。该函数可将 DTR 、 RTS 等硬件信号置ON或 OFF ,并能模拟 XON或 XOFF 。其原型如下:BOOL EscapeCommFunction(HANDLE hFile,DWOR

D dwFunc );参数说明如下:l hFile 通信设备(如串行口)的句柄。该句柄由 CreateFile()

函数返回。 l dwFunc 指定执行扩展功能所对应的宏值。 dwFunc 的有效宏值

(可用“ |”组合多个值)说明见MSDN。

Page 37: 串行通信机理 与 应用

37

扩展的串行通信编程 GetCommModemStatus

函数 GetCommModemStatus 可以获取Modem 控制寄存器的值,如可读取 DSR 、 CTS 的状态。其原型如下:

BOOL GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat);

参数说明如下:          hFile

通信设备(如串行口)的句柄。该句柄由 CreateFile() 函数返回。          lpModemStat

指向一个代表当前 Modem状态控制寄存器的值的变量。该参数的有效值(可用“ |”组合多个宏值)说明见MSDN 。

Page 38: 串行通信机理 与 应用

38

扩展的串行通信编程 计算机与无线数传模块间的通信要按硬件协议来

进行,则要对计算机发送信息和接收信息两种情况分别处理。

在计算机要发送信息时,首先要通过 GetCommModemStatus 函数来获取当前 DSR 的状态。只有当DSR 为 ON时,即模块空闲时,才可发送,且发送时设置 DTR 以标识信息的类型,完成后还要恢复 DTR 的状态。示例如下:

Page 39: 串行通信机理 与 应用

39

扩展的串行通信编程if (GetCommModemStatus(m_pComm,&dwModSta))

if (!(dwModSta|MS_DSR_ON))//判断空闲{

//硬件忙return ;

}if (!EscapeCommFunction(m_pComm,CLRDTR))// 设置 DTR{

//硬件错AfxAbort();

}// 可以发送信息InfoSend();// 发送信息if (!EscapeCommFunction(m_pComm,SETDTR))//恢复 DTR{

//硬件错AfxAbort();

}

Page 40: 串行通信机理 与 应用

40

扩展的串行通信编程 当计算机接收到信息时,首先要令 DTR 为高电平(表示上位机忙);读取信息时,同时要依据 DSR 的状态来判定信息的类型;读结束时,要恢复 DTR 的电平。具体过程如下:

//Step1 :读之前 EscapeCommFunction(pComm->m_hComm,CLRDTR);// 置 DTR 为高 // 系统忙状态

Page 41: 串行通信机理 与 应用

41

扩展的串行通信编程 //Step 2 :读的过程中 DWORD dwModStat; if (GetCommModemStatus(m_hComm,&dwModStat)) { if (!(dwModStat&MS_DSR_ON))//判断 DSR { // 信息为数据 } else { // 信息为命令 } } else { //出错处理 } //Step3 :读取后(完成) EscapeCommFunction(pComm->m_hComm,SETDTR);//恢复 DSR状态 // 以后为空闲状态

Page 42: 串行通信机理 与 应用

42

小结 串行通信定义与应用背景 串行通信系统的通用模型 串行接口配置 串行通信机理 多线程串行通信的编程 扩展的串行通信编程

Page 43: 串行通信机理 与 应用

43

The End!

参考资料:1. 苏统华 .项目管理精髓 . 程序员 ,2002,(4):39-43

2. 苏统华 . 多线程串行通信系统的研究 . 程序春秋 ,2003,(7):72-76

3. 苏统华 , 张田文 . 用况驱动开发过程的研究与应用 . 微机发展 .2003,(11):107-109,113

4. 其他未发表资料,见 : http://blog.hexun.com/maotong

Thanks for your attention