本帖最后由 李维强-15级 于 2015-6-9 11:55 编辑
一个关于新建线程中,用MSComm控件接收数据的问题,现在情况是这样。
我在主窗口拖了一个MSComm控件到窗口里面去, 用类向导关联这个控件,并且设变量名为m_ComPort。
然后把这个m_ComPort初始化好,并且把事件响应这些函数都处理都弄好。
以下是我主窗口程序事件的定义和接收数据函数
我先在头文件里面定义一个数组 用来装数据,和之前说的MSComm控件变量
[C++] syntaxhighlighter_viewsource syntaxhighlighter_copycode
CMSComm m_ComPort;
BYTE rxdata[1024];
然后在CPP文件里面做了如下定义
[C++] syntaxhighlighter_viewsource syntaxhighlighter_copycode
void CMyPortDlg:Init()
{
这里里面做m_ComPort;初始化的操作主要为:
m_ComPort.SetCommPort(1); //选择COM1
m_ComPort.SetInBufferSize(1024); //接收缓冲区
m_ComPort.SetOutBufferSize(1024);//发送缓冲区
m_ComPort.SetInputLen(0);//设置当前接收区数据长度为0,表示全部读取
m_ComPort.SetInputMode(1);//以二进制方式读写数据
m_ComPort.SetRThreshold(1);//接收缓冲区有1个及1个以上字符时,将引发接收数据的OnComm事件
m_ComPort.SetSettings("9600,n,8,1");//波特率9600无检验位,8个数据位,1个停止位
….
…
}
void CMyPortDlg:Send(CString strData)
{
这个里面把参数strData传进来的字符 转换成16进制数据,通过串口发出去
}
BEGIN_EVENTSINK_MAP(CSportDlg, CDialog)
//{{AFX_EVENTSINK_MAP(CSportDlg)
ON_EVENT(CMyPortDlg, IDC_MSCOMM1, 1 /* OnComm */, OnCommMscomm1, VTS_NONE)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
void CMyPortDlg::OnCommMscomm1()
{
// TODO: Add your control notification handler code here
VARIANT variant1;
COleSafeArray safearray;
LONG len,k;
if(m_ComPort.GetCommEvent()==2)
{
variant1 = m_ComPort.GetInput();
safearray = variant1;
len = safearray.GetOneDimSize();
for(k=0;k<len;k++)
{
safearray.GetElement(&k,rxdata+k);
}
然后再简单的分析数据,几行代码;
}
}
如果用以上代码 在主窗口线程里面去发送和接收都没有问题。我发送一个数据给下位机,下位机马上就反馈数据回来给我程序了。
但是我因为程序需要,需要在新建线程里面去发送数据和接收数据,结果就带来了以下问题,把我困扰惨了。。。
我新建线程AfxBeginThread(MyThread1,this);然后把主窗口线程的this指针传给新建线程,为了就是调用主窗口的CMyPortDlg:Send()这个发送数据函数;
[C++] syntaxhighlighter_viewsource syntaxhighlighter_copycode
UINT CProduceDlg::MyThread1(void *param)
{
CMyPortDlg * Dlg =(CMyPortDlg *)param;
…
…
}
下面我要在新线程里面给下位机发命令,让下位机启动一段时间,让它搜集数据,过5秒后发命令让其关闭,然后我再发命令给下位机,让它返回一个通过刚才5秒钟收集数据,然后经过处理后的数据。
然后我在新建线程MyThread1里面这样做
[C++] syntaxhighlighter_viewsource syntaxhighlighter_copycode
UINT CProduceDlg::MyThread1(void *param)
{
CMyPortDlg * Dlg =(CMyPortDlg *)param;
Dlg->Send("FFAAAAFF"); //发送启动命令
Sleep(5000); //这里延迟5秒 ,并且让主窗口线程响应ON_EVENT事件
Dlg->Send("FF0000FF"); //发送关闭命令
Sleep(500); //这里延迟一下,也让主窗口响应ON_EVENT
Dlg->Send("FFBBBBFF"); //发送查询命令
Sleep(1000); //延迟1秒,留出足够的时间让下位机返回数据
然后操作rxdata[]里面的数据
}
我记得很早听人说 Sleep这个函数可以让出CPU执行权,在Sleep的时间里面,可以让其他线程执行程序,所以我故意在发送启动命令后延迟5秒,我以为这5秒可以让主窗口线程响应足够多的ON_EVENT事件,结果调试跟踪发现,在延迟5秒期间,主程序1次都没有响应ON_EVENT事件,而是在我发送Dlg->Send("FF0000FF ");这个关闭命令过后,主程序里面的ON_EVENT事件才来,而且来的不是m_ComPort.GetCommEvent()==2,GetCommEvent()返回的是1008,也就是“缓冲区溢出”,(因为我给下位机发送启动命令后,下位机会每3ms就发送一个数据给我电脑),而且是连续返回几个这个溢出事件,等着几个溢出事件响应完了,程序执行“Dlg->Send("FFBBBBFF");//发送查询命令”过后,新线程里面再执行Sleep(1000);,在这期间主窗口也不会响应ON_EVENT事件,所以我写在OnComm里面的那些数据处理操作根本就不执行,以至于后面我新线程里面最后 “操作rxdata[]里面的数据”,根本就是无效操作。
于是我把代码改为下面一种
[C++] syntaxhighlighter_viewsource syntaxhighlighter_copycode
UINT CProduceDlg::MyThread1(void *param)
{
CMyPortDlg * Dlg =(CMyPortDlg *)param;
Dlg->Send("FFAAAAFF"); //发送启动命令
pMyThread->SuspendThread() //把线程挂起 然后在 OnComm里面判断收到足够数据就恢复
…
..
}
结果 把线程一挂起,线程就永远挂起了,主窗口线程也不会响应任何一个ON_EVENT事件,也就根本就无法进入到OnComm函数,也就无法恢复。
我看MSDN里面说Sleep(0);可以让出时间片,让后我加进MyThread1里面各个地方,各种不同加法,结果还是不行,主线程都不得响应ON_EVENT,或者像我注释里面 理想的那样 去响应ON_EVENT事件,从而顺利的进入OnComm里面去操作数据。。。
我能确定在线程里面Dlg->Send("FFAAAAFF");这个命令一定起作用了的,下位机也不断向我电脑发数据,我下位机上有显示的。关键问题就是在响应ON_EVENT事件这里出问题。
|