串口编程

串口开发,需要用到一些工具,这里我推荐 :

虚拟串口工具(Virtual Serial Port Driver) : http://www.eltima.com/products/vspdxp/,这个是收费的,可以百度个破解版本的.

串口调试工具(AccessPort) :http://www.sudt.com/,这个是免费的,随便下.

虚拟串口工具 : 当我们没有串口,但我们又需要测试我们的串口代码,怎么办?

                       通过软件虚拟出来!

Virtual Serial Port Driver就是这一类型的工具,软件打开的主界面 :

 

如上图:Physical ports : 我家里面的电脑的确没有串口连接

      Virtual ports : 也没有创建任何的虚拟串口

点击右侧的Add pair,产生了一对的虚拟串口,如下图:

这一对串口的关系是 : COM1发送的数据,COM2接收,COM2发送的数据,COM1接收.

这样,我们在代码里面操作COM1,就可以使用串口调试工具打开COM2完成数据的接收和发送.

下面截个串口工具AccessPort的主界面吧 :

看上图: COM2已经给我打开了,在虚拟串口工具中也可以看见,如下图:

废话不多说,直接上代码.在代码之后写了一些Win32串口API使用的说明.

1.SerialPort.h

 

#ifndef TRAIN_SERIAL_PORT_H
#define TRAIN_SERIAL_PORT_H

// headers
#include <windows.h>
// end headers

// macros
#ifndef NULL
#define NULL ((void *)0)
#endif // NULL

#ifndef TRUE
#define TRUE  1
#endif // TRUE

#ifndef FALSE
#define FALSE  0
#endif // FALSE

#define PORT_IN_BUF_SIZE  8192 // size of the device's internal input buffer
#define PORT_OUT_BUF_SIZE 8192 // size of the device's internal output buffer
// end macros

// enums
enum PORT_ERROR{
	PORT_SUCCESS = 0,
	PORT_ERROR_INVALID_PARA = 0-1,
	PORT_ERROR_OPEN			= 0-2,
	PORT_ERROR_SET_BUF		= 0-3,
	PORT_ERROR_SET_TIMEOUT  = 0-4,
	PORT_ERROR_GET_DCB		= 0-5,
	PORT_ERROR_SET_DCB		= 0-6,
	PORT_ERROR_INVALID_HANDLE = 0-7,
	PORT_INVALID_CLR_TYPE   = 0-8,
	PORT_ERROR_CLEAR_BUFFER = 0-9,
	PORT_ERROR_WRITE_FILE	= 0-10,
	PORT_ERROR_WRITE_TIMEOUT   = 0-11,
	PORT_ERROR_WRITE_NOT_EQUAL = 0-12,
	PORT_ERROR_READ_FILE	= 0-13,
	PORT_ERROR_READ_TIMEOUT = 0-14,
	PORT_ERROR_CREATE_EVENT = 0-15,
	PORT_ERROR_GET_RESULT   = 0-16,
	PORT_ERROR_SET_MASK		= 0-17,
	PORT_ERROR_END = 0-100
};

enum PORT_CLRBUF_TYPE{
	PORT_CLEAR_RX,
	PORT_CLEAR_TX,
	PORT_CLEAR_RX_TX
};
// end enums

#ifdef __cplusplus
extern "C"{
#endif // __cplusplus

	void PortSetAsync(const bAsync);
int PortClose(HANDLE *handle);
int PortOpen(HANDLE *handle, const unsigned char *pszPortName, const int iBaudRate);
int PortClearBuffer(HANDLE *handle, enum PORT_CLRBUF_TYPE eClrType);
int PortSends(HANDLE *handle, const char *pszSendData, const unsigned long ulWriteLen, unsigned long *pOutWrittens);
int PortRecvs(HANDLE *handle, char *psInRecvData, const unsigned long ulMaxReadBytes, unsigned long *pulOutRecvBytes);

#ifdef __cplusplus
}
#endif // __cplusplus

#endif // TRAIN_SERIAL_PORT_H

// end of file


2.SerialPort.c


#include"SerialPort.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

static int sg_bAsync = FALSE;

// set synchronization or asynchronization
// TRUE-asynchronize, FALSE-synchronization
void PortSetAsync(const bAsync) 
{
	if(TRUE == bAsync)
	{
		sg_bAsync = FILE_FLAG_OVERLAPPED;
	}
	else
	{
		sg_bAsync =0;
	}
}

// open serial port,return the handle to operate serial port
// pszPortName should be like COM1,COM2...COM99,the max is COM99
int PortOpen(HANDLE *handle, const unsigned char *pszPortName, const int iBaudRate)
{
	int iRet;
	int iPortNum;
	unsigned char szPortNum[3+1];
	unsigned char szPortName[12+1];
	COMMTIMEOUTS stCommTimeouts;
	DCB stDcb; // device-control block

	if(NULL == pszPortName || MAX_PATH < strlen(pszPortName) ||
	   (9600 != iBaudRate   && 115200 != iBaudRate))
	{
		return PORT_ERROR_INVALID_PARA;
	}

	if(strlen(pszPortName)<4 || strlen(pszPortName)>5)
	{
		return PORT_ERROR_INVALID_PARA;
	}

	memset(szPortName, 0x00, sizeof(szPortName));
	strncpy(szPortName, pszPortName, 3);
	strcpy(szPortNum,  pszPortName+3);
	iPortNum = 0;
	iPortNum = atoi(szPortNum);

	if(strcmp(szPortName, "COM") !=0 || iPortNum==0)
	{
		return PORT_ERROR_INVALID_PARA;
	}

	// if port number is more than 9,it should format like this "\\\\.\\COMxx"
	if(iPortNum > 9)
	{
		sprintf(szPortName, "\\\\.\\%s", pszPortName);
	}
	else
	{
		strcpy(szPortName, pszPortName);
	}

	*handle = CreateFile(szPortName,				  // COM name
		                GENERIC_READ | GENERIC_WRITE, // allow write and read
						0,							  // not share with other process
						NULL,
						OPEN_EXISTING,				  // serial port must be open,not create
						sg_bAsync,					  // synchronization or asynchronization
						NULL
						);

	if(INVALID_HANDLE_VALUE == *handle)
	{
		return PORT_ERROR_OPEN;
	}

	iRet = SetupComm(*handle, PORT_IN_BUF_SIZE, PORT_OUT_BUF_SIZE); // if fails,return 0
	if(FALSE == iRet)
	{
		return PORT_ERROR_SET_BUF;
	}

	// set timeout for read
	stCommTimeouts.ReadIntervalTimeout		  = 500;
	stCommTimeouts.ReadTotalTimeoutMultiplier = 2000;
	stCommTimeouts.ReadTotalTimeoutConstant	  = 5000;

	// set timeout for write 
	stCommTimeouts.WriteTotalTimeoutMultiplier = 100;
	stCommTimeouts.WriteTotalTimeoutConstant   = 3000;

	iRet = SetCommTimeouts(*handle, &stCommTimeouts);
	if(FALSE == iRet)
	{
		return PORT_ERROR_SET_TIMEOUT;
	}
	
	// get current configuration,then set only a few members of the DCB structure
	iRet = GetCommState(*handle, &stDcb);
	if(FALSE == iRet)
	{
		return PORT_ERROR_GET_DCB;
	}

	// change only a few members of the DCB structure
	stDcb.BaudRate = iBaudRate;
	stDcb.ByteSize = 8;
	stDcb.Parity   = NOPARITY;
	stDcb.StopBits = ONESTOPBIT;

	iRet = SetCommState(*handle, &stDcb);
	if(FALSE == iRet)
	{
		return PORT_ERROR_SET_DCB;
	}

	iRet = SetCommMask(*handle, EV_RXCHAR|EV_TXEMPTY); 
	if(FALSE == iRet)
	{
		return PORT_ERROR_SET_MASK;
	}

	return PortClearBuffer(handle, PORT_CLEAR_RX_TX);
}

// clear serial port receive and send buffer
int PortClearBuffer(HANDLE *handle, enum PORT_CLRBUF_TYPE eClrType)
{
	int iRet;

	if(INVALID_HANDLE_VALUE == *handle)
	{
		return PORT_ERROR_INVALID_HANDLE;
	}

	if(PORT_CLEAR_RX > eClrType || PORT_CLEAR_RX_TX < eClrType)
	{
		return PORT_INVALID_CLR_TYPE;
	}

	if(PORT_CLEAR_TX == eClrType)
	{
		iRet = PurgeComm(*handle, PURGE_TXABORT|PURGE_TXCLEAR);
	}
	else if(PORT_CLEAR_RX == eClrType)
	{
		iRet = PurgeComm(*handle, PURGE_RXABORT|PURGE_RXCLEAR);
	}
	else if(PORT_CLEAR_RX_TX == eClrType)
	{
		iRet = PurgeComm(*handle, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
	}

	if(FALSE == iRet)
	{
		return PORT_ERROR_CLEAR_BUFFER;
	}

	return PORT_SUCCESS;
}

// close handle
int PortClose(HANDLE *handle)
{
	int iRet;

	if(INVALID_HANDLE_VALUE == *handle)
	{
		return PORT_ERROR_INVALID_HANDLE;
	}

	iRet    = CloseHandle(*handle);
	*handle = INVALID_HANDLE_VALUE;

	return !iRet; 
}

// send data to serial port
int PortSends(HANDLE *handle, const char *pszSendData, const unsigned long ulWriteLen, unsigned long *pOutWrittens)
{	
	int		 iRet;
	COMSTAT  stComStat;
	unsigned long  ulWrittens;
	unsigned long  ulErrFlags;
	OVERLAPPED stOverLapped;
 
	if(INVALID_HANDLE_VALUE == *handle)
	{
		return PORT_ERROR_INVALID_HANDLE;
	}
	if( ulWriteLen<=0 || NULL==pszSendData )
	{
		return PORT_ERROR_INVALID_PARA;
	}

	if(FILE_FLAG_OVERLAPPED == sg_bAsync)
	{
		stOverLapped.hEvent	    = CreateEvent( NULL, TRUE,FALSE,NULL);
		stOverLapped.Offset	    = 0;
		stOverLapped.OffsetHigh = 0;
		if( NULL == stOverLapped.hEvent )
		{
			return PORT_ERROR_CREATE_EVENT;
		}
		iRet = WriteFile(*handle, pszSendData, ulWriteLen, &ulWrittens, &stOverLapped);

	}
	else
	{
		iRet = WriteFile(*handle, pszSendData, ulWriteLen, &ulWrittens, NULL);

	}
	
	if(FALSE == iRet)
	{
		if(0 == sg_bAsync)
		{
			return PORT_ERROR_WRITE_FILE;
		}
		else
		{
			DWORD dwLastError = GetLastError();
			if( dwLastError == ERROR_IO_PENDING )
			{
				DWORD dwWaitResult = WaitForSingleObject(stOverLapped.hEvent, 5000);
				// PortClearBuffer(handle, PORT_CLEAR_TX);
				CloseHandle(stOverLapped.hEvent);
				if( dwWaitResult == WAIT_FAILED )
				{
					return PORT_ERROR_WRITE_FILE;
				}
				else if(dwWaitResult == WAIT_ABANDONED || dwWaitResult == WAIT_OBJECT_0)
				{
					// do nothing
				}
				else if(dwWaitResult == WAIT_TIMEOUT)
				{
					return PORT_ERROR_WRITE_TIMEOUT;
				}
			}
			else
			{
				return PORT_ERROR_WRITE_FILE;
			}
		}
	}

	if(FILE_FLAG_OVERLAPPED == sg_bAsync)
	{
		iRet = GetOverlappedResult(*handle, &stOverLapped, &ulWrittens, TRUE);
		if(0 == iRet)
		{
			return PORT_ERROR_GET_RESULT;
		}
	}

	if(ulWriteLen != ulWrittens)
	{
		return PORT_ERROR_WRITE_NOT_EQUAL;
	}

	// clear transmit error information
	ClearCommError(*handle, &ulErrFlags, &stComStat);
	*pOutWrittens = ulWrittens;
	
	return PORT_SUCCESS;
}

// read data from serial port
int PortRecvs(HANDLE *handle, char *psInRecvData, const unsigned long ulMaxReadBytes, unsigned long *pulOutRecvBytes)
{
	int iRet;
	unsigned long ulRecvBytes;
	OVERLAPPED stOverLapped;

	if(NULL == psInRecvData || 0 >= ulMaxReadBytes)
	{
		return PORT_ERROR_INVALID_PARA;
	}
	
	if(FILE_FLAG_OVERLAPPED == sg_bAsync)
	{
		stOverLapped.hEvent	    = CreateEvent( NULL, TRUE,FALSE,NULL);
		stOverLapped.Offset	    = 0;
		stOverLapped.OffsetHigh = 0;
		if( NULL == stOverLapped.hEvent )
		{
			return PORT_ERROR_CREATE_EVENT;
		}
		iRet = ReadFile(*handle, psInRecvData, ulMaxReadBytes, &ulRecvBytes, &stOverLapped); 
	}
	else
	{
		iRet = ReadFile(*handle, psInRecvData, ulMaxReadBytes, &ulRecvBytes, NULL); 
	}

	if(FALSE == iRet)
	{
		if(0 == sg_bAsync)
		{
			return PORT_ERROR_READ_FILE;
		}
		else
		{
			DWORD dwLastError = GetLastError();
			if( dwLastError == ERROR_IO_PENDING )
			{
				DWORD dwWaitResult = WaitForSingleObject(stOverLapped.hEvent, 7000);
				// PortClearBuffer(handle, PORT_CLEAR_RX);
				CloseHandle(stOverLapped.hEvent);
				if( dwWaitResult == WAIT_FAILED )
				{
					return PORT_ERROR_READ_FILE;
				}
				else if(dwWaitResult == WAIT_ABANDONED || dwWaitResult == WAIT_OBJECT_0)
				{
					// do nothing
				}
				else if(dwWaitResult == WAIT_TIMEOUT)
				{
					return PORT_ERROR_READ_TIMEOUT;
				}
			}
			else
			{
				return PORT_ERROR_READ_FILE;
			}
		}
	}

	if(FILE_FLAG_OVERLAPPED == sg_bAsync)
	{
		iRet = GetOverlappedResult(*handle, &stOverLapped, &ulRecvBytes, TRUE);
		if(0 == iRet)
		{
			return PORT_ERROR_GET_RESULT;
		}
	}
	
	*pulOutRecvBytes = ulRecvBytes;

	return PORT_SUCCESS;
}

// end of file 

 

使用参考 :
3.main.c

#include "SerialPort.h"



int main(void)
{
	HANDLE handle;
	int iRet;
	unsigned long ulSends;
	unsigned long ulRecvs;
	unsigned char szRecvBuffer[1024];

	PortSetAsync(TRUE);

	iRet = PortOpen(&handle, "COM2", 115200);
	if(0 == iRet)
	{
		printf("PortOpen Succeed\n");
	}
	else
	{
		printf("PortOpen Fail\n");
		return -1;
	}

	iRet = PortSends(&handle, "123", 3, &ulSends);
	if(0 == iRet)
	{
		printf("PortSends Succeed, SendBytes=%d\n", ulSends);
	}
	else
	{
		printf("PortSends Fail\n");
		PortClose(&handle);
		return -2;
	}

	memset(szRecvBuffer, 0x00, sizeof(szRecvBuffer));
	iRet = PortRecvs(&handle, szRecvBuffer, 1024, &ulRecvs);
	if(0 == iRet)
	{
		printf("PortRecvs Succeed, RecvBytes=%d\n", ulRecvs);
		printf("RecvData : %s\n", szRecvBuffer);
	}
	else
	{
		printf("PortRecvs Fail\n");
		PortClose(&handle);
		return -2;
	}

	iRet = PortClose(&handle);
	if(0 == iRet)
	{
		printf("PortClose Succeed\n");
	}
	else
	{
		printf("PortClose Fail\n");
		return -2;
	}

	return 0;
}

// end of file


4.演示例子

先看运行效果,如图:

代码如下 :

main.c

#include "SerialPort.h"



int main(void)
{
	HANDLE handle;
	int iCnt;
	int iRet;
	unsigned long ulSends;
	unsigned long ulRecvs;
	unsigned char szRecvBuffer[1024];

	PortSetAsync(TRUE);

	iCnt = 0;
	while(1)
	{
		iRet = PortOpen(&handle, "COM3", 115200);
		if(0 == iRet)
		{
			printf("PortOpen Succeed\n");
			break;
		}
		else
		{
			printf("PortOpen Fail, iCnt=%d, Retrying...\n", ++iCnt);
			Sleep(10);
			if(iCnt > 10000 * 10)
			{
				return 0;
			}
			continue;
		}
	}

	iCnt = 0;
	while(1)
	{
		iRet = PortSends(&handle, "Ready?", 6, &ulSends);
		if(0 == iRet)
		{
			printf("Handshaking..., SendBytes=%d\n", ulSends);
			memset(szRecvBuffer, 0x00, sizeof(szRecvBuffer));
			iRet = PortRecvs(&handle, szRecvBuffer, 1, &ulRecvs);
			if(0 == iRet)
			{
				if(0 != ulRecvs)
				{
					printf("PortRecvs Succeed, RecvBytes=%d\n", ulRecvs);
					printf("RecvData : %s\n", szRecvBuffer);
				}
				if(szRecvBuffer[0] == 'Y')
				{
					printf("Handshake succeeds\n");
					break;
				}
				else
				{
					if(0 != ulRecvs)
					{
						printf("Handshaking Fail : Not Matched, iCnt=%d, Retrying...\n", ++iCnt);
					}
					else
					{
						printf("Handshaking Fail, iCnt=%d, Retrying...\n", ++iCnt);
					}
					
					PortClearBuffer(&handle, PORT_CLEAR_RX_TX);
					Sleep(10);
					if(iCnt > 10000 * 10)
					{
						PortClose(&handle);
						return 0;
					}
					
					continue;
				}
			}
			else
			{
				printf("Handshaking Fail, iCnt=%d, Retrying...\n", ++iCnt);
				Sleep(10);
				if(iCnt > 10000 * 10)
				{
					PortClose(&handle);
					return 0;
				}
				
				continue;
			}
		}
		else
		{
			PortClearBuffer(&handle, PORT_CLEAR_RX_TX);
			printf("Retry..., iCnt=%d", iCnt);
			if(iCnt > 3)
			{
				printf("PortSends Fail\n");
				PortClose(&handle);
				return 0;
			}
			Sleep(10);
			continue;
		}
	}

	iCnt = 0;
	while(1)
	{
		memset(szRecvBuffer, 0x00, sizeof(szRecvBuffer));
		iRet = PortRecvs(&handle, szRecvBuffer, 4, &ulRecvs);
		if(0 == iRet)
		{
			printf("PortRecvs Succeed, RecvBytes=%d\n", ulRecvs);
			printf("RecvData : %s\n", szRecvBuffer);
			if(strcmp(szRecvBuffer, "CMD1") == 0)
			{
				PortSends(&handle, "Welcome!", strlen("Welcome!"), &ulSends);
			}
			else if(strcmp(szRecvBuffer, "CMD2") == 0)
			{
				PortSends(&handle, "I miss you!", strlen("I miss you!"), &ulSends);
			}
			else if(strcmp(szRecvBuffer, "CMD3") == 0)
			{
				PortSends(&handle, "I waut for you!", strlen("I waut for you!"), &ulSends);
			}
			else if(strncmp(szRecvBuffer, "END", 3) == 0)
			{
				break;
			}
		}
		else
		{
			printf("Waiting CMD, iCnt=%d, Retry...\n", ++iCnt);
	
			continue;
		}
		PortClearBuffer(&handle, PORT_CLEAR_RX_TX);
		
	}

	iRet = PortClose(&handle);
	if(0 == iRet)
	{
		printf("PortClose Succeed\n");
	}
	else
	{
		printf("PortClose Fail\n");
		return -2;
	}

	return 0;
}

// end of file


 

 

Win32串口API使用说明:

1.CreateFile

原型 :

HANDLE CreateFile(
  LPCTSTR lpFileName,
  DWORD dwDesiredAccess,
  DWORD dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD dwCreationDisposition,
  DWORD dwFlagsAndAttributes,
  HANDLE hTemplateFile
);

lpFileName : [入参] Com Port名字,如COM1,COM2,...,COM Port名字长度不能超过MAX_PATH

           如果COM1到COM9,直接可以使用,但如果是COM10以上,则要格式化成\\\\.\\COMxx

           考虑到串口很少情况会使用超过COM100的,所以PortOpen接口对此作了限制。

dwDesiredAccess : [入参] 串口访问权限,包括读(GENERIC_READ)/写(GENERIC_WRITE),

               对串口操作来说,一般需要同时具备读写权限,即GENERIC_READ | GENERIC_WRITE

dwShareMode : [入参] 共享类型。即本进程打开串口后,限制其他进程访问串口的权限控制。

            包括FILE_SHARE_READ/FILE_SHARE_WRITE/FILE_SHARE_DELETE三种共享权限。

            该参数受第二个参数dwDesiredAccess的影响,如你当以GENERIC_READ权限打开串口

            本来就天生不具备WRIET权限,现在你要共享FILE_SHARE_WRITE,这在现实生活中也说不通的。

            同理以GENERIC_WRITE打开却共享FILE_SHARE_READ,也是这样。

            这两种情况在其他进程共享打开时,都会返回错误码ERROR_SHARING_VIOLATION.

            在实际项中一般不共享,传0即可。

lpSecurityAttributes : [入参] 该参数决定子进程是否继承CreateFile返回的句柄HANDLE,

                   参数为NULL,则子进程不继承,相反则继承。在开发中,传NULL的场景更多些。

dwCreationDisposition : [入参] 该参数决定是打开还是新建文件。对串口来说,必须是打开已经存在的。

                    即参数OPEN_EXISTING.

dwFlagsAndAttributes : [入参] 设置打开的文件的一些标志位和属性。对串口来说,该参数主要用于

                    表示串口是同步的还是异步的,0表示同步,FILE_FLAG_OVERLAPPED表示异步。


 hTemplateFile : [入参] 对串口来说,这个参数没意义。因为串口是OPEN_EXISTING,CreateFile在调用时

               会忽略参数hTemplateFile.

 

2.SetupComm

原型 :

BOOL SetupComm(
  HANDLE hFile,
  DWORD dwInQueue,
  DWORD dwOutQueue
);

该函数主要设置串口通讯的读缓冲区和写缓冲区大小,如果在CreateFile打开串口后,没有调用SetupComm

设置缓冲区大小,则会使用默认的缓冲区大小。

 

 3.COMMTIMEOUTS

原型 :

typedef struct _COMMTIMEOUTS {  
   DWORD ReadIntervalTimeout;  
   DWORD ReadTotalTimeoutMultiplier;  
   DWORD ReadTotalTimeoutConstant;  
   DWORD WriteTotalTimeoutMultiplier;  
   DWORD WriteTotalTimeoutConstant;
}  COMMTIMEOUTS,  *LPCOMMTIMEOUTS;


这里主要看看这个结构体各个成员的含义。

每个成员使用的超时单位都是以毫秒来计算的。

a.ReadIntervalTimeout :接收到第一个字节以后该参数才使用,计算每两个接收到的字节的隔间时间,如果

                   大于ReadIntervalTimeout,则立即返回读缓冲区中的数据。

b.ReadTotalTimeoutMultiplier : 乘数因子,计算方式为TotalTimeout =  乘数因子X 已经接收到的字节数

                   如果接收的字节数的实际使用时间大于计算出来的TotalTimeout,则超时了。

                   当然,总的超时时间还要依赖ReadTotalTimeoutConstant

c.ReadTotalTimeoutConstant : 常量因子,此时配合ReadTotalTimeoutMultiplier计算总的超时时间为:

                    TotalTimeout =乘数因子X 已经接收到的字节数 + 常量因子。

d.如果ReadTotalTimeoutmultiplier和ReadTotalTimeoutConstant同时设置为0,

则在接收字节时忽略总超时时间。

e.WriteTimeoutMultiplier和WriteTotalTimeoutConstant :原理同b,c,d。

 

 4.SetCommTimeouts

 原型 :

BOOL SetCommTimeouts(
  HANDLE hFile,
  LPCOMMTIMEOUTS lpCommTimeouts
);

只要理解上面的结构体COMMTIMEOUT各个成员变量的含义,这个函数就比较简单了。

 

5.DCB

原型 :

typedef struct _DCB {  
  DWORD DCBlength;  
  DWORD BaudRate;  
  DWORD fBinary  :1;  
  DWORD fParity  :1;  
  DWORD fOutxCtsFlow  :1;  
  DWORD fOutxDsrFlow  :1;  
  DWORD fDtrControl   :2;  
  DWORD fDsrSensitivity    :1;  
  DWORD fTXContinueOnXoff  :1;  
  DWORD fOutX  :1;  
  DWORD fInX   :1;  
  DWORD fErrorChar  :1;  
  DWORD fNull  :1;  
  DWORD fRtsControl  :2;  
  DWORD fAbortOnError  :1;  
  DWORD fDummy2  :17;  
  WORD wReserved;  
  WORD XonLim;  
  WORD XoffLim;  
  BYTE ByteSize;  
  BYTE Parity;  
  BYTE StopBits;  
  char XonChar;  
  char XoffChar;  
  char ErrorChar;  
  char EofChar;  
  char EvtChar;  
  WORD wReserved1;
} DCB;


这个结构体成员变量很多,这里只针对BaudRate,ByteSize,Parity,StopBits作说明

BaudRate : 常用的波特率有 CBR_9600/CBR_57600/CBR_115200,当然也可以使用自定义的波特率。

ByteSize : 在接收到的一个字节中,使用多少二进制位表示实际数据。可以去5,6,7,8

Parity   : 奇偶校验位,不同的值,校验算法不同。其值可以去EVENPARITY,MARKPARITY,NOPARITY

          ODDPARITY,SPACEPARITY。

          一般我选择NOPARITY,然后自己在应用层制定自己的传输协议,在协议中增加校验部分,

          如LRC,CRC等校验。

StipBits : 停止位,其值为ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS

 

其中,ByteSize为5时,StopBits不能是TWOSTOPBITS

     ByteSize为6,7,8时,StopBits不能是ONE5STOPBITS

不然在CreateFile会报错,返回的句柄是INVALID_HANDLE_VALUE;

 

6.SetCommState

原型 :

BOOL SetCommState(
  HANDLE hFile,
  LPDCB lpDCB
);


只要了解DCB结构体,这个函数就简单了。


 

 


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值