多线程,多接收模式串口类 LsComm 之二
多线程,多接收模式串口类 LsComm 之二
作者:liu_sir
描述:一个串口通讯类
应用平台:Windows
版本:v1.2
上次我做的“多线程,多接收模式串口类LsComm”,说实在的有不少的问题
。 好不容易有一段空闲的时间,把以前发现的Bugs修改了一下。
一、Bugs修正
1.ERR : 修改了98下 AutoReceiveBySignal 模式不能正常执行的bug
原因: CcomPort::m_WriteOverlapped.hEvent 没有设置事件!!!!粗心,害人阿。导致在Win98下发送数据异常,不过奇怪在
Win2K正常,而且测试的时候忽略了测试环境平台的影响。
修改: 相应的代码
if(this-IsOverlapped())
{
this-m_hWriteEvent= ::CreateEvent(NULL,true,false,NULL);
if(this-m_hCloseEvent==NULL) return false;
this-m_WriteOverlapped.hEvent = this-m_hWriteEvent;
}2.ERR : 修改了 ManualReceiveByQuery 模式下,发送会出现不动的情况。
原因: 在dwWriteBytes= this-m_pPort-Write(pBuf,Count);
前,串口已经设置中断,所以需要等待中断事件发生。
修改: 去掉中断设置的代码
this-m_pPort-GetSerialPort()-SetMask(dwStoredFlags);
3.ERR : 打开一个计算机上不存在的串口的时候没有异常捕获。
原因: 没有捕获 CserialPort 抛出的 CserialException 异常
修改: 不过对于异常的处理改为不抛出异常,不知道是否妥当?
try
{
this-m_pPort-Open(nPort,dwBaud,spParity,DataBits,spStopbits,spFC,m_IsOverlapped);
}
catch(CSerialException* pE)
{
//AfxMessageBox(pE-GetErrorMessage());
pE-Delete();
return false;
}
4.ERR : 感觉 AutoReceiveByBreak 意义不大应该去掉
原因: 全部的事件都可以用AutoReceiveBySignal方式实现
修改: 暂时保留:DWORD dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |EV_RLSD | EV_RXCHAR | EV_RXFLAG ;
//??| EV_TXEMPTY 添加后在首次执行时总是接收不到全部数据
,以后就正常了。现在还搞不清楚是什么原因。
5.ERR : 感觉 ManualReceiveByConst 意义不大应该去掉
原因: 实现方式不太好
修改: 暂时保留
二、遗留问题
1.ERR : 流控制模式下可能不正确,自己在这方面没有经验,没有测试。
2.ERR : 结构问题,把 this-m_ComPort.GetSerialPort() 获取
CserialPort 的指针好像不妥,如果类的使用者在程序中这样用
this-m_ComPort.GetSerialPort()-Close();收发数据的时候就会产生异常。但是由于使用别人的CserialPort类
,比较
稳定,但有不能破坏别人代码的完整性。
3.ERR : ManualReceiveByConst 方式受 CommTimeOUts 的影响可能不太准确。
其它问题:我的计算机上只有一个串口可用,所以是2-3口短接进行的测试,其它测试还不太完全。
三、由于前一段时间确实比较忙,有好多网友提出的问题,都没有回复,实在非常抱歉,在这里简单的回复一下
1.风也飘飘:你好,我感觉这个类做的很好,但我想实现两台电脑之间的实时数据传输(为字符型),不知道怎么用,可否指点一二?
答: 感觉可以这样写:
(1)首先:定义一个接收函数:
void OnReceiveData(LPVOID pSender,void* pBuf,DWORD InBufferCount)
{//在此处理要接收的数据
} (2)然后,打开串口,监听Com2 this-m_ComPort.Open(2,LsComm::CComPort::AutoReceiveBySignal );
this-m_ComPort.SetReceiveFunc((FOnReceiveData)OnReceiveData,this);
(3)发送: char a[10000];//字符数组
BYTE b[10000];//字节数组
memset(a,''''a'''',sizeof(a));
memset(b,0x0b,sizeof(b));
this-m_ComPort.Output(a,sizeof(a)); //发送字符数组
this-m_ComPort.Output(b,sizeof(b)); //发送字节数组
感觉在C里面是不分 char 和字节的,像 char c=’a’;和char c=0x61;是一样的,只不过 char
只能取字符类型范围,超过就被截短。
2.zkf00:中断接收函数OnComBreak怎么用?
答:试验了一下
void OnComBreak(LPVOID pSender,DWORD dwMask,COMSTAT stat)
{
//deal with the break of com here
switch(dwMask)
{
case EV_BREAK:
{
break;
}
case EV_CTS: //在这里处理CTS信号
{
break;
}
}
}
3.greatim:DataWaiting 是有什么用的??在例子程序里没有引用到。而且在 Open 的函数里,CreateEvent 被屏蔽了,是否代表
DataWaiting 这函数不能使用呢? DataWaiting 和 Attech 有什么关系?
答:因为 DataWaiting 是 PJ Naughter 写的,请仔细看他的源码:
BOOL CSerialPort::DataWaiting(DWORD dwTimeout)
{
ASSERT(IsOpen());
ASSERT(m_hEvent);
//Setup to wait for incoming data
DWORD dwOldMask;
GetMask(dwOldMask);
SetMask(EV_RXCHAR);//1.设置接收中断事件
//Setup the overlapped structure
OVERLAPPED o;
o.hEvent = m_hEvent;
//Assume the worst;
BOOL bSuccess = FALSE;
DWORD dwEvent;
bSuccess = WaitEvent(dwEvent, o);//2. 设置监听
if (!bSuccess)
{//3.dwTimeOut为所等待的时间,有数据收到,返回发现数据
if (WaitForSingleObject(o.hEvent, dwTimeout) == WAIT_OBJECT_0)
{
DWORD dwBytesTransferred;
GetOverlappedResult(o, dwBytesTransferred, FALSE);
bSuccess = TRUE;
}
}
//Reset the event mask
SetMask(dwOldMask);
return bSuccess;
}
这好像与 Attach 没什么关系吧?
4.Sander:在win2000下能用no overlapped吗?
答:查看了一下 MSDN 中 CreateFile 的说明,没有在 Win2K 下的使用限制,应该是可以的。
5.Sander:当用 ExecuteByAutoSignalRecvMode,
BOOL bSuccess = ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, &overlapped);
dwSignaledHandle=::WaitForMultipleObjects(3,WaitHandles,false,INFINITE);
或
this-m_pPort-GetSerialPort()-GetOverlappedResult(overlapped,this-m_InBufferCount,false)
这个两个函数
WaitForMultipleObject
或
GetOverlappedResult)
它会以 COMMTIMEOUTS 中设置的 timeout 来返回吗?也就是说 Overlapped 中的 Event 是在什么时候激活的?
答:这个问题我以前没有仔细考虑,真是不好意思。好像 COMMTIMEOUTS的TimeOut 仅对 ReadFile,WriteFile 起作用,具体可以看 MSDN 中 COMMTIMEOUTS 的描述
。
WaitForSingleObject(m_ReadOverlapped.hEvent,dwMilliseconds)==WAIT_OBJECT_0)
会等待 m_ReadOverlapped.hEvent 事件置信号标志的时候返回。那么读取
时间什么时候返回呢,找了下面的一段话:
When reading from a communications device, the behavior of ReadFile is governed by the current
communication time-outs as set and retrieved using the SetCommTimeouts and GetCommTimeouts
functions. Unpredictable results can occur if you fail to set the time-out values. For more
information about communication time-outs, see COMMTIMEOUTS.
可见 SetCommTimeouts 对这 ReadFile 起作用,也就是对 m_ReadOverlapped.hEvent 起作用。因此定时间接收模式在 COMMTIMEOUTS 时也会置读事件的 hEvent,所以等待
时间的限制就有可能不太准确。
6.Hi_nihaoma:为什么我使用重叠方式打开串口,根据示例:
for(int j= 0; j< 10; j++)
{
if (!port2.Write(pBuf, 10000, overlapped))
{
DWORD dwBytesWritten;
WaitForSingleObject(event, INFINITE);
port2.GetOverlappedResult(overlapped, dwBytesWritten, TRUE);
}
if (!port2.Read(pBuf, 10, overlapped))
{
DWORD dwBytesRead;
if (WaitForSingleObject(event,1000) == WAIT_OBJECT_0)
{
TRACE(_T("Data was read from the serial port\n"));
port2.GetOverlappedResult(overlapped,dwBytesRead,FALSE);
}
else
TRACE(_T("No data was read from the serial port\n"));
}
port2.SetMask(EV_TXEMPTY);
port2.WaitEvent(dwMask,overlapped);
}
port2.GetOverlappedResult(overlapped,dwBytesRead,FALSE);
dwByteRead= 4啊???急急急!!!
答:感觉可能是接收的问题,不能所有容纳发送的全部数据,而引发异常吧。看你这行port2.Write(pBuf, 10000, overlapped);一次发送这么大的数据量
,是不是这的问题,
我的计算机上只有一个串口,把2,3口连接后收发数据测试了一下。一次发送超过100个就会发生读地址错误,但是低于这个速率就没问题。可能是接收的速度跟不上吧
。具体问题正在找。
结束语:
本来早就想要改一下,可实在是没有时间,不是开玩笑,大概3个月没有时间上网看看新闻了。写程序,就是要认真仔细的面对自己写的每一行代码
,不放过自己的每一个Bug。谁都希望自己的程序不出一个Bug,可这实在是说起来容易做起来难。希望大家看到Bugs要贴在下面,有时间我会努力改的。上面的一些问题自己的水平实在是太有限了
,搞得还不是太清楚,希望如果谁知道,就告诉偶。有些问题就得摆出来,然后再一点点搞清楚才会有提高。如果只是默许的认为简单,容易,不求甚解,相反会害了自己。