引言·串口通信是Windows应用软件开发的重要环节,除了普通的通信软件外,还在工业控制领域有广泛的用途,因此掌握串口编程是每个程序员的必备技巧。·无庸讳言,目前网上有不少介绍串口通信的文章和代码,但对广大读者而言,缺少入门的、系统的介绍串口编程的教程,因此小编组织了这个教程,它将填补这方面的空白。深入浅出VisualC++串口编程RS-232C接口,1970年由美国电子工业协会联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定,全名是数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准。本期教程将对DOS平台的串口编程,及Windows平台下基于API、控件和第三方类的串口编程进行介绍。深入浅出VC++串口编程之基本概念在PC机的主板上,有一种类型的接口可能为我们所忽视,那就是RS-232C串行接口,在微软的Windows系统中称其为COM。我们可以通过设备管理器来查看COM的硬件参数设置,如图1。图1在Windows上查看PC串口设置迄今为止,几乎每一台PC都包含COM。本质而言,COM是PC为和外界通信所提供的一种串行数据传输的接口。作为一种物理通信的途径和设备,它和目前风靡的另一种串行接口――USB所提供的功能是一致的。不过RS-232C显然已经开始被后起之秀USB赶超,因为USB的传输速率已经远远超过了RS-232C。尽管如此,RS-232C仍然具有非常广泛的应用,在相对长的一段时间里,难以被USB等接口取代。RS-232C接口(又称EIARS-232C),1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定,全名是数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准。本文将对这一接口进行硬件原理的介绍,随后我们将逐章学习DOS平台的串口编程,及Windows平台下基于API、控件和第三方类的串口编程,昀后本文将给出一个综合实例。硬件原理众所周知,CPU与存储芯片和I/O芯片的通信是并行的(并行传输的昀大位数依赖于CPU的字长、数据总线的宽度),一种叫做UART(通用异步收发器,UniversalAsynchronousReceiver/Transmitter)的芯片提供了并行数据传输和RS-232C串行数据传输方式的转换。这样的设备通常有如图2所示的管脚分布,当其向外传输数据时,CPU并行的将数据写入这类芯片的寄存器,UART再将寄存器中的数据一位一位地移动并向外传输;当外界向其传输数据时,UART一位一位地接收数据,并将其移位组合为并行数据,CPU再并行地读取这些数据。实际上,由于UART芯片一般以TTL/CMOS电平工作,在UART连接接口之前,还要经过一个TTL/CMOS和RS-232C电平的转换。RS-232C规定了其标准的电气特性,逻辑1对应的电压必须在-5~-15V之间;逻辑0对应的的电压必须在+5~+15V之间。图2UART并/串转换一个常见的TTL/CMOS和RS-232C电平转换芯片如图3。RS-232C通常以两类接插件与外界相连,分别称为DB9和DB25,如图4所示。图4DB9和DB25而接插件中各个针的定义则如表1:表1DB9和DB25引脚定义DB9DB25针号功能说明缩写针号功能说明缩写1数据载波检测DCD8数据载波检测DCD2接收数据RXD3接收数据RXD3发送数据TXD2发送数据TXD4数据终端准备DTR20数据终端准备DTR5信号地GND7信号地GND6数据设备准备好DSR6数据准备好DSR7请求发送RTS4请求发送RTS8清除发送CTS5清除发送CTS9振铃指示DELL22振铃指示DELLRS-232C定义为数据通信设备(DCE)和数据终端设备(DTE)之间的互连,实现上,到现在为止,究竟一个设备属于DCE还是属于DTE已经没有明显的界限,PC即可作为DCE,又可作为DTE。两串口互连,连接方法主要有二:一种方法是,数据的发送和接收由软件控制,不进行硬件握手,其连接方法如图5(昀常用DB9连接示意)和表2(DB9、DB25三线连接表),真正需要互相连接的是RXD、TXD和GND;图5无硬件握手时两串口连接表2DB9、DB25三线连接9针-9针5针-25针29针-25针233222322333557757软件握手又称为XON/XOFF,通常以CTRL-S(0x13)和CTRL-Q(0x11)两个字符来实现流控制。前者用于请求对方暂停发送,后者用于清除暂停传送的请求,继续发送数据。另一种方法是,数据的发送和接收由硬件控制,进行硬件握手,其连接方法如图6(昀常用DB9连接示意),需要连接的信号除RXD、TXD和GND外,还包括DTR、DSR、RTS和CTS。硬件握手依赖于RTS和CTS信号,当发送设备欲发送数据时,将RTS信号置为有效表示请求发送,接收设备准备好后,置CTS信号有效,接着发送设备通过信号线TXD开始发送串行数据。这里我们联想开来,RTS/CTS模式在许多领域里都出现过。回忆一下IEEE802.11无线局域网协议标准,在其MAC协议中就使用了RTS/CTS,RTS/CTS抽象开来就是一种请求/应答。笔者曾经在拙作中多次以实例论证计算机领域里许多知识的相通性,这又是一个明证。图6有硬件握手时两串口连接实际上,目前我们经常使用的是方法一,即只连接RXD、TXD和GND,简单灵活。另外,串口之间互连还有诸多途径,如图7所示。图7其它互连方式调试工具在MS-DOS下使用的编程环境是TC2.0;在Windows2000下的编程环境是VC++6.0;借助工具:串口调试助手2.1(图8)。图8串口调试助手串口调试助手是由《VisualC++/TurboC串口通信编程实践》一书作者龚建伟编写的共享软件,可以方便地进行串口上的数据收发、显示(16进制和ASCII码方式)和串口参数的设置,在串口调试领域应用广泛。串口调试助手的开发原理很简单(相信读者看完本文后在相当短的时间之内就能开发出这样的软件),但是作者龚建伟敏锐地抓住了串口调试在业界的需求,使得自身随这一软件而成名。这一事件或多或少会给程序员们一定的启发。优秀的共享软件不一定要技术含量高,只要有需求,哪怕是开发原理再简单,都能拥有广泛的使用者。为了在一台PC上同时搭建DOS和Windows平台,我们应该在Windows平台上安装虚拟PC的软件VmWare(图9,VMwareInc.版权所有,)。VMware的确是天才的作品!在同一PC上,利用VmWare几乎可以安装所有的操作系统,而且操作系统之间的切换不需要重新启动电脑,与传统的LILO等多系统引导方式有本质的不同。VM的意义是VirtualMachine,即虚拟出一个逻辑的电脑。图9VmWare虚拟PC在虚拟PC的MS-DOS操作系统上,我们安装TC2.0开发环境。如果您的PC上没有软驱,为了制作MS-DOS启动软盘,请安装RamDiskNT模拟一个软盘,并在其上安装MS-DOS启动程序。RamDiskNT是一个磁盘模拟软件,其界面如图10所示。图10磁盘模拟深入浅出VC++串口编程之DOS的串口编程在DOS平台下,操作串口主要有下列方式:通过BIOS调用、通过串口的硬件中断或通过对串口硬件进行轮询,本章将对以上三种方式进行具体的介绍并给出例子。1.BIOS中断在DOS操作系统下,IBMPC及其兼容机提供了一种灵活的串口I/O访问方法,即通过INT14H调用ROMBIOS串行通讯例行程序。当设置AH为不同的值时,产生不同的功能:AH0初始化端口AH1向串口写字符AH2从串口读字符AH3取通讯口状态初始化端口时(即当AH=0时),需要在AL寄存器中赋一字节初始化参数,其各项意义如图1;图1调用INT14H时AL寄存器设置当向串口写字符时(即当AH=1时),AL寄存器中的字符是需要写入的字符;当向串口写字符时(即当AH=2时),AL寄存器中的字符是需要读取的字符。看看下面的例程:#includestdio.h#includedos.h#includebios.h#defineSTRauthor:sbhunionREGSinregs,outregs;main(){//设置串口参数init_rs232();//写串口的例子write_rs232(STR,strlen(STR));//读串口的例子read_rs232();return(0);}init_rs232(){do{inregs.h.ah=0;//AH=0表示初始化端口inregs.h.al=0xe7;inregs.x.dx=0;//COM1int86(0x14,&inregs,&outregs);}while(outregs.h.ah=0x80);return(0);}write_rs232(char*string,intlen){inti;do{inregs.h.ah=1;//发送AL寄存器的字符inregs.h.al=*string;inregs.x.dx=0;int86(0x14,&inregs,&outregs);}while(outregs.h.al=0x80);for(i=1;ilen;i++){inregs.h.ah=1;inregs.h.al=*(string+i);inregs.x.dx=0;int86(0x14,&inregs,&outregs);}}read_rs232(){do{inregs.h.ah=2;//读取AL寄存器中的字符inregs.x.dx=0;int86(0x14,&inregs,&outregs);}while(outregs.h.al!=3||outregs.h.ah=0x80);return(0);}其中使用的int86函数的原型为:int_Cdeclint86(intintno,unionREGS*inregs,unionREGS*outregs);int86()函数可以调用BIOS功能,现在的程序员们已经很少接触这个函数,80%的程序员甚至都未曾见过这个函数。其实,在茹毛饮血的DOS时代,int86()函数几乎是昀常用和昀核心的函数之一。几乎可以说,在那个时代,不会int86()就等于不会编程。而与int86配合使用的,就是REGS这样一个联合体,定义为:unionREGS{structWORDREGSx;structBYTEREGSh;};其中的WORDREGS定义为:structWORDREGS{unsignedintax,bx,cx,dx,si,di,cflag/*进位标志*/,flags/*标志寄存器*/;};而BYTEREGS则定义为:structBYTEREGS{unsignedcharal,ah,bl,bh,cl,ch,dl,dh;};原来WORDREGS和BYTEREGS是16位的8086处理器内部的寄存器啊!因此,当CPU发展到286、386以后,再安装DOS也是建立在利用CPU实模式的基础上的!另外一个函数与int86()的功能是类似的:Int_Cdeclint86x(intintno,unionREGSinregs,unionREGSoutregs,structSREGSsegregs);其中的SREGS为段寄存器结构体,定义为:structSREGS{unsignedintes;unsignedintcs;unsignedintss;unsignedintds;};int86和int86x这两个函数的功能都是执行一个由参数intno指定的8086软中断。在执行软中断之前,两个函数都把inregs中的内容放置到各寄存器中(int86x还把segregs.x.es和segregs.x.ds的值存到相应的段寄存器中),软中断返回后,这两个函数都把当前寄存器的值存到outregs,并把系统进位标志拷贝到outregs.s.cflag中,把8086标志寄存器值存到outregs.x.flag