【MFC】串口通信接收模块底层函数API
前言
最近在做wince平台的上位机开发,关于串口通信都是直接调用系统底层的API函数,所以特地研究了一下串口通信的实现方法
正文
SetCommMask()函数
取得 串行端口事件信息,必须先设函数置信息掩码。简单来说,就是过滤条件。
SetCommMask()函数原型:
BOOL SetCommMask(HANDLE hFile, //标识通信端口的句柄
DWORD dwEvtMask //能够使能的通信事件
);
- hFile:
串行端口的Handle值,此值即为使用CreateFile函数后所返回的值。 - dwEvtMask :
信息掩码位值,由下列常组成,若没为0则取消所有的信息检测。
项目 | Value |
---|---|
EV_BREAK | 收到Break信号。 |
EV_CTS | CTS(Clear To Send)线路发生变化。 |
EV_DSR | DSR(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 | 在输出缓冲区中的数据己被完全送出。 |
举例:
SetCommMask(hComm, EV_RXCHAR | EV_CTS | EV_DSR);
WaitCommEvent()函数
使用SetCommMask函数设置所要检测的事件后,当此事件发生时,就可以用WaitCommEvent得知该事件是否已发生,若此函数返回True,表示设置的信息已发生。
函数原型:
BOOL WaitComrnEvent(
HANDLE hFi1e, //通信设备的句柄
LPWORD lpEvtMask,//发生的事件变量的地址
LPOVERLAPFED lpoverlapped //Overlapped结构的地址
)
- hFile:
串行端口的Handle值,此值即为使用CreateFile函数后所返回的值。 - IpEvtMask:
指向所检测到的信息的参数地址,32位长度,信息常数如SetCommMask函数的第二个参数,若发生错误,则此值返回0。 - IpOverlapped:
使用Overlapped方式打开文件时应给定的结构,在串行通信中若不采用后台工作时,则可不使用;但是在不使用Overlapped的情形下,若己设置了信息屏蔽,则会使得程序停在比函数上,一直到有事件发生,并被检到为止,才会离开等待的状态,因此使用时需注意,最好还是使用Overlapped结构在等待息的程序。
返回值:
如果函数成功,返回非零值,否则返回0。要得到错误信息,可以调用GetLastError函数。
注意:
如果hFile是用异步方式打开的,而lpOverlapped 指向一个非空的OVERLAPPED结构体,那么函数WaitCommEvent被默认为异步操作,马上返回。这时,OVERLAPPED结构体必须包含一个由CreateEvent()函数返回的手动重置事件对象的句柄hEven。
如果hFile是用同步方式打开的,那么函数WaitCommEvent不会返回,直到要等待的事件发生。
程序举例:
网上关于wince下串口编程的方法大同小异,下面贴出接收线程部分代码。
// A code block
//串口读线程函数
DWORD CCESeries::ReadThreadFunc(LPVOID lparam)
{
CCESeries *ceSeries = (CCESeries*)lparam;
DWORD evtMask;
BYTE * readBuf = NULL;//读取的字节
DWORD actualReadLen=0;//实际读取的字节数
DWORD willReadLen;
DWORD dwReadErrors;
COMSTAT cmState;
// 清空缓冲,并检查串口是否打开。
ASSERT(ceSeries->m_hComm !=INVALID_HANDLE_VALUE);
//清空串口
PurgeComm(ceSeries->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR );
SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
while (TRUE)
{
if (WaitCommEvent(ceSeries->m_hComm,&evtMask,0))
{
SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
//表示串口收到字符
if (evtMask & EV_RXCHAR)
{
ClearCommError(ceSeries->m_hComm,&dwReadErrors,&cmState);
willReadLen = cmState.cbInQue ;
if (willReadLen <= 0)
{
continue;
}
readBuf = new BYTE[willReadLen];
ZeroMemory(readBuf,willReadLen);
//读取串口数据
ReadFile(ceSeries->m_hComm, readBuf, willReadLen, &actualReadLen,0);
//如果读取的数据大于,
if (actualReadLen>0)
{
//触发读取回调函数
if (ceSeries->m_OnSeriesRead)
{
ceSeries->SeriesRead(ceSeries->m_pOwner,readBuf,actualReadLen);
actualReadLen = 0;
}
}
//释放内存
delete[] readBuf;
readBuf = NULL;
}
}
//如果收到读线程退出信号,则退出线程
if (WaitForSingleObject(ceSeries->m_hReadCloseEvent,500) == WAIT_OBJECT_0)
{
break;
}
}
return 0;
}
//关闭读线程
void CCESeries::CloseReadThread()
{
SetEvent(m_hReadCloseEvent);
//设置所有事件无效无效
SetCommMask(m_hComm, 0);
//清空所有将要读的数据
PurgeComm( m_hComm, PURGE_RXCLEAR );
//等待秒,如果读线程没有退出,则强制退出
if (WaitForSingleObject(m_hReadThread,2000) == WAIT_TIMEOUT)
{
TerminateThread(m_hReadThread,0);
}
m_hReadThread = NULL;
}
参考链接
链接1: 串口开发中使用WaitCommEvent.
链接2: 串口编程C++实例(CE).