Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2070056
  • 博文数量: 909
  • 博客积分: 4000
  • 博客等级: 上校
  • 技术积分: 12260
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-06 20:50
文章分类

全部博文(909)

文章存档

2008年(909)

我的朋友

分类:

2008-05-06 22:11:35

一起学习
多线程,多接收模式串口类 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要贴在下面,有时间我会努力改的。上面的一些问题自己的水平实在是太有限了 ,搞得还不是太清楚,希望如果谁知道,就告诉偶。有些问题就得摆出来,然后再一点点搞清楚才会有提高。如果只是默许的认为简单,容易,不求甚解,相反会害了自己。
下载本文示例代码


多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二多线程,多接收模式串口类 LsComm 之二
阅读(483) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~