vc Win32 API实现串行通信.docx
《vc Win32 API实现串行通信.docx》由会员分享,可在线阅读,更多相关《vc Win32 API实现串行通信.docx(15页珍藏版)》请在冰豆网上搜索。
vcWin32API实现串行通信
串口是常用的计算机与外部串行设备之间的数据传输通道,由于串行通信方便易行,所以应用广泛。
我们可以利用WindowsAPI提供的通信函数编写出高可移植性的串行通信程序。
本实例介绍在VisualC++6.0下如何利用Win32API实现串行通信程序。
程序编译运行后的界面效果如图一所示:
图一、串口通信示例程序
一、实现方法
在Win16中,可以利用OpenComm()、CloseComm()和WriteComm()等函数打开、关闭和读写串口。
但在Win32中,串口和其他通信设备均被作为文件处理,串口的打开、关闭和读写等操作所用的API函数与操作文件的函数相同。
可通过CreateFile()函数打开串口;通过CloseFile()函数关闭串口;通过DCB结构、CommProp()、GetCommProperties()、SetCommProperties()、GetCommState()及SetCommState()等函数设置串口状态,通过函数ReadFile()和WritFile()等函数读写串口。
下面来详细介绍其实现原理。
对于串行通信设备,Win32API支持同步和异步两种I/O操作。
同步操作方式的程序设计相对比较简单,但I/O操作函数在I/O操作结束前不能返回,这将挂起调用线程,直到I/O操作结束。
异步操作方式相对要复杂一些,但它可让耗时的I/O操作在后台进行,不会挂起调用线程,这在大数据量通信的情况下对改善调用线程的响应速度是相当有效的。
异步操作方式特别适合同时对多个串行设备进行I/O操作和同时对一个串行设备进行读/写操作。
串行设备的初始化
串行设备的初始化是利用CreateFile()函数实现的。
该函数获得串行设备句柄并对其进行通信参数设置,包括设置输出/接收缓冲区大小、超时控制和事件监视等。
例如下面的代码实现了串口的初始化:
//串行设备句柄;
HANDLEhComDev=0;
//串口打开标志;
BOOLbOpen=FALSE;
//线程同步事件句柄;
HANDLEhEvent=0;
DCBdcb;
COMMTIMEOUTStimeouts;
//设备已打开
if(bOpen)returnFALSE;
//打开COM1
if((hComDev=CreateFile(“COM1”,GENERIC?
READ|GENERIC?
WRITE,0,NULL,OPEN?
EXISTING,FILE?
ATTRIBUTE?
NORMAL,NULL))==INVALID?
HANDLE?
VALUE)
returnFALSE;
//设置超时控制
SetCommTimeouts(hComDev,&timeouts);
//设置接收缓冲区和输出缓冲区的大小
SetupComm(hComDev,1024,512);
//获取缺省的DCB结构的值
GetCommState(hComDev,&dcb);
//设定波特率为9600bps
dcb.BaudRate=CBR?
9600;
//设定无奇偶校验
dcb.fParity=NOPARITY;
//设定数据位为8
dcb.ByteSize=8;
//设定一个停止位
dcb.StopBits=ONESTOPBIT;
//监视串口的错误和接收到字符两种事件
SetCommMask(hComDev,EV?
ERR|EV?
RXCHAR);
//设置串行设备控制参数
SetCommState(hComDev,&dcb);
//设备已打开
bOpen=TRUE;
//创建人工重设、未发信号的事件
hEvent=CreateEvent(NULL,FALSE,FALSE,
“WatchEvent”);
//创建一个事件监视线程来监视串口事件
AfxBeginThread(CommWatchProc,pParam);
}
在设置串口DCB结构的参数时,不必设置每一个值。
首先读出DCB缺省的参数设置,然后只修改必要的参数,其他参数都取缺省值。
由于对串口进行的是同步I/O操作,所以除非指定进行监测的事件发生,否则WaitCommEvent()函数不会返回。
在串行设备初始化的最后要建立一个单独的监视线程来监视串口事件,以免挂起当前调用线程,其中pParam可以是一个对事件进行处理的窗口类指针。
如果要进行异步I/O操作,打开设备句柄时,CreateFile的第6个参数应增加FILE?
FLAG?
OVERLAPPED标志。
数据发送
数据发送利用WriteFile()函数实现。
对于同步I/O操作,它的最后一个参数可为NULL;而对异步I/O操作,它的最后一个参数必需是一个指向OVERLAPPED结构的指针,通过OVERLAPPED结构来获得当前的操作状态。
BOOLWriteComm(LPCVOIDlpSndBuffer,DWORDdwBytesToWrite)
{
//lpSndBuffer为发送数据缓冲区指针,
dwBytesToWrite为将要发送的字节长度
//设备已打开
BOOLbWriteState;
//实际发送的字节数
DWORDdwBytesWritten;
//设备未打开
if(!
bOpen)returnFALSE;
bWriteState=WriteFile(hComDev,lpSndBuffer,dwBytesToWrite,&dwBytesWritten,NULL);
if(!
bWriteState||dwBytesToWrite!
=dwBytesWritten)
//发送失败
returnFALSE;
else
//发送成功
returnTRUE;
}
数据接收
接收数据的任务由ReadFile函数完成。
该函数从串口接收缓冲区中读取数据,读取数据前,先用ClearCommError函数获得接收缓冲区中的字节数。
接收数据时,同步和异步读取的差别同发送数据是一样的。
DWORDReadComm(LPVOIDlpInBuffer,DWORDdwBytesToRead)
{
//lpInBuffer为接收数据的缓冲区指针,dwBytesToRead为准备读取的数据长度(字节数)
//串行设备状态结构
COMSTATComStat;
DWORDdwBytesRead,dwErrorFlags;
//设备未打开
if(!
bOpen)return0;
//读取串行设备的当前状态
ClearCommError(hComDev,&dwErrorFlags,&ComStat);
//应该读取的数据长度
dwBytesRead=min(dwBytesToRead,ComStat.cbInQue);
if(dwBytesRead>0)
//读取数据
if(!
ReadFile(hComDev,lpInBuffer,dwBytesRead,&dwBytesRead,NULL))
dwBytesRead=0;
returndwBytesRead;
}
事件监视线程
事件监视线程对串口事件进行监视,当监视的事件发生时,监视线程可将这个事件发送(SendMessage)或登记(PostMessage)到对事件进行处理的窗口类(由pParam指定)中。
UINTCommWatchProc(LPVOIDpParam)
{
DWORDdwEventMask=0;//发生的事件;
while(bOpen)
{
//等待监视的事件发生
WaitCommEvent(hComDev,&dwEventMask,NULL);
if((dwEventMask&EV?
RXCHAR)==EV?
RXCHAR)
……//接收到字符事件后,可以将此消息登记到由pParam有指定的窗口类中进行处理
if(dwEventMask&EV?
ERR)==EV?
ERROR)
……//发生错误时的处理
}
SetEvent(hEvent);
//发信号,指示监视线程结束
return0;
}
关闭串行设备
在整个应用程序结束或不再使用串行设备时,应将串行设备关闭,包括取消事件监视,将设备打开标志bOpen置为FALSE以使事件监视线程结束,清除发送/接收缓冲区和关闭设备句柄。
voidCloseSynComm()
{
if(!
bOpen)return;
//结束事件监视线程
bOpen=FALSE;
SetCommMask(hComDev,0);
//取消事件监视,此时监视线程中的WaitCommEvent将返回
WaitForSingleObject(hEvent,INFINITE);
//等待监视线程结束
CloseHandle(hEvent);//关闭事件句柄
//停止发送和接收数据,并清除发送和接收缓冲区
PurgeComm(hComDev,PURGE?
TXABORT|PURGE?
RXABORT|PURGE?
TXCLEAR|PURGE?
RXCLEAR);
//关闭设备句柄
CloseHandle(hComDev);
}
二、编程步骤
1、启动VisualC++6.0,生成一个基于对话框的的应用程序,将该程序命名为“SerealCom”;
2、按照图一的界面设计对话框,具体设置参见代码部分;
3、使用ClassWizard为对话框的按钮添加鼠标单击消息响应函数;
4、添加代码,编译运行程序。
三、程序代码
//////////////////////////////////////////////////////////////
#if!
defined(_COMM_ACCESS_FUNCTIONS_AND_DATA)
#define_COMM_ACCESS_FUNCTIONS_AND_DATA
#if_MSC_VER>1000
#pragmaonce
#endif//_MSC_VER>1000
#defineEVENTCHAR0x0d
#defineMAXBLOCKLENGTH59
externBYTEXwCom;
externBYTEsCom1[5],sCom2[MAXBLOCKLENGTH+12];
externsCom3[MAXBLOCKLENGTH+12];
externBYTEopation;
externshortComNum;
#defineFC_DTRDSR0x01
#defineFC_RTSCTS0x02
#defineFC_XONXOFF0x04
#defineASCII_BEL0x07
#defineASCII_BS0x08
#defineASCII_LF0x0A
#defineASCII_CR0x0D
#defineASCII_XON0x11
#defineASCII_XOFF0x13
classCComStatus
{
public:
HANDLEm_hCom;
BYTEm_bComId;
BYTEm_bByteSize;
BYTEm_bStopBits;
BYTEm_bParity;
DWORDm_dwBaudRate;
//WORDm_fChEvt;
charm_bEvtChar;
DWORDm_fBinary;
BOOLm_bConnected;
BOOLm_fXonXoff;
BOOLm_bFlowCtrl;
OVERLAPPEDm_rdos;
OVERLAPPEDm_wtos;
//functions
CComStatus();
CComStatus(BYTEbComId,BYTEbByteSize,BYTEbStopBits,BYTEbParity,
DWORDdwBaudRate,/*WORDfChEvt,*/charbEvtChar,DWORDfBinary);
BOOLOpenConnection();
BOOLCloseConnection();
BOOLSetupConnection();
BOOLIsConnected();
};
UINTCommWatchProc(LPVOIDlpData);
BOOLWriteCommBlock(CComStatus&comDev,LPSTRlpByte,DWORDdwBytesToWrite);
intReadCommBlock(CComStatus&comDev,LPSTRlpszBlock,intnMaxLength);
intReadCommBlockEx(CComStatus&comDev,LPSTRlpszBlock,intnMaxLength,DWORDdwTimeOut);
#endif
///////////////////////////////////////////////////////////////////////
#include"stdafx.h"
#include"com232.h"
BYTEXwCom=0x40;
BYTEsCom1[5],sCom2[MAXBLOCKLENGTH+12],sCom3[MAXBLOCKLENGTH+12];
BYTEopation;
shortComNum;
CComStatus:
:
CComStatus()
{
m_hCom=NULL;
m_bComId=(char)ComNum;//COM1
m_bByteSize=8;
m_bStopBits=ONESTOPBIT;
m_bParity=NOPARITY;
m_dwBaudRate=9600;
m_bEvtChar=EVENTCHAR;
m_fBinary=1;
m_bConnected=FALSE;
m_bFlowCtrl=FC_XONXOFF;
m_fXonXoff=FALSE;
}
CComStatus:
:
CComStatus(BYTEbComId,BYTEbByteSize,BYTEbStopBits,BYTEbParity,DWORDdwBaudRate,/*WORDfChEvt,*/charbEvtChar,DWORDfBinary)
{
m_hCom=NULL;
m_bComId=bComId;
m_bByteSize=bByteSize;
m_bStopBits=bStopBits;
m_bParity=bParity;
m_dwBaudRate=dwBaudRate;
m_bEvtChar=bEvtChar;
m_fBinary=fBinary;
m_bConnected=FALSE;
m_bFlowCtrl=FC_XONXOFF;
m_fXonXoff=FALSE;
}
BOOLCComStatus:
:
OpenConnection()
{
charcsCom[10];
COMMTIMEOUTSCommTimeOuts;
if((m_bComId<0)||(m_bComId>4))
returnFALSE;//从COM1到COM4
if(m_hCom)//ifalreadyopen
returnFALSE;
//OVERLAPPED包含异步I/O信息
m_rdos.Offset=0;
m_rdos.OffsetHigh=0;
m_rdos.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if(m_rdos.hEvent==NULL)
returnFALSE;
m_wtos.Offset=0;
m_wtos.OffsetHigh=0;
m_wtos.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if(m_wtos.hEvent==NULL)
{
CloseHandle(m_rdos.hEvent);
returnFALSE;
}
wsprintf(csCom,"COM%d",m_bComId);
m_hCom=CreateFile(csCom,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,ILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,NULL);
if(m_hCom==INVALID_HANDLE_VALUE){
//dwError=GetLastError();
//handleerror
returnFALSE;
}
else
{
SetCommMask(m_hCom,EV_RXCHAR);//getanyearlynotifications
SetupComm(m_hCom,4096,4096);//setupdevicebuffers
//purgeanyinformationinthebuffer
PurgeComm(m_hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
//setupforoverlappedI/O
DWORDdwTemp=1000/(this->m_dwBaudRate/8);
CommTimeOuts.ReadIntervalTimeout=0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier=0;//((dwTemp>0)?
dwTemp:
1);
CommTimeOuts.ReadTotalTimeoutConstant=1000;
//CBR_9600isapproximately1byte/ms.Forourpurposes,allow
//doubletheexpectedtimepercharacterforafudgefactor.
CommTimeOuts.WriteTotalTimeoutMultiplier=2*CBR_9600/this->m_dwBaudRate;//(npTTYInfo);
CommTimeOuts.WriteTotalTimeoutConstant=0;//1000;
SetCommTimeouts(m_hCom,&CommTimeOuts);
}
if(!
SetupConnection())
{
CloseConnection();
returnFALSE;
}
EscapeCommFunction(m_hCom,SETDTR);
m_bConnected=TRUE;
returnTRUE;
}
BOOLCComStatus:
:
CloseConnection()
{
if(NULL==m_hCom)
return(TRUE);
//setconnectedflagtoFALSE
m_bConnected=FALSE;
//disableeventnotificationandwaitforthread
//tohalt
SetCommMask(m_hCom,0);
EscapeCommFunction(m_hCom,CLRDTR);
//purgeanyoutstandingreads/writesandclosedevicehandle
PurgeComm(m_hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
CloseHandle(m_hCom);
m_hCom=NULL;
//changetheselectableitemsinthemenu
CloseHandle(m_rdos.hEvent);
CloseHandle(m_wtos.hEvent);
return(TRUE);
}
BOOLCComStatus:
:
SetupConnection()
{
BOOLfRetVal;
BYTEbSet;
DCBdcb;
if(m_hCom==NULL)
returnFALSE;
dcb.DCBlength=sizeof(DCB);
GetCommState(m_hCom,&dcb);
dcb.BaudRate=this->m_dwBaudRate;
dcb.ByteSize=this->m_bByteSize;
dcb.Parity=this->m_bParity;
dcb.StopBits=this->m_bStopBits;
dcb.EvtChar=this->m_bEvtChar;
//setuphardwareflowcontrol
bSet=(BYTE)((m_bFlowCtrl&FC_DTRDSR)!
=0);
dcb.fOutxDsrFlow=bSet;
if(bSet)
dcb.fDtrControl=DTR_CONTROL_HANDSHAKE;
else
dcb.fDtrControl=DTR_CONTROL_ENABLE;
bSet=(BYTE)((m_bFlowCtrl&FC_RTSCTS)!
=0);
dcb.fOutxCtsFlow=bSet;
if(bSet)