VC++串口编程基于Win32 API.docx
- 文档编号:23716889
- 上传时间:2023-05-20
- 格式:DOCX
- 页数:17
- 大小:21.12KB
VC++串口编程基于Win32 API.docx
《VC++串口编程基于Win32 API.docx》由会员分享,可在线阅读,更多相关《VC++串口编程基于Win32 API.docx(17页珍藏版)》请在冰豆网上搜索。
VC++串口编程基于Win32API
在WIN32API中,串口使用文件方式进行访问,其操作的API基本上与文件操
作的API一致。
Win32中用于打开串口的API函数为CreateFile,其原型为:
HANDLECreateFile(
LPCTSTRlpFileName,//将要打开的串口逻辑名,如COM1或COM2
DWORDdwAccess,//指定串口访问的类型,可以是读取、写入或两者并列
DWORDdwShareMode,//指定共享属性,由于串口不能共享,该参数必须置为0
LPSECURITY_ATTRIBUTESlpsa,//引用安全性属性结构,缺省值为NULL
DWORDdwCreate,//创建标志,对串口操作该参数必须置为OPENEXISTING
DWORDdwAttrsAndFlags,//属性描述,用于指定该串口是否可进行异步操作,
//FILE_FLAG_OVERLAPPED:
可使用异步的I/O
HANDLEhTemplateFile//指向模板文件的句柄,对串口而言该参数必须置为NULL
);例如,以下程序用于以同步读写方式打开串口COM1:
HANDLEhCom;
DWORDdwError;
hCon=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,
NULL);
if(hCom==(HANDLE)0xFFFFFFFF)
{
dwError=GetLastError();
MessageBox(dwError);
}对于dwAttrsAndFlags参数及FILE_FLAG_OVERLAPPED标志的由来,可解释如下:
Windows文件操作分为同步I/O和重叠I/O(OverlappedI/O)两种方式,在同步I/O
方式中,API会阻塞直到操作完成以后才能返回(在多线程方式中,虽然不会阻塞
主线程,但是仍然会阻塞监听线程);而在重叠I/O方式中,API会立即返回,操
作在后台进行,避免线程的阻塞。
重叠I/O非常灵活,它也可以实现阻塞(例如我
们可以设置一定要读取到一个数据才能进行到下一步操作)。
如果进行I/O操作的
API在没有完成操作的情况下返回,我们可以通过调用GetOverLappedResult()函
数阻塞到I/O操作完成后返回。
T
配置串口是通过改变设备控制块DCB(DeviceControlBlock)的成员变量值来
实现的,接收缓冲区和发送缓冲区的大小可通过SetupComm函数来设置。
DCB结构体定义为:
typedefstruct_DCB{//dcb
DWORDDCBlength;//sizeof(DCB)
DWORDBaudRate;//currentbaudrate
DWORDfBinary:
1;//binarymode,noEOFcheck
DWORDfParity:
1;//enableparitychecking
DWORDfOutxCtsFlow:
1;//CTSoutputflowcontrol
DWORDfOutxDsrFlow:
1;//DSRoutputflowcontrol
DWORDfDtrControl:
2;//DTRflowcontroltype
DWORDfDsrSensitivity:
1;//DSRsensitivity
DWORDfTXContinueOnXoff:
1;//XOFFcontinuesTx
DWORDfOutX:
1;//XON/XOFFoutflowcontrol
DWORDfInX:
1;//XON/XOFFinflowcontrol
DWORDfErrorChar:
1;//enableerrorreplacement
DWORDfNull:
1;//enablenullstripping
DWORDfRtsControl:
2;//RTSflowcontrol
DWORDfAbortOnError:
1;//abortreads/writesonerror
DWORDfDummy2:
17;//reserved
WORDwReserved;//notcurrentlyused
WORDXonLim;//transmitXONthreshold
WORDXoffLim;//transmitXOFFthreshold
BYTEByteSize;//numberofbits/byte,4-8
BYTEParity;//0-4=no,odd,even,mark,space
BYTEStopBits;//0,1,2=1,1.5,2
charXonChar;//TxandRxXONcharacter
charXoffChar;//TxandRxXOFFcharacter
charErrorChar;//errorreplacementcharacter
charEofChar;//endofinputcharacter
charEvtChar;//receivedeventcharacter
WORDwReserved1;//reserved;donotuse
}DCB;
而SetupComm函数的原型则为:
BOOLSetupComm(
HANDLEhFile,//handletocommunicationsdevice
DWORDdwInQueue,//sizeofinputbuffer
DWORDdwOutQueue//sizeofoutputbuffer
);E以下程序将串口设置为:
波特率为9600,数据位数为7位,停止位为2位,偶
校验,接收缓冲区和发送缓冲区大小均为1024个字节,最后用PurgeComm函数终止
所有的后台读写操作并清空接收缓冲区和发送缓冲区:
DCBdcb;
dcb.BaudRate=9600;//波特率为9600
dcb.ByteSize=7;//数据位数为7位
dcb.Parity=EVENPARITY;//偶校验
dcb.StopBits=2;//两个停止位
dcb.fBinary=TRUE;
dcb.fParity=TRUE;
if(!
SetCommState(hCom,&dcb))
{
MessageBox("串口设置出错!
");
}
SetupComm(hCom,1024,1024);
PurgeComm(hCom,PURCE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
超时设置是通过改变COMMTIMEOUTS结构体的成员变量值来实现的,
COMMTIMEOUTS的原型为:
typedefstruct_COMMTIMEOUTS
{
DWORDReadIntervalTimeout;//定义两个字符到达的最大时间间隔,单位:
毫秒
//当读取完一个字符后,超过了ReadIntervalTimeout,仍未读取到下一个字符,就会
//发生超时
DWORDReadTotalTimeoutMultiplier;
DWORDReadTotalTimeoutConstant;
//其中各时间所满足的关系如下:
//ReadTotalTimeout=ReadTotalTimeOutMultiplier*BytesToRead+
ReadTotalTimeoutConstant
DWORDWriteTotalTimeoutMultiplier;
DWORDWriteTotalTimeoutConstant;
}COMMTIMEOUTS,*LPCOMMTIMEOUTS;
设置超时的函数为SetCommTimeouts,其原型中接收COMMTIMEOUTS的指针为参
数:
BOOLSetCommTimeouts(
HANDLEhFile,//handletocommunicationsdevice
LPCOMMTIMEOUTSlpCommTimeouts//pointertocommtime-outstructureharacter
charEvtChar;//received);
以下程序将串口读操作的超时设定为10毫秒:
COMMTIMEOUTSto;
memset(&to,0,sizeof(to));
to.ReadIntervalTimeout=10;
SetCommTimeouts(hCom,&to);
与SetCommTimeouts对应的GetCommTimeouts()函数的原型为:
BOOLGetCommTimeouts(
HANDLEhFile,//handleofcommunicationsdevice
LPCOMMTIMEOUTSlpCommTimeouts//pointertocommtime-outstructure
);
在读写串口之前,需要用SetCommMask()函数设置事件掩模来监视指定通信端
口上的事件,其原型为:
BOOLSetCommMask(
HANDLEhFile,//标识通信端口的句柄
DWORDdwEvtMask//能够使能的通信事件
);
有了Set当然还会有Get,与SetCommMask对应的GetCommMask()函数的原型为:
BOOLGetCommMask(
HANDLEhFile,//标识通信端口的句柄
LPDWORDlpEvtMask//addressofvariabletogeteventmask
);
串口上可以发生的事件可以是如下事件列表中的一个或任意组合:
EV_BREAK、
EV_CTS、EV_DSR、EV_ERR、EV_RING、EV_RLSD、EV_RXCHAR、EV_RXFLAG、EV_TXEMPTY。
我们可以用WaitCommEvent()函数来等待串口上我们利用SetCommMask()函数
设置的事件:
BOOLWaitCommEvent(
HANDLEhFile,//标识通信端口的句柄
LPDWORDlpEvtMask,//addressofvariableforeventthatoccurredt;
}COMMTIMEOUTS,*LPCOMMTIMEOUTS;
LPOVERLAPPEDlpOverlapped,//addressofoverlappedstructure
);
WaitCommEvent()函数一直阻塞,直到串口上发生我们用所SetCommMask()函
数设置的通信事件为止。
一般而言,当WaitCommEvent()返回时,程序员可以由分
析*lpEvtMask而获得发生事件的类别,再进行相应的处理。
对串口进行读取所用的函数和对文件进行读取所用的函数相同,读函数原型如
下:
BOOLReadFile(
HANDLEhFile,//handleoffiletoread
LPVOIDlpBuffer,//pointertobufferthatreceivesdata
DWORDnNumberOfBytesToRead,//numberofbytestoread
LPDWORDlpNumberOfBytesRead,//pointertonumberofbytesread
LPOVERLAPPEDlpOverlapped//pointertostructureforoverlappedI/O
);
对串口进行写入所用的函数和对文件进行写入所用的函数相同,写函数原型如
下:
BOOLWriteFile(
HANDLEhFile,//handletofiletowriteto
LPCVOIDlpBuffer,//pointertodatatowritetofile
DWORDnNumberOfBytesToWrite,//numberofbytestowrite
LPDWORDlpNumberOfBytesWritten,//pointertonumberofbyteswritten
LPOVERLAPPEDlpOverlapped//pointertostructureforoverlappedI/O
);
利用API函数实现串口通信时关闭串口非常简单,只需使用CreateFile函数
返回的句柄作为参数调用CloseHandle即可:
BOOLCloseHandle(
HANDLEhObject//handletoobjecttoclose
);hFile,//handletocommunicationsdev__
在笔者的《深入浅出Win32多线程程序设计之综合实例》中我们已经给出一个
利用WINAPI进行串口通信的例子,这里再给出一个类似的例子,以进一步加深理
解。
利用WINAPI进行串口通信对话框上控件对应的资源文件(.RC)中的内容如下:
BEGIN
EDITTEXTIDC_RECV_EDIT,28,119,256,46,ES_AUTOHSCROLL
GROUPBOX"发送数据",IDC_STATIC,19,15,282,70
GROUPBOX"接收数据",IDC_STATIC,19,100,282,80
EDITTEXTIDC_SEND_EDIT,29,33,214,39,ES_AUTOHSCROLL
PUSHBUTTON"清除",IDC_CLEAR_BUTTON,248,33,50,14
PUSHBUTTON"发送",IDC_SEND_BUTTON,248,55,50,14
END而整个对话框的消息映射(描述了消息及其对应的行为)如下:
BEGIN_MESSAGE_MAP(CSerialPortAPIDlg,CDialog)
//{{AFX_MSG_MAP(CSerialPortAPIDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()符准确无误。
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_CLEAR_BUTTON,OnClearButton)
ON_BN_CLICKED(IDC_SEND_BUTTON,OnSendButton)
ON_MESSAGE(COM_RECVDATA,OnRecvData)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()我们为IDC_SEND_EDIT和IDC_RECV_EDIT编辑框控件分别添加了一个CString
变量m_recv和m_send,下面的代码描述了这一行为:
classCSerialPortAPIDlg:
publicCDialog
{
//Construction
public:
CSerialPortAPIDlg(CWnd*pParent=NULL);//standardconstructor
//DialogData
//{{AFX_DATA(CSerialPortAPIDlg)
enum{IDD=IDD_SERIALPORTAPI_DIALOG};
CStringm_recv;//IDC_RECV_EDIT控件对应的变量
CStringm_send;//IDC_SEND_EDIT控件对应的变量
//}}AFX_DATA
//ClassWizardgeneratedvirtualfunctionoverrides
//{{AFX_VIRTUAL(CSerialPortAPIDlg)
protected:
virtualvoidDoDataExchange(CDataExchange*pDX);//DDX/DDVsupport
//}}AFX_VIRTUAL
//Implementation
protected:
BOOLOpenSerialPort1();
HICONm_hIcon;
//Generatedmessagemapfunctions
//{{AFX_MSG(CSerialPortAPIDlg)
virtualBOOLOnInitDialog();
afx_msgvoidOnSysCommand(UINTnID,LPARAMlParam);
afx_msgvoidOnPaint();
afx_msgHCURSOROnQueryDragIcon();
afx_msgvoidOnClearButton();
afx_msgvoidOnSendButton();
afx_msgvoidOnRecvData(WPARAMwParam,LPARAMlParam);SetCommTimeouts(hCom,&to);
与SetCommTimeo//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CSerialPortAPIDlg:
:
CSerialPortAPIDlg(CWnd*pParent/*=NULL*/)
:
CDialog(CSerialPortAPIDlg:
:
IDD,pParent)
{
//{{AFX_DATA_INIT(CSerialPortAPIDlg)
//在构造函数中初始化变量
m_recv=_T("");//在构造函数中初始化变量
m_send=_T("");
//}}AFX_DATA_INIT
//NotethatLoadIcondoesnotrequireasubsequentDestroyIconinWin32
m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
//建立编辑框控件和变量之间的映射
voidCSerialPortAPIDlg:
:
DoDataExchange(CDataExchange*pDX)
{
CDialog:
:
DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSerialPortAPIDlg)
DDX_Text(pDX,IDC_RECV_EDIT,m_recv);
DDX_Text(pDX,IDC_SEND_EDIT,m_send);
//}}AFX_DATA_MAP
}在对话框的OnInitDialog()函数中,我们启动窗口监听线程并将主窗口句柄传
递给线程控制函数:
BOOLCSerialPortAPIDlg:
:
OnInitDialog()
{
CDialog:
:
OnInitDialog();
//Add"About..."menuitemtosystemmenu.
//IDM_ABOUTBOXmustbeinthesystemcommandrange.
ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX<0xF000);
CMenu*pSysMenu=GetSystemMenu(FALSE);
if(pSysMenu!
=NULL)
{
CStringstrAboutMenu;OnQueryDragIcon();
afx_msgvoidOnClearButt_strAboutMenu.LoadString(IDS_ABOUTBOX);
if(!
strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);
}
}
//Settheiconforthisdialog.Theframeworkdoesthisautomatically
//whentheapplication'smainwindowisnotadialog
SetIcon(m_hIcon,TRUE);//Setbigicon
SetIcon(m_hIcon,FALSE);//Setsmallicon
//TODO:
Addextrainitializationhere
//启动串口监视线程
DWORDthreadID;
hCommThread=:
:
CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,
(LPTHREAD_START_ROUTINE)SerialPort1ThreadProcess,
AfxGetMainWnd()->m_hWnd,0,&threadID);
if(hCommThread==NULL)
{
:
:
AfxMessageBox("创建串口1处理线程失败");
:
:
PostQuitMessage(0);
}
returnTRUE;//returnTRUEunlessyousetthefocustoacontrol
}
//"清除"按钮函数
voidCSerialPortAPIDlg:
:
OnClearButton()
{
//T
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC+串口编程基于Win32 API VC 串口 编程 基于 Win32
![提示](https://static.bdocx.com/images/bang_tan.gif)