发一下牢骚和主题无关:
storysnail的Windows串口编程记笔
Author : He YiJun (storysnail<at>gmail.com QQ:363559089)
Develop Team : 7fane Team (http://www.7fane.com,测试网站,到2013年11月尾)
Editor : Yang QiuXi
Art Designer : He YiJun
License : 7fane Team License 1.0
Last Update : 2013-03-26
这半个月因肺部感染而不得不临时终止那令人生厌的中石油巡检任务,闭门在家安静的
涵养。整月的钱工自然是泡汤了,可却得来了极其贵珍的个人闲暇光时,让我能酣畅淋漓的
做软件方面的研讨,虽是家常便饭,针剂苦药,但可心静头埋于书房,却比天堂还美甜!
惚恍已至月末,任务位单来了消息,让我一会儿从美甜的梦中惊醒,从哪里来,回哪里
去,种这如"主体思惟"一样恐怖的思维是我挥之不去的梦魇,奈无、手足无措、病弱的身材
却情不自禁的向那发声的地方靠去!
好了,还是不再发牢骚了,只是个人得觉种这肿臃低效的国企够能存在,本身就是对“
国富论”绝佳的讥嘲,我只能用界世是多元的来啊Q一下了!
切入正题,这段光时做GSM/GPRG和GPS的小西东,须要通过串口发送AT指令来制控,前以
调试直一在用串口助手和minicom之类的现成软件,可是一点都不爽,为什么不自己写个操纵
串口的软件,就像在ARM和stm32上一样!
这文章其实只是我的一个记笔,分为两篇,一篇是《storysnail的Windows串口编程记笔》,
一另篇是《storysnail的Linux串口编程记笔》,由于网上已有非常多的似相文章,有些长篇
大论,有些短小精悍,连我自己都思考过是不是有要必再写一篇,但在Ling的煽动下还是写了!
本篇是Windows串口编程记笔,细详分析了串口信通会用到的api函数,并供提了两个示例程序,
这两个示例程序是在64位Windows7系统上用Code::Blocks上编写测试的。
一:写串口程序用到的函数
1:windows与Linux串口备设文件名照对
操纵系统 串口1 串口2 USB/RS-232转换器Windows COM1 COM2 COMX(我的系统上X=4)Linux /dev/ttyS0 /dev/ttyS1 /dev/ttyUSB0
2:写串口程序用到的函数
串行讯通函数定义在winbase.h头文件中,所以须要括包该文件。面下是要分析的函数表列
CreateFile 开打串口 CloseHandle 闭关串口 GetCommState 取得串口前当状态 SetCommState 置设串口状态SetupComm 置设串口用的I/O缓冲区的小大GetCommTimeouts 检测信通时超置设 SetCommTimeouts 置设信通时超参数 BuildCommDCB 用字符串中的值来充填备设制控块 WriteFile 发送数据 ReadFile 接收数据 GetOverlappedResult 回返最后异步操纵结果 ClearCommError 更新串口状态结构体,并除清部全串口硬件误错 PurgeComm 清空串口缓冲区,退出部全相干操纵 CreateEvent 创立一个被监控件事 SetCommMask 置设监控串口信通件事WaitCommEvent 等待被监控件事发生 WaitForSingleObject 等待一个被监测象对的结果 WaitForMultipleObjects 等待多个被监测象对的结果
2.1
CreateFile()
用处:开打串口
原型:
HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
参数说明:
lpFileName: 要开打的文件名称。对串口信通说来就是COMX(X为、1、2、3等)dwDesiredAccess: 读写模式置设dwShareMode: 串口同享模式lpSecurityAttributes: 串口的安全性属dwCreationDistribution: 创立文件的性子dwFlagsAndAttributes: 性属及相干标记hTemplateFile: 此处为0
操纵说明:串口被功成开打时,会回返其句柄,当前对串口的操纵都用使该句柄。
否则回返INVALID_HANDLE_VALUE即-1。
别特说明:
ReadFile和WriteFile的行为不仅受开打串口时是不是用使异步i/o的影响,还受信通时超置设的影响。
串行口读写的同步、异步式方是在开打端口的同时给dwFlagsAndAttributes参数传入当适的值而设定的。
在同步式方下,调用ReadFile和WriteFile后,当际实读写操纵成完或发生时超时才回返调用程序。
而异步式方函数在动启接收或发送进程后即立回返,程序续继向下行执。程序在调用ReadFile和
WriteFile时必须供提一个OVERLAPPED数据结构指针,该结构中括包一个手动的件事同步象对,
其后的程序必须借助于该件事同步象对,成完数据的接收和发送进程。
信通端口的时超置设对读写的理处式方也会发生影响,如果调用读写函数时发生端口时超,
则读写函数即立回返并回返已传输的数据字节数。
举例:
HANDLE hComm;
//hComm为函数回返的串口1的句柄
hComm=CreateFile("
COM1
",
//串号口
GENERIC_READ|GENERIC_WRITE,
//许允读写
0,
//讯通备设不许允其他应用程序同享,必须以占独式方开打
NULL,
//无安全性属,表现该串口可不被子程序继承
OPEN_EXISTING,
//讯通备设已存在
FILE_FLAG_OVERLAPPED,
//用使异步式方开打,即异步I/O
0);
//讯通备设不能用板模开打
2.2
CloseHandle()
用处:闭关串口
原型:
BOOL CloseHandle(HANDLE hObjedt)
参数说明:
hObjedt:串口句柄
操纵说明:功成闭关串口时回返true,否则回返false
举例:
CloseHandle(hComm);
2.3
GetCommState()
用处:取得串口前当状态
原型:BOOL GetCommState(HANDLE hFile,LPDCB lpDCB);
参数说明:
hFile:串口句柄
lpDCB:备设制控块(Device Control Block)结构地址。此结构中含有和备设相干的参数。此处是与串口相干的参数。
由于参数非常多,当须要置设串口参数时,通常是先取得串口的参数结构,改修部份参数后再将参数结构写入。
在此仅分析多数的几个经常使用的参数:
DWORD BaudRate:串口波特率
#define CBR_110 110
#define CBR_300 300
#define CBR_600 600
#define CBR_1200 1200
#define CBR_2400 2400
#define CBR_4800 4800
#define CBR_9600 9600
#define CBR_14400 14400
#define CBR_19200 19200
#define CBR_38400 38400
#define CBR_56000 56000
#define CBR_57600 57600
#define CBR_115200 115200
#define CBR_128000 128000
#define CBR_256000 256000
DWORD fParity:为1的话激活奇偶验校查检
DWORD Parity:验校式方,
#define NOPARITY 0 //无验校
#define ODDPARITY 1 //奇验校
#define EVENPARITY 2 //偶验校
#define MARKPARITY 3 //验校置位
#define SPACEPARITY 4 //验校清零
DWORD ByteSize:一个字节的数据位个数,范围是5~8
DWORD StopBits:停止位个数
#define ONESTOPBIT 0 // 1位停止位
#define ONE5STOPBITS 1 // 1.5位停止位
#define TWOSTOPBITS 2 // 2位停止位
操纵举例:
DCB ComDCB;
//串口备设制控块
if
(GetCommState(hComm,&ComDCB)) {
//取获串口前当状态
//功成行执
}
else
{
//误错理处
}
2.4
SetCommState()
用处:置设串口状态,括包经常使用的变动串号口、波特率、奇偶验校式方、数据位数等
原型:BOOL SetCommState(HANDLE hFile,LPDCB lpDCB);
参数说明:
hFile: 串口句柄
lpDCB:备设制控块(Device Control Block)结构地址。要变动的串口参数括包在此结构中。
操纵举例:
DCB ComDCB; GetCommState(hComm,&ComDCB);
//取得前当串口状态
ComDCB.BaudRate=9600;
//变动为9600bps,该值即为你要改修后的波特率
if
(SetCommState(hComm,&ComDCB)) {
//将变动后的参数写入串口
//功成行执
}
else
{
//误错理处
}
2.5
SetupComm()
用处:置设串口用的I/O缓冲区的小大。Windows用I/O缓冲区来暂存串口输入和输出的数据。
如果信通的速率较高,则应当置设较大的缓冲区。调用SetupComm函数可以置设串行口
的输入和输出缓冲区的小大。
原型:BOOL SetupComm(HANDLE hFile,DWORD dwInQueue,DWORD dwOutQueue);
参数说明:
hFile: 串口句柄
dwInQueue: 输入缓冲区的小大(字节数)
dwOutQueue: 输出缓冲区的小大(字节数)
操纵举例:
if
(SetupComm(hComm,1024,1024)) {
//功成行执
}
else
{
//误错理处
}
2.6
GetCommTimeouts ()
用处:检测信通时超置设
原型:BOOL GetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpctmo);
参数说明:详见SetCommTimeouts()函数
2.7
SetCommTimeouts ()
用处:置设信通时超参数
原型:BOOL SetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpctmo);
参数说明:
lpctmo: 指向括包新的时超参数的commtimeouts结构。commtimeouts结构定义如下:
typedef struct _COMMTIMEOUTS {
DWORD ReadIntervalTimeout;
DWORD ReadTotalTimeoutMultiplier;
DWORD ReadTotalTimeoutConstant;
DWORD WriteTotalTimeoutMultiplier;
DWORD WriteTotalTimeoutConstant;
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
ReadIntervalTimeout: 以毫秒为位单指定信通线上两个字符达到之间的最大光时。
在ReadFile操纵其间,收到第一个字符时开始盘算光时。
若恣意两个字符达到之间的隔间过超这个最大值,
ReadFile操纵成完,回返缓冲数据。0值表现不必隔间限时。
若该成员为MAXDWORD,且ReadTotalTimeoutConstant和
ReadTotalTimeoutMultiplier成员为零,则指出读操纵要
即立回返已接收到的字符,即使未收到字符,读操纵也要
即立回返。
在用异步式方读写串口时,虽然ReadFile和WriteFile在
成完操纵前以就可能回返,但时超仍然是起作用的。在种这情况下,
时超定规的是操纵的成完光时,而不是ReadFile和WriteFile的回返光时。
ReadTotalTimeoutMultiplier:以毫秒为位单指定一个乘数,该乘数用来盘算读操纵的总限时光时。
ReadTotalTimeoutConstant:以毫秒为位单指定一个常数,用于盘算读操纵的总限时光时。
读操纵的总限时光时的盘算公式是:
读操纵的总限时光时=ReadTotalTimeoutMultiplier×要求读/写的字符数+ReadTotalTimeoutConstant
例如,要读入10个字符,那么读操纵的总限时光时的盘算公式为:
读操纵的总限时光时=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant
ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant成员的值为0表现读操纵不必使限时光时。
WriteTotalTimeoutMultiplier:和ReadTotalTimeoutMultiplier似相
WriteTotalTimeoutConstant:和ReadTotalTimeoutConstant似相
操纵举例:
COMMTIMEOUTS m_commtimeouts; m_commtimeouts.ReadIntervalTimeout = 1000; m_commtimeouts.ReadTotalTimeoutMultiplier = 1000; m_commtimeouts.ReadTotalTimeoutConstant = 1000; m_commtimeouts.WriteTotalTimeoutMultiplier = 1000; m_commtimeouts.WriteTotalTimeoutConstant = 1000;
//串口时超参数置设
if
(setcommtimeouts(m_hcomm,&m_commtimeouts)) {
//功成行执
}
else
{
//误错理处
}
2.8
BuildCommDCB()
用处:用字符串中的值来充填备设制控块
原型:BOOL WINAPI BuildCommDCBA(LPCSTR lpszdef,LPDCB lpdcb);
参数说明:
lpszdef: 指向一个以null结束的字符串,该字符串指定串口的制控信息。
比如,“1200,n,8,1”指定波特率为1200,无奇偶验校位,有8个数据位和1个停止位。
lpdcb: 指向被充填的dcb结构。
操纵举例:
DCB ComDCB;
if
(buildcommdcb(“1200,n,8,1”, &ComDCB)) {
//立建串口备设制控块
//功成行执
}
else
{
//误错理处
}
2.9
WriteFile()
用处:向串口写数据
原型:BOOL WriteFile(HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped);
参数说明:
hFile: 串口句柄
lpBuffer: 待写入数据的首地址
nNumberOfBytesToWrite: 待写入数据的字节数长度
lpNumberOfBytesWritten:函数回返的际实写入串口的数据个数的地址,利用此变量可断判际实写入的字节数
和预备写入的字节数是不是同相。
lpOverlapped: 异步I/O结构的指针
操纵举例:
DWORD BytesSent=0;
unsigned
char
SendBytes[5]={1,2,3,4,5}; OVERLAPPED ov_Write; ov_Write.Offset=0; ov_Write.OffsetHigh=0; WriteFile(hComm,
//调用功成回返非零,失败回返零
SendBytes,
//输出缓冲区
5,
//预备发送的字符长度
&BytesSent,
//际实出发的字符数可以用使该值来查检是不是将部全的数据功成写入串口
&ov_Write);
//异步结构
2.10
ReadFile()
用处:读串口数据
原型:BOOL ReadFile(HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
lpNumberOfBytesRead,
lpOverlapped);
参数说明:
hFile:串口句柄
lpBuffer:存储被读出数据的首地址
nNumberOfBytesToRead:预备读出的字节个数
NumberOfBytesRead:际实读出的字节个数
lpOverlapped:异步I/O结构,
操纵举例:
unsigned
char
ucRxBuff[20]; COMSTAT ComStat; DWORD dwError=0; DWORD BytesRead=0; OVERLAPPED ov_Read; ov_Read.hEvent=CreateEvent(NULL, true, false, NULL);
//必须创立效有件事
//查检串口接收缓冲区中的数据个数.假如前当串口中有5个字节数据的话,
//那么行执完ClearCommError()函数后,ComStat结构中的ComStat.cbInQue将被充填为5,
//此值在ReadFile函数中可被直接利用。
ClearCommError(hComm,&dwError,&ComStat); bResult=ReadFile(hComm,
//串口句柄
ucRxBuff,
//输入缓冲区地址
ComStat.cbInQue,
//想读入的字符数
&BytesRead,
//际实读出的字节数的变量指针
&ov_Read);
//异步结构指针
2.11
GetOverlappedResult()
用处:回返最后异步操纵结果
原型:BOOL GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpoverlapped,PDWORD lpnumberofbytestransferred,BOOL bwait);
参数说明:
hfile: 串口句柄
lpoverlapped: 指向一个在动启异步操纵时指定的OVERLAPPED结构.
如果采取异步式方,则在调用ReadFile或WriteFile函数
时需必指定一个OVERLAPPED结构,调用后程序可续继行执
其它操纵,在适合的地方再调用函数GetOverlappedResult
断判异步操纵是不是成完。OVERLAPPED结构最主要的成员是
hEvent。hEvent是读写件事。当串口用使异步讯通时,
函数回返时操纵可能还没有成完,程序可以通过查检该
件事得悉是不是读写毕完。当调用ReadFile, WriteFile函数
的时候,该成员会主动被置为无信号状态;当异步操纵成完后,
该成员变量会主动被置为有信号状态。
OVERLAPPED结构定义如下:
typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED,*POVERLAPPED,*LPOVERLAPPED;
lpnumberofbytestransferred: 指向一个32位变量,该变量的值回返际实读写操纵传输的字节数。
bwait: 该参数用于指定函数是不是直一等到异步操纵结束。
如果该参数为TRUE,函数直到操纵结束才回返。
如果该参数为FALSE,函数直接回返,这时如果操纵没有成完,
通过调用GetLastError()函数会回返ERROR_IO_INCOMPLETE。
函数回返结果:通过断判OVERLAPPED结构中的hEvent是不是被置位来断判异步操纵是不是成完。
2.12
ClearCommError()
用处:除清串口误错标记以便续继输入、输出操纵
或者取读串口在现的状态和信通误码的值
原型:BOOL ClearCommError(HANDLE hFile,
LPDWORD lpErrors,
LPCOMATAT lpStat);
参数说明:
hFile: 串口句柄
lpErrors: 回返误错码的值,误错常数如下:
1-CE_BREAK: 检测到中断信号。意思是说检测到某个字节数据少缺正当的停止位。
2-CE_FRAME: 硬件检测到帧误错。
3-CE_IOE: 信通备设发生输入/输出误错。
4-CE_MODE: 置设模式误错,或是hFile值误错。
5-CE_OVERRUN: 出溢误错,缓冲区量容足不,数据将失丢。
6-CE_RXOVER: 出溢误错。
7-CE_RXPARITY: 硬件查检到验校位误错。
8-CE_TXFULL: 发送缓冲区已满。
lpStat: 指向信通端口状态的结构变量,该结构中对我们很主要的只有cbInQue和cbOutQue。
COMSTAT原型如下:
typedef struct _COMSTAT {
DWORD fCtsHold:1; // Tx waiting for CTS signal
DWORD fDsrHold:1; // Tx waiting for DSR signal
DWORD fRlsdHold:1; // Tx waiting for RLSD signal
DWORD fXoffHold:1; // Tx waiting, XOFF char rec''d
DWORD fXoffSent:1; // Tx waiting, XOFF char sent
DWORD fEof:1; // EOF character sent
DWORD fTxim:1; // character waiting for Tx
DWORD fReserved:25; // reserved
DWORD cbInQue; // bytes in input buffer 输入缓冲区中的字节数
DWORD cbOutQue; // bytes in output buffer 输出缓冲区中的字节数
} COMSTAT,*LPCOMSTAT;
操纵举例:
COMSTAT ComStat; DWORD dwError=0;
//ClearCommError会将串口中已接收到的数据字节个数充填到ComStat.cbInQue,
//利用此值数就可以用ReadFile()函数去读串口中的数据了。
ClearCommError(hComm,&dwError,&ComStat);
2.13
PurgeComm()
用处:除清串口缓冲区
原型:BOOL PurgeComm(HANDLE hFile,DWORD dwFlags);
参数说明:
hFile: 串口句柄
dwFlags:指定串口行执的动作,由以下参数构成:
PURGE_TXABORT:停止前目部全的传输任务即立回返不管是不是成完传输动作。
PURGE_RXABORT:停止前目部全的取读任务即立回返不管是不是成完取读动作。
PURGE_TXCLEAR:除清发送缓冲区的部全数据。
PURGE_RXCLEAR:除清接收缓冲区的部全数据。
操纵举例:
//除清串口的部全操纵。
PurgeComm(hComm, PURGE_RXCLEAR|PURGE_TXCLEAR |PURGE_RXABORT|PURGE_TXABORT);
2.14
CreateEvent
用处:创立一个被监控件事
原型:HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCSTR lpName);
参数说明:
lpEventAttributes: 安全性属,NULL表现用使认默性属
bManualReset: 为FALSE,表现该件事变成激起态后会主动置重为非激起态。
为TRUE,则表现不会主动置重,如果想让件事由激起态变成非激起态,须要调用ResetEvent()来置重
bInitialState: TRUE,表现创立的件事一开始就是激起态
FALSE,表现创立的件事一开始就非是激起态
lpName: 件事象对的名字,任何线程或进程都可以通过该名字用使该件事象对
回返值:功成回返件事句柄,并且调用GetLastError回返0,如果lpName已存在,则会回返已存在的件事象对,
GetLastError回返ERROR_ALREADY_EXISTS.
失败回返NULL
2.15
SetCommMask()
用处:置设监控串口信通件事。
原型:BOOL SetCommMask(HANDLE hFile,DWORD dwEvtMask);
参数说明:
hFile: 串口句柄
dwEvtMask: 预备监视的串口件事掩码
该参数有如下信息掩码位值:
EV_BREAK: 收到BREAK信号
EV_CTS: CTS(clear to send)线路发生化变
EV_DSR: DST(Data Set Ready)线路发生化变
EV_ERR: 线路状态误错,括包了CE_FRAME/CE_OVERRUN/CE_RXPARITY 3钟误错。
EV_RING: 检测到振铃信号。
EV_RLSD: CD(Carrier Detect)线路信号发生化变。
EV_RXCHAR: 输入缓冲区中已收到数据。
EV_RXFLAG: 用使SetCommState()函数置设的DCB结构中的等待字符已被传入输入缓冲区中。
EV_TXEMPTY: 输出缓冲区中的数据已被全完送出。
操纵举例:
//监视串口中有无数据和发送缓冲区中的数据是不是部全发送毕完。
if
(SetCommMask(hComm,EV_RXCHAR|EV_TXEMPTY)) {
//功成行执
}
else
{
//误错理处
}
2.16
WaitCommEvent()
用处:用来断判用SetCommMask()函数置设的串口信通件事是不是已发生。
如果异步操纵不能即立成完的话,函数会回返FALSE,这时应当调用GetLastError()函
数到得误错原因,如果GetLastError()回返ERROR_IO_PENDING,表现异步操纵正在台后
行进.在种这情况下,函数回返之前系统置设OVERLAPPED结构中的件事为无信号状态,
WaitCommEvent()函数会等待用SetCommMask()函数置设的串口件事发生,当有件事
发生或发生误错时,WaitCommEvent()函数会把OVERLAPPED结构中的件事置为有信号
状态,并将件事掩码充填到lpEvtMask参数中.
原型:BOOL WaitCommEvent(HANDLE hFile,LPDWORD lpEvtMask,LPOVERLAPPED lpOverlapped);
参数说明:
hFile: 串口句柄
lpEvtMask: 函数行执完后如果检测到串口信通件事的话就将其写入该参数中。
lpOverlapped:异步结构,用来保存异步操纵结果。
操纵举例:
OVERLAPPED lpoverlapped; DWORD dwMask,dwTrans,dwError=0,err; memset(&lpoverlapped,0,
sizeof
(OVERLAPPED)); lpoverlapped.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if
(!WaitCommEvent(hComm,&dwMask,&lpoverlapped)){
if
(GetLastError()==ERROR_IO_PENDING){ GetOverlappedResult(hComm,&lpoverlapped,&dwTrans,true);
switch
(dwMask){
case
EV_RXCHAR:
//输入缓冲区中已收到数据。
//you code
break
;
case
EV_TXEMPTY:
//输出缓冲区中的数据已被全完送出。
//you code
break
;
case
EV_BREAK:
//收到BREAK信号
//you code
break
;
case
EV_CTS:
//CTS(clear to send)线路发生化变
//you code
break
;
case
EV_DSR:
//DST(Data Set Ready)线路发生化变
//you code
break
;
case
EV_RING:
//检测到振铃信号。
//you code
break
;
case
EV_RLSD:
//CD(Carrier Detect)线路信号发生化变。
//you code
break
;
case
EV_RXFLAG:
//用使SetCommState()函数置设的DCB结构中的等待字符已被传入输入缓冲区中。
//you code
break
;
case
EV_ERR:
//线路状态误错,括包了CE_FRAME/CE_OVERRUN/CE_RXPARITY 3钟误错。
switch
(dwError){
case
CE_FRAME: err=0;
break
;
case
CE_OVERRUN: err=1;
break
;
case
CE_RXPARITY: err=2;
break
;
default
:
break
; }
//you code
break
;
default
:
break
; } } }
2.17
WaitForSingleObject
用处:等待一个被监测象对的结果
原型:DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMiliseconds);
参数说明:
hHandle: 被监测象对的句柄
dwMiliseconds: 等待的最长光时.光时终了时,即便被监测象对没有激起,函数还是会即立回返。
此值是0,代表立刻回返
此值是INFINITE,表现穷无等待
回返值:失败回返WAIT_FAILED,这时应当调用GetLastError()取得更多信息
功成以下三种值
WAIT_OBJECT_0 等待的象对激起
WAIT_TIMEOUT 等待时超
WAIT_ABANDONED 一个有拥mutex的线程结束前没有释放mutex
2.18
WaitForMultipleObjects
用处:等待多个被监测象对的结果
原型:DWORD WaitForMultipleObjects(DWORD nCount,const HANDLE *lpHandle,BOOL bWaitAll,DWORD dwMiliseconds);
参数说明:
nCount: lpHandle中的句柄量数,最大值为MAXNUM_WAIT_OBJECTS
lpHandle: 由多少象对句柄构成的组数
bWaitAll: 如果为TRUE,表现部全句柄都必须激起,此函数才能回返
如果为FALSE,只要有一个句柄被激起就会立刻回返
dwMiliseconds: 等待的最长光时.光时终了时,即便被监测象对没有激起,函数还是会即立回返。
此值是0,代表立刻回返
此值是INFINITE,表现穷无等待
二:示例程序
面下分析了大部份的串口信通会用到的函数,一般大家在写串口讯通程序时多爱好用件事
式方。即事前置设好须要监视的串口信通件事,然后创立一个线程监视是不是有件事发生,如果
没有件事发生的话,该线程会直一冷静的等待,当有件事发生时,再断判是何种件事,并通知
相干线程去理处,而理处的结果会通过件事或管道等信通式方通知主体窗线程来示显。
不过我写的程序特地将多线程部份移除了,这样是为了更清晰的展示如何操纵串口,毕竟
进程管理、线程的调度和同步是个很大的话题,有趣兴的友人可以看看jeffrey Richter的
《win32多线程程序设计》,这本书虽然很老,但却非常用实,核心的西东一般化变都非常小!
同步读写串口的简略程序
/********************************************************************* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * main.c Develop Team : 7fane Team Team Leader : He YiJun (storysnail<at>gmail.com QQ:363559089) Main Programmer : He YiJun Program comments : Ling Ying License : 7fane Team License 1.0 Last Update : 2013-03-25* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 功能说明: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 更 新:* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 已知问题:* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **********************************************************************/
#include <stdio.h>#include <stdlib.h>#include <windows.h>#include <tchar.h> #define COM_MAX_BUFFER 512
//串口数据存缓的最大字节数
#define THREAD_QUIT 1#define CMD_MAX_LEN 255 HANDLE hCom;
//全局变量,串口句柄
/********************************************************************函数名称:Com_Open()函数功能:开打串口函数说明:无口入参数:无出口参数:功成回返FALSE,失败回返TRUE调用例实:无*********************************************************************/
BOOL Com_Open(){ hCom=CreateFile("
COM4
",
//COMX口
GENERIC_READ|GENERIC_WRITE,
//许允读和写
0,
//占独式方
NULL, OPEN_EXISTING,
//开打而不是创立
0,
//同步式方,异步式方用FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED
NULL);
if
(hCom == INVALID_HANDLE_VALUE) {
printf
("
Open COM4 Fault!\n
");
return
FALSE; }
return
TRUE;}
/********************************************************************函数名称:Com_Setup()函数功能:配置串口函数说明:无口入参数:无出口参数:功成回返FALSE,失败回返TRUE调用例实:无*********************************************************************/
BOOL Com_Setup(){ COMMTIMEOUTS TimeOuts; DCB ComDCB;
//置设串口缓冲区
if
(!SetupComm(hCom,COM_MAX_BUFFER,COM_MAX_BUFFER)) {
printf
("
Setup COM4 Fault!\n
");
return
FALSE; }
//置设时超
/* //在读一次输入缓冲区的容内后读操纵就即立回返,而不管是不是读入了要求的字符。 TimeOuts.ReadIntervalTimeout=MAXDWORD; TimeOuts.ReadTotalTimeoutMultiplier=0; TimeOuts.ReadTotalTimeoutConstant=0; TimeOuts.WriteTotalTimeoutMultiplier=100; TimeOuts.WriteTotalTimeoutConstant=500; */
//设定读时超
TimeOuts.ReadIntervalTimeout=1000; TimeOuts.ReadTotalTimeoutMultiplier=500; TimeOuts.ReadTotalTimeoutConstant=5000;
//设定写时超
TimeOuts.WriteTotalTimeoutMultiplier=500; TimeOuts.WriteTotalTimeoutConstant=2000;
if
(!SetCommTimeouts(hCom,&TimeOuts)) {
printf
("
Setup COM4 Fault!\n
");
return
FALSE; }
if
(!GetCommState(hCom,&ComDCB)) {
//取获串口前当状态
printf
("
Setup COM4 Fault!\n
");
return
FALSE; } ComDCB.BaudRate = CBR_115200;
//变动为115200bps,该值即为你要改修后的波特率
ComDCB.fParity = 0;
//无奇偶效验
ComDCB.Parity = NOPARITY;
//无验校
ComDCB.ByteSize = 8;
//8数据位
ComDCB.StopBits = ONESTOPBIT;
//1停止位
if
(!SetCommState(hCom,&ComDCB)) {
//将变动后的参数写入串口
printf
("
Setup COM4 Fault!\n
");
return
FALSE; }
//在读写串口之前,还要清空缓冲区
if
(!PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR)) {
printf
("
Setup COM4 Fault!\n
");
return
FALSE; }
return
TRUE;}
/********************************************************************函数名称:Com_Read()函数功能:同步读串口,如果串口没有数据会直一塞阻函数说明:无口入参数:lpReadBuffer:将数据写入lpReadBuffer所指向的存缓区 ReadSize:预取读的字节数出口参数:回返际实读到的字节数,失败回返0调用例实:无*********************************************************************/
DWORD Com_Read(
char
*lpReadBuffer){ DWORD rCount;
//取读的字节数
BOOL bReadStat; bReadStat=ReadFile(hCom,lpReadBuffer,COM_MAX_BUFFER,&rCount,NULL);
if
(!bReadStat) {
printf
("
Read COM4 Fault!\n
");
return
0; }
printf
("
Read com: %s\n
",lpReadBuffer); PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return
rCount;}
/********************************************************************函数名称:Com_Write()函数功能:同步写串口函数说明:无口入参数:lpReadBuffer:将lpWriteBuffer所指向的缓冲区中的数据写入串口 ReadSize:预写入的字节数出口参数:回返际实写入的字节数,失败回返0调用例实:无*********************************************************************/
BOOL Com_Write(
char
*lpWriteBuffer,DWORD lpWriteBufferLen){ DWORD dwBytesWrite=0; COMSTAT ComStat; DWORD dwErrorFlags; BOOL bWriteStat; ClearCommError(hCom,&dwErrorFlags,&ComStat); bWriteStat=WriteFile(hCom,lpWriteBuffer,lpWriteBufferLen,&dwBytesWrite,NULL);
if
(!bWriteStat) {
printf
("
Write COM4 Fault!\n
");
return
FALSE; } PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
printf
("
Wrote com: %s\n
",lpWriteBuffer);
return
TRUE;}
/********************************************************************函数名称: main()函数功能:main()函数说明:main()口入参数:无出口参数:0调用例实:无*********************************************************************/
int
main(){
char
lpReadBuffer[COM_MAX_BUFFER+1];
char
lpWriteBuffer[COM_MAX_BUFFER+1];
char
cmd[CMD_MAX_LEN+1]; DWORD rCount = 0;
if
(!Com_Open()) {
return
0; }
if
(!Com_Setup()) { CloseHandle(hCom);
return
0; }
while
(1) { memset(cmd,'\0',CMD_MAX_LEN+1); _tprintf (_T("
%s
"), _T("
\nEnter Command:
")); _fgetts (cmd, CMD_MAX_LEN, stdin);
/* Get rid of the new line at the end */
/* Messages use 8-bit characters */
cmd[strlen(cmd)-1] = '\0';
//最少能到得一个回车字符
if
(
strcmp
(cmd, "
$Quit
") == 0)
break
;
if
(strncmp (cmd, "
read
",
sizeof
("
read
")) == 0) { memset(lpReadBuffer,'\0',COM_MAX_BUFFER+1); rCount = Com_Read(lpReadBuffer);
printf
("
Read com char num: %d\n
",(
int
)rCount); }
if
(strncmp (cmd, "
write
",
sizeof
("
write
")) == 0) { memset(lpWriteBuffer,'\0',COM_MAX_BUFFER+1); lpWriteBuffer[0] = 'A'; lpWriteBuffer[1] = 'T'; lpWriteBuffer[2] = 0x0d; lpWriteBuffer[3] = '\0'; Com_Write(lpWriteBuffer,strlen(lpWriteBuffer)); memset(lpReadBuffer,'\0',COM_MAX_BUFFER+1); rCount = Com_Read(lpReadBuffer);
printf
("
Read com char num: %d\n
",(
int
)rCount); } } CloseHandle(hCom);
return
0;}
异步读串口的示例代码:
/************************************************************************* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * main.c Develop Team : 7fane Team Team Leader : He YiJun (storysnail<at>gmail.com QQ:363559089) Main Programmer : He YiJun Program comments : Ling Ying License : 7fane Team License 1.0 Last Update : 2013-03-25* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 功能说明: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 更 新:* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 已知问题:* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **************************************************************************/
#include <stdio.h>#include <stdlib.h>#include <windows.h>#include <tchar.h> #define COM_MAX_BUFFER 512
//串口数据存缓的最大字节数
#define THREAD_QUIT 1#define CMD_MAX_LEN 255 HANDLE hCom;
//全局变量,串口句柄
/************************************************************************函数名称:Com_Open()函数功能:开打串口,异步IO函数说明:无口入参数:无出口参数:功成回返FALSE,失败回返TRUE调用例实:无*************************************************************************/
BOOL Com_Open(){ hCom=CreateFile("
COM4
",
//COMX口
GENERIC_READ|GENERIC_WRITE,
//许允读和写
0,
//占独式方
NULL, OPEN_EXISTING,
//开打而不是创立
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
//异步式方
NULL);
if
(hCom == INVALID_HANDLE_VALUE) {
printf
("
Open COM4 Fault!\n
");
return
FALSE; }
return
TRUE;}
/************************************************************************函数名称:Com_Setup()函数功能:配置串口函数说明:无口入参数:无出口参数:功成回返FALSE,失败回返TRUE调用例实:无*************************************************************************/
BOOL Com_Setup(){ COMMTIMEOUTS TimeOuts; DCB ComDCB;
//置设串口缓冲区
if
(!SetupComm(hCom,COM_MAX_BUFFER,COM_MAX_BUFFER)) {
printf
("
Setup COM4 Fault!\n
");
return
FALSE; }
//置设时超
//设定读时超
TimeOuts.ReadIntervalTimeout=1000; TimeOuts.ReadTotalTimeoutMultiplier=500; TimeOuts.ReadTotalTimeoutConstant=5000;
//设定写时超
TimeOuts.WriteTotalTimeoutMultiplier=500; TimeOuts.WriteTotalTimeoutConstant=2000;
if
(!SetCommTimeouts(hCom,&TimeOuts)) {
printf
("
Setup COM4 Fault!\n
");
return
FALSE; }
if
(!GetCommState(hCom,&ComDCB)) {
//取获串口前当状态
printf
("
Setup COM4 Fault!\n
");
return
FALSE; } ComDCB.BaudRate = CBR_115200;
//变动为115200bps,该值即为你要改修后的波特率
ComDCB.fParity = 0;
//无奇偶效验
ComDCB.Parity = NOPARITY;
//无验校
ComDCB.ByteSize = 8;
//8数据位
ComDCB.StopBits = ONESTOPBIT;
//1停止位
if
(!SetCommState(hCom,&ComDCB)) {
//将变动后的参数写入串口
printf
("
Setup COM4 Fault!\n
");
return
FALSE; }
//在读写串口之前,还要清空缓冲区
if
(!PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR)) {
printf
("
Setup COM4 Fault!\n
");
return
FALSE; }
return
TRUE;}
/************************************************************************函数名称:Com_Read()函数功能:读串口函数说明:无口入参数:lpReadBuffer:将数据写入lpReadBuffer所指向的存缓区 ReadSize:预取读的字节数出口参数:回返际实读到的字节数,失败回返0调用例实:无*************************************************************************/
DWORD Com_Read(
char
*lpReadBuffer,DWORD ReadSize){ OVERLAPPED lpoverlapped; COMSTAT ComStat; DWORD dwErrorFlags; DWORD rCount = 0;
//取读的字节数
DWORD dwBytesRead = ReadSize; BOOL bReadStat;
if
(dwBytesRead > COM_MAX_BUFFER) dwBytesRead = COM_MAX_BUFFER; memset(&lpoverlapped,0,
sizeof
(OVERLAPPED)); lpoverlapped.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
//取读串口在现的状态和信通误码的值
//主要是为了到得输入缓冲区中的字节数
ClearCommError(hCom,&dwErrorFlags,&ComStat);
//dwBytesRead是预取读的字节数
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
if
(!dwBytesRead)
return
0; bReadStat=ReadFile(hCom,lpReadBuffer,dwBytesRead,&rCount,&lpoverlapped);
if
(!bReadStat) {
if
(GetLastError()==ERROR_IO_PENDING) {
//回返ERROR_IO_PENDING,标明串口正在行进读操纵
// GetOverlappedResult函数的最后一个参数设为TRUE时,
//函数会直一等待,直到读操纵成完或由于误错而回返。
GetOverlappedResult(hCom,&lpoverlapped,&rCount,TRUE);
//用使WaitForSingleObject函数等待,直到读操纵成完或延时已达到2秒钟
//当串口读操纵行进毕完后,lpoverlapped.hEvent件事会变成有信号
//WaitForSingleObject(lpoverlapped.hEvent,2000);
PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
printf
("
READ IO PENDING %d!\n
",(
int
)rCount);
return
rCount; }
printf
("
Read COM4 Fault!\n
");
return
0; } PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return
rCount;}
/************************************************************************函数名称:Com_Write()函数功能:写串口函数说明:无口入参数:lpReadBuffer:将lpWriteBuffer所指向的缓冲区中的数据写入串口 ReadSize:预写入的字节数出口参数:回返际实写入的字节数,失败回返0调用例实:无*************************************************************************/
DWORD Com_Write(
char
*lpWriteBuffer,DWORD WriteSize){ DWORD wCount = 0;
//写入的际实字节数
DWORD dwBytesWrite=WriteSize; OVERLAPPED lpoverlapped; COMSTAT ComStat; DWORD dwErrorFlags; BOOL bWriteStat;
if
((dwBytesWrite > COM_MAX_BUFFER) || (!dwBytesWrite))
return
0; memset(&lpoverlapped,0,
sizeof
(OVERLAPPED)); lpoverlapped.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
//取读串口在现的状态和信通误码的值
//主要是为了到得输出缓冲区中的字节数
ClearCommError(hCom,&dwErrorFlags,&ComStat);
//如果输出缓冲区中有数据,那么回返0
if
(ComStat.cbOutQue != 0) {
printf
("
Write buffer was not empty!\n
");
return
0; } bWriteStat=WriteFile(hCom,lpWriteBuffer,dwBytesWrite,&wCount,&lpoverlapped);
if
(!bWriteStat) {
if
(GetLastError()==ERROR_IO_PENDING) { ClearCommError(hCom,&dwErrorFlags,&ComStat); wCount = ComStat.cbOutQue; WaitForSingleObject(lpoverlapped.hEvent,1000);
printf
("
WROTE IO PENDING %d!\n
",(
int
)wCount);
return
wCount; }
printf
("
Write COM4 Fault!\n
");
return
0; } PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return
wCount;}
/************************************************************************函数名称: main()函数功能:main()函数说明:main()口入参数:无出口参数:0调用例实:无*************************************************************************/
int
main(){
char
lpReadBuffer[COM_MAX_BUFFER+1];
char
lpWriteBuffer[COM_MAX_BUFFER+1];
char
cmd[CMD_MAX_LEN+1]; DWORD rCount = 0; DWORD wCount = 0;
if
(!Com_Open()) {
return
0; }
if
(!Com_Setup()) { CloseHandle(hCom);
return
0; }
while
(1) { memset(cmd,'\0',CMD_MAX_LEN+1); _tprintf (_T("
%s
"), _T("
\nEnter Command:
")); _fgetts (cmd, CMD_MAX_LEN, stdin);
/* Get rid of the new line at the end */
/* Messages use 8-bit characters */
cmd[strlen(cmd)-1] = '\0';
if
(
strcmp
(cmd, "
$Quit
") == 0)
break
;
if
(strncmp (cmd, "
read
",
sizeof
("
read
")) == 0) { memset(lpReadBuffer,'\0',COM_MAX_BUFFER+1); rCount = Com_Read(lpReadBuffer,COM_MAX_BUFFER);
if
(rCount > 0) {
printf
("
Read com: %s\n
",lpReadBuffer);
printf
("
Read com char num: %d\n
",(
int
)rCount); } }
if
(strncmp (cmd, "
write
",
sizeof
("
write
")) == 0) { memset(lpWriteBuffer,'\0',COM_MAX_BUFFER+1); lpWriteBuffer[0] = 'A'; lpWriteBuffer[1] = 'T'; lpWriteBuffer[2] = 0x0d; lpWriteBuffer[3] = '\0'; wCount = Com_Write(lpWriteBuffer,strlen(lpWriteBuffer));
if
(wCount > 0) {
printf
("
Wrote com: %s\n
",lpWriteBuffer);
printf
("
Wrote com char num: %d\n
",(
int
)wCount); } } } CloseHandle(hCom);
return
0;}
7fane Team 议协 1.0 中文版
当您浏览、理解并意愿遵照以下条款时,您就有拥了取获、用使、复制、发分或通过信通
络网播传7fane Team作品的权力。
1. 7fane Team的作品可以在非商业用处下收费用使。
2. 如果软件供提了源代码,那么你可以变动源代码或软件接口以应适你的应用。
3. 在未取得7fane Team的权授之前,你可不以在商业用处下用使7fane Team的作品,
也可不以将7fane Team的作品用于营利为的目的动活。关于取得许可,请发送Email
到storysnail@gmail.com以取获更多信息。
4. 你不得租赁,再许可,销售,让渡,押抵7fane Team的作品和服务。
5. 你不得删除或改修7fane Team作品的版权信息和相干的链接,例如址网信息或“关于口窗”
中的部全信息,除非您已取得7fane Team的书面权授。
6. 你可不以通过改修7fane Team的作品来取得衍生作品,更可不以重新分配这些衍生作品。
7. 如果您不能遵照本议协,您的许可将被终止,您必须停止用使并删除7fane Team作品及其
本副,并且可不以再续继取获、用使、复制、发分或通过信通络网播传7fane Team作品。
8. 7fane Team有拥并留保改修本议协的权力和在本议协改修后不另行通知的权力。改修后
的新议协将适用于新的许可户用。
9. 7fane Team作品是作为不供提任何确明的或隐含的抵偿或担保的式形供提的。
10.7fane Team对于用使其作品而生成的任何信息不担承任何义务,也不会对播传或用使
这些信息担承义务。
11. 户用出于愿自而用使本7fane Team作品,您必须懂得用使的险风,我们不承诺对户用供提
任何式形的技术支持、用使担保,所以你必须担承部全险风。
关于 "7fane Team作品" 的定义:
"7fane Team作品" 括包文本、像图、音频视频、软件等由7fane Team创作的一切。
版权部全 (c)2001-2012,7fane Team 留保部全权力。
文章结束给大家分享下程序员的一些笑话语录: AdobeFlash拖垮Windows拖垮IE!又拖垮Linux拖垮Ubuntu拖垮FirxEox!还拖垮BSD拖垮MacOS拖垮Safri!简直无所不拖!AdobeFlash滚出网路世界!不要以为市占有率高就可以持续出烂货产品!以后替代品多得是!