微型机与应用
MICROCOMPUTER & ITS APPLICATIONS
1999年 第18卷 第4期 Vol.18 No.4 1999



在Windows95下实现PC机与单片机AT89C51的串行通信
黄海容　黄继武　袁兰英　王来运　余　进
　　摘　要：在Windows95下使用串口API函数实现PC机与单片机AT89C51的串口通信，重点介绍计算机采用事件驱动I/O方式的函数编程及单片机串口中断发送、接收程序的实现。
　　关键词：Windows95　单片机AT89C51　RS-232接口　RS-485接口　串行通信
　　在以单片机为基础的数据采集和实时控制系统中，通过计算机中的RS-232接口进行计算机与单片机之间的命令和数据传送，就可以利用计算机对生产现场进行监测和控制。由于计算机上的RS-232所传送的距离不超过30m，所以，在远距离的数据传送和控制时，可以用MAX485的接口转换芯片将RS-232转换成RS-485协议进行远距离传送。在发送和接收端都进行协议转换后，RS-485协议对数据传送来说是相对透明的，所以依然可以使用计算机中的RS-232进行远距离的数据传送和控制。在最简单的RS-232直接传送通信系统中，只要发送和接收双方同时准备好，仅用信号发送端(TXD)，信号接收端(RXD)和信号地(GND)3根线即可进行通信；若以应答方式进行数据通信，可使用请求发送(RTS)、清除发送(CTS)或数据终端准备(DTR)、数据装置准备(DSR)进行硬件握手。在Windows95下，可以很方便地使用Win32通信API函数来实现这些硬件的握手以及数据的传送。在89C51单片机系统中，分别从P3.0和P3.1引出串口线RXD和TXD通过专用的电平转换芯片转换成RS-232接口标准的电平，这样，二者之间就可以通过RS-232接口进行数字信号的传送。单片机也可以以直接传送或应答握手的方式进行数据通信，但由于握手方式占用其他的端口，而单片机的端口数量有限，所以，计算机与单片机的通信常采用直接传送的方式，本文将重点介绍。
1　Windows95下的通信编程
　　Windows95通信体系提供了1个改进的串行应用程序接口SAPI用来进行交互式串行通信。其中，串口和其他通信设备是作为文件进行处理的，串口的打开、关闭、读取和写入所用的函数和操作文件的函数相同。
　　通信会话以调用CreateFile函数开始，CreateFile函数为读访问或写访问打开串口，打开成功后返回该串口句柄，供读写串口时使用。CreateFile函数的使用如下：
CreateFile(szDevice,fdwAccess,fdwShareMode,lpsa,fdwCreate,fdwAttrsAndFlags,hTemplateFile)
　　其中，第1个参数szDevice是要打开的串口逻辑名，如COM1或COM2；第2个参数fdwAccess指定串口的访问类型，如读、写或两者兼而有之，大部分通信是双向的，因而通常设置为：GENERICREAD｜GENERICWRITE；第3个参数fdwShareMode指定串口的共享属性，串口不能共享，所以它必须为0；第4个参数lpsa引用安全性属性结构；第5个参数fdwCreate指定如果CreateFile正被已有的文件调用时应做些什么，既然串口总是存在，此参数就必须被设置为OPENEXISTING。第6个参数fdwAttrsAndFlags描述了该端口的各种属性，对串口而言，唯一有意义的设置是FILEFLAGOVERLAPPED，指定该设置时，端口I/O可以在后台进行；最后1个参数hTemplateFile是指向模板文件的句柄，当端口打开时，该参数为NULL。
　　打开串口后，在Windows95下可以对串口进行合适的配置。Windows95提供了COMMPROP结构，COMMPROP结构中包含了对串口允许的设置，如波特率、数据位数、停止位的个数以及奇偶校验方法等，如果串口连接到调制解调器，COMMPROP结构中还包含调制解调器支持的设置。但COMMPROP结构给出的只是单纯的信息，它不能用来改变串口的设置。Windows95下串口设置的改变是通过改变它的DCB结构来实现的，DCB结构中包含了所有串口的设置，其中包括硬件的握手、流控制等。
　　Windows95提供GetCommState函数来得到当前串口的设置情况，该函数接收1个打开的端口句柄和1个指向DCB结构的指针，在DCB结构中返回信息，GetCommState函数的补充函数是SetCommState函数，SetCommState函数将DCB结构中的内容写向串口设置，这2个函数的调用如下：
　　BOOLGetCommState(hComm,&dcb)
　　BOOLSetCommState(hComm,&dcb)
　　其中，hComm为打开串口的句柄，dcb为1个指向DCB的结构。
　　Windows95中实现串口的读写函数与文件的读写函数相同，读写函数的使用格式如下：
　　ReadFile(hComm,inbuff,nBytes,&nBytesRead,&overlapped)
　　WriteFile(hComm,outbuff,nBytes,&nBytesWrite,&overlapped)
　　其中，第1个参数是打开串口的句柄，第2个参数是数据所使用的缓冲区，第3个参数是要读取的字节数，第4个参数是实际读取的字节数，实际读取的字节数可能小于要读取的字节数，最后1个参数指向1个覆盖似的结构，当CreateFile中dwAttrsAndFlags参数设置为FILEFLAGOVERLAPPED时，此参数可以指定1个OVERLAPPED结构，使数据的读写操作在后台进行。
　　读写端口可以通过4种技术来实现：查询、同步I/O、异步I/O(后台I/O)和事件驱动I/O。查询方式直接、易于理解，但占用大量CPU时间；同步I/O直到读取所指定字节数或超时时才返回，这样很容易长时间地阻塞线程；异步I/O可以在后台读写数据，而在前台做其他的事情；事件驱动I/O是由Windows95通知应用程序某些事件什么时候发生，然后根据所发生的事情来对串口进行操作。
　　这4种不同的技术，各有利弊和自己适用的领域，所以，在不同的通信系统中，可以根据不同的要求采用不同的技术。在监测系统中，由于事件的偶然性和要求传送的实时性，计算机常采用事件驱动I/O方式来进行现场监测。
　　在事件驱动I/O方式下，Windows95报告给应用程序的事件由函数GetCommMask返回，改变返回的事件时，可以使用SetCommMask函数设置，这2个函数的调用如下：
　　GetCommMask(hComm,&dwMask)
　　SetCommMask(hComm,dwMask)
　　第1个参数是打开串口的句柄，第2个参数是要等待的1个或多个事件的掩码。在用SetCommMask设置了有用的事件后，应用程序调用WaitCommEvent函数来等待事件的发生，直到事件发生，WaitCommEvent函数返回。WaitCommEvent函数使用格式如下：
　　WaitCommEvent(hComm,&dwEvent,&overlapped)
　　第1个参数是打开串口的句柄，第2个参数是返回的事件，第3个参数是指定同步或者异步操作。当函数返回后，可根据返回的事件掩码进行相应的串口操作。
　　完成通信后，串口应该关闭，否则，它始终处于打开状态，其他应用程序就不能打开或使用它。关闭串口的函数为：CloseHandle(hComm)，其中，hComm为打开的串口句柄。
2　单片机下的通信编程
　　单片机89C51的串行端口有4种工作方式，通过编程设计，可以使其工作在任一方式，以满足不同场合的需要。其中，方式0主要用于外接移位寄存器，以扩展单片机的I/O电路；方式1主要用于双机之间或外设电路的通信；方式2、3除有方式1的功能外，还可用作多机通信，以构成多微机系统，方式2、3的区别在于波特率的不同。
　　单片机的串行通信的波特率可以程控设定，在不同的工作方式下，由时钟振荡频率的分频值或由定时器T1的定时溢出时间确定。
　　单片机的串行端口有2个控制寄存器，用来设置工作方式、发送或接收的状态、特征位、数据传送的波特率以及中断标志TI和RI。
　　单片机的串行端口有1个数据寄存器SBUF，该寄存器为发送和接收所共有，在一定条件下，向SBUF写入数据就启动了发送过程，读SBUF就启动了接收过程。
　　单片机可以采用循环方式或中断方式实现串行数据的传送。在循环方式下，单片机循环对数据寄存器SBUF进行读写来实现数据的接收和发送；在中断方式下，对方式1、2来说，1帧数据发送或接收完后，TI/RI自动置1，请求串行中断，若CPU响应中断，则执行串行中断服务程序，并把TI/RI清0以再次响应中断。对在方式2、3下的接收，还要视串口控制寄存器SCON的设置才可确定RI是否被置位以及串口中断是否开放。
　　实时控制中，由于事件的突发性，常采用中断的方式进行数据传送，中断方式能更大限度地提高资源的利用率，使CPU在不进行数据通信时做其他的工作。下面重点介绍单片机在方式1下的中断方式编程。
　　方式1是10位异步通信方式，其中包括1个起始位，8个数据位和1个停止位。波特率由定时器T1的溢出率和串口控制寄存器SMOD的状态确定，在CPU的晶振为11.0592MHz时，波特率常采用9600b/s。
　　对SBUF进行写操作就可启动发送，在发送移位时钟的同步下，从TXD先送出起始位，然后是8位数据位，最后是停止位，这样，1帧数据发送完，中断标志TI置位。
　　在允许接收的条件下(REN＝1)，当RXD出现由1到0的负跳变时，即被当成是串行发送来的1帧数据的起始位，从而启动1次接收过程。当8位数据接收完，并检测到高电平停止位后，即把收到的8位数据装入SBUF，置位RI，1帧数据的接收过程就完成了。
　　下面是单片机以方式1在直接传送下的中断接收和发送程序。由于没有使用通信握手，所以通信双方都应做好通信准备。在计算机接收、单片机发送时，由计算机先发送字母“R”，通知单片机计算机已准备好，然后计算机在事件驱动I/O方式下等待接收到字符“Y”；当单片机接收到“R”时，向计算机发送“Y”，表示单片机也已准备好，这样，一旦计算机接收到“Y”就表示双方都已准备好，二者之间就可以进行数据交换了。在计算机发送、单片机接收时，计算机发送1帧数据，单片机响应中断，接收数据。单片机程序的具体实现过程如下：
　　org　0000h
　　ajmpstart
　　org0023h　　；串行中断入口
　　ljmps&r
　　org0100h
start:mov　tmod,#20h　；设置定时器T1方式2
　　movpcon,#00h；使SMOD为0
　　movtll,#0fdh；波特率为9600b/s
　　movthl,#0fdh
　　setbea；开全局中断
　　clret1；关T1中断
　　setbes；开串行中断
　　setbtrl；开T1定时
　　movscon,#50h；串行方式1，允许接收
　　sjmp$
S&r:movc,ri
　　jcrecive;RI为1，执行接收子程序
　　sjmpsend；否则，执行发送子程序
recive:mova,sbuf；接收数据
　　clrri
　　cjnea,#52h,re；是否接收到“R”
　　mova,#59h；是，发送“Y”
　　movsbuf,a
　　sjmpendtr
re:mov　@rl,a　　；r1为接收数据存放地址
　　incr1
　　sjmpendtr
send:mova,@r0；发送数据，r0为存放数据的地址
　　movsbuf,a
　　jnbti,$
　　clrti
　　incr0
endtr:reti；中断返回
3　结束语
　　串口通信是一种广泛应用于各个领域的通信方式，由于目前大部分计算机都安装了Windows95操作系统，所以本文具体实现了在Windows95下利用它的SDK函数来与单片机进行串口通信。本文所提出的实现函数在所有当前流行软件如VC++、Delphi等中都可实现。它不仅可以用于近距离的RS-232通信，而且，还可以实现中远距离RS-485通信。在使用该程序的通信系统中，近远距离的通信都取得良好的效果。
作者单位：武汉大学电子信息学院(430072)
参考文献
　1　MirhoCA,TerrisseA著，贺军，高胜友译.WINDOWS95通信编程.北京：清华大学出版社，1997
　2　陈光东，赵性初.单片微型计算机原理与接口技术.武汉：华中理工大学出版社，1993
收稿日期：1998-10-10
