1、先入为主,实例开始,可以编写测试程序向串口发送数据,并用串口监测工具Access Port监测串口通信数据
a、设计串口类
class ComDevice { public: ComDevice(); ~ComDevice(); //打开串口 int OpenCom(char *,LPDCB);//char指向串口逻辑名,LPDCB指向设备控制块数据结构 int CloseCom();//关闭串口 int Read(char *,DWORD);//读串口收到的数据(一次) int Write(char *,DWORD,DWORD);//向串口发送数据 public: DWORD m_error_code;//最后一次操作错误码 DCB m_state;//串口配置 COMMTIMEOUTS m_Timeouts;//读写超时时间 HANDLE m_handle;//串口句柄 };
int ComDevice::OpenCom(char *port,LPDCB lpDCB) { this->m_error_code = 0;//操作错误码复位 /*如果串口已经打开*/ if(this->m_handle != NULL) return -1; //打开串口 this->m_handle = CreateFile(port,GENERIC_READ | GENERIC_WRITE,//读写方式打开 0, NULL, OPEN_EXISTING,//已经创建,则打开即可 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,//重叠方式(异步) NULL); if(this->m_handle == INVALID_HANDLE_VALUE) { this->m_error_code = ::GetLastError();//获取错误码 this->m_handle = NULL; return -2; } //初始化串口信息 //设置串口读写缓冲区大小 if(!SetupComm(this->m_handle,4200,4200)) return -1; //终止所有的异步数据读写操作并清空读写缓冲区 if(!PurgeComm(this->m_handle,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) return -1; if(!GetCommState(this->m_handle,&m_state)) return -1; /*设置一些需要修改的信息即可,其他使用系统默认值*/ this->m_state.DCBlength = sizeof(lpDCB); this->m_state.BaudRate = lpDCB->BaudRate;//传输速率 this->m_state.ByteSize = lpDCB->ByteSize;//指定端口当前使用数据位数 this->m_state.Parity = lpDCB->Parity;//奇偶校验 this->m_state.StopBits = lpDCB->StopBits;//指定当前串口使用停止位数 this->m_state.fOutxDsrFlow = lpDCB->fOutxDsrFlow;//指定DSR是否用于检测发送流控制,当该成员为TRUE,而DSR为OFF时,发送将被挂起,直到DSR置ON。 this->m_state.fDtrControl = lpDCB->fDtrControl;//DTR流量控制 this->m_state.fOutxCtsFlow = lpDCB->fOutxCtsFlow;//指定CTS是否用于检测发送流控制 this->m_state.fRtsControl = lpDCB->fRtsControl;//RTS流量控制 if(!SetCommState(this->m_handle,&(this->m_state))) return -1; return 0; }c、读串口数据
int ComDevice::Read(char *readBuff,DWORD readLen) { COMSTAT state; DWORD error_ = 0; DWORD len = 0; this->m_error_code = 0; if(this->m_handle == NULL) return -1; //读取DTR信号判断串口连接是否有效 if(this->m_state.fOutxDsrFlow == true) { DWORD sig_mask = 0; GetCommModemStatus(this->m_handle,&sig_mask); if((sig_mask & MS_DSR_ON) != MS_DSR_ON)//fOutxDsrFlow为true时,DSR必须为ON,才能发送数据 return -1; } //清除串口错误 if(!ClearCommError(this->m_handle,&error_,&state)) { this->m_error_code = ::GetLastError(); return -1; } //设置超时 if(!SetCommTimeouts(this->m_handle,&m_Timeouts)) { this->m_error_code = ::GetLastError(); return -1; } OVERLAPPED os_read;//重叠结构体(用于异步I/O操作) memset(&os_read,0,sizeof(OVERLAPPED));//初始化结构体 if((os_read.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL)//创建重叠事件 { this->m_error_code = ::GetLastError(); return -2; } if(!::ReadFile(this->m_handle,readBuff,readLen,&len,&os_read)) { //判断是否读完 if((this->m_error_code = ::GetLastError()) == ERROR_IO_PENDING) ::GetOverlappedResult(this->m_handle,&os_read,&len,TRUE);//获取重叠操作结果 } this->m_error_code = ::GetLastError(); ::CloseHandle(os_read.hEvent);//关闭重叠事件句柄 return (int)len; }d、向串口写数据
int ComDevice::Write(char *SndBuff,DWORD SndLen,DWORD mTime) { COMSTAT state; DWORD error_ = 0; DWORD len = 0; this->m_error_code = 0; if(this->m_handle == NULL) return -1; if(this->m_state.fOutxDsrFlow == TRUE) { DWORD sig_mask = 0; ::GetCommModemStatus(this->m_handle,&sig_mask); if((sig_mask & MS_DSR_ON) != MS_DSR_ON) return -1; } if(!PurgeComm(this->m_handle,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) { this->m_error_code = ::GetLastError(); return -1; } COMMTIMEOUTS time_out; time_out.ReadIntervalTimeout = MAXDWORD; time_out.ReadTotalTimeoutConstant = 0; time_out.ReadTotalTimeoutMultiplier = 0; time_out.WriteTotalTimeoutConstant = mTime time_out.WriteTotalTimeoutMultiplier = mTime; if(!::SetCommTimeouts(this->m_handle,&time_out)) { this->m_error_code = ::GetLastError(); return -1; } if(!ClearCommError(this->m_handle,&error_,&state)) { this->m_error_code = ::GetLastError(); return -1; } OVERLAPPED os_write; memset(&os_write,0,sizeof(OVERLAPPED)); if((os_write.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) { this->m_error_code = ::GetLastError(); return -2; } if(!::WriteFile(this->m_handle,SndBuff,SndLen,&len,&os_write)) { if((this->m_error_code = ::GetLastError()) == ERROR_IO_PENDING) ::GetOverlappedResult(this->m_handle,&os_write,&len,TRUE); } this->m_error_code = ::GetLastError(); ::CloseHandle(os_write.hEvent); return len; }
int ComDevice::CloseCom() { this->m_error_code = 0; if(this->m_handle == NULL) return 0; if(!EscapeCommFunction(this->m_handle,CLRDTR))//关闭DTR信号 this->m_error_code = GetLastError(); if(!PurgeComm(this->m_handle,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) { this->m_error_code = ::GetLastError(); //return -1; } if(! ::CloseHandle(this->m_handle)) { this->m_error_code = ::GetLastError(); return -2; } this->m_handle = NULL; return 0; }
windows中串口和其它通信设备被当做文件处理,和linux差不多,串口的打开、读取、写入、关闭函数和文件操作函数一致。
a、串口打开函数hTemplateFile:hTemplateFile:指向模板文件的句柄,当端口处于打开状态时,不使用该参数,因而必须置成0
b、设置串口缓冲区大小BOOL SetupComm(HANDLE hFile,DWORD dwInQueue , DWORD dwOutQueue);
c、关闭串口CloseHandle(HANDLE hObject);
d、获取串口当前配置• lpDCB:一个非常重要的结构—设备控制块DCB ( Device Control Block )。
DCB结构的主要参数说明如下:g、读串口操作
BOOLReadFile(HANDLE hFile , LPVOID lpBuffer , DWORD nNumberOfBytesToRead , LPDWORDlpNumberOfBytesRead , LPOVERLAPPED lpOverlapped)
参数介绍:
·hFile:指向标识的句柄。对串口来说,就是由CreateFile函数返回的句柄。该句柄必须拥有GENERIC_READ的权限。
·lpBuffer:指向一个缓冲区,该缓冲区主要用来存放从串口设备中读取的数据。
·nNumberOfBytesToRead:指定要从串口设备读取的字节数。
·lpNumberOfBytesRead:指向调用该函数读出的字节数。ReadFile()在读操作前,首先将其设置为0。Windows NT/2000中当lpOverlapped没有设置时,lpNumberOfBytesRead必须设置。当lpOverlapped设置时,lpNumberOfBytesRead可以不设置。这是可以调用GetOverlappedResult()函数获取实际的读取数值。Windows 9x中这个参数一定要设置。
·lpOverlapped:是一个OVERLAPPED的结构,该结构将在后面介绍。如果hFile以FILE_FLAG_OVERLAPPED方式常见,则需要此结构;否则,不需要此结构。
h、写串口数据
BOOL WriteFile(HANDLE hFile , LPVOID lpBuffer , DWORDnNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWriten, LPOVERLAPPED lpOverlapped)
参数介绍:
·hFile:指向标识的句柄。对串口来说,就是由CreateFile函数返回的句柄。该句柄必须拥有GENERIC_READ的权限。
·lpBuffer:指向一个缓冲区,该缓冲区主要用来存放待发送数据。
·nNumberOfBytesToWrite:指定向串口写入的字节数。
·lpNumberOfBytesWriten:指向调用该函数已写入的字节数。WriteFile()在写操作前,首先将其设置为0。Windows NT/2000中当lpOverlapped没有设置时,lpNumberOfBytesWriten必须设置。当lpOverlapped设置时,lpNumberOfBytesWriten可以不设置。这是可以调用GetOverlappedResult()函数获取实际的写入数值。Windows 9x中这个参数一定要设置。
·lpOverlapped:是一个OVERLAPPED的结构,该结构将在后面介绍。如果hFile以FILE_FLAG_OVERLAPPED方式常见,则需要此结构;否则,不需要此结构。
i、异步I/O操作
OVERLAPPED结构:
typedef struct_OVERLAPPED{
DWORD Iternal;//系统保留,指定一个和系统相关的状态
DWORD IteralHigh;//系统保留,指出发送或接收数据长度
DWORD Offset;//指定文件传送的起始位置
DWORD OffsetHigh;//指定文件传送字节便宜的高位字
HANDLE hEvent;//指定I/O操作完成后出发的事件
}OVERLAPPED;
异步I/O可有GetOverlappedResult()函数获取操作结果
BOOLGetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,LPDWORDlpNumberOfBytesTransfered,BOOL bWait);
j、超时设置
超时结构体定义:
typedef struct_COMMTIMEOUTS{
DWORD ReadIntervalTimeout;//指定通信线路上两个字符到达之间的最大时间间隔(ms)
DWORD ReadTotalTimeoutMutiplier;//计算读操作总时间的系数(单位:ms)
DWORD ReadTotalTimeoutConstant;//计算读操作总时间的常数(单位:ms)
DWORD WriteTotalTimeoutMutiplier;//计算写操作总时间的系数(单位:ms)
DWORD WriteTotalTimeoutCaonstant;//计算写操作总时间的常数(单位:ms)
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
获取当前超时参数:
BOOLGetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts)
设置超时参数:
BOOLSetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts)