MFC对话框程序开线程读串口,界面卡主解决方案 本帖最后由 VisualEleven 于 2013-08-09 12:21:02 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 改用异步模式 试试看Serial Communications in Win32 //设定读超时 TimeOuts.ReadIntervalTimeout=0; TimeOuts.ReadTotalTimeoutMultiplier=0.5; TimeOuts.ReadTotalTimeoutConstant=1;你好,发现更改读超时可以缓解界面卡的问题,需要设成很小才行,但是这样在while循环里读串口就太快了,并且串口给buff的总是0,我有一个自动应答的功能加了定时器来判断串口是否返回数据判断bReadStat是否为1,而buff被传进了0,bReadStat也是1,这不是我想要的,不知道说的清不清楚,帮忙看看吧,谢谢! Sleep(1),while中地方任选会好。PS:楼主按钮是开线程启动的么?如果不是用线程的话,是会非常卡的。另外,如果楼主开了线程还卡的话,那么说明楼主电脑估计是单核的。 按说吧超时设大些就可以啊TimeOuts.ReadIntervalTimeout=50;TimeOuts.ReadTotalTimeoutMultiplier=50;TimeOuts.ReadTotalTimeoutConstant=100;把调用CreateFile的那段贴出来看看 }*/ hcom=CreateFile(SerialName,GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING,0, NULL); int t=GetLastError(); if(hcom==INVALID_HANDLE_VALUE) { AfxMessageBox(_T("打开串口失败!")); return false; } else{ //指定端口监测的事件集 SetupComm(hcom,100,100); //输入缓冲区和输出缓冲区的大小都是100 COMMTIMEOUTS TimeOuts; //设定读超时 TimeOuts.ReadIntervalTimeout=1000; TimeOuts.ReadTotalTimeoutMultiplier=0.5; TimeOuts.ReadTotalTimeoutConstant=1; //在读一次输入缓冲区的内容后读操作就立即返回, //而不管是否读入了要求的字符。 //设定写超时 TimeOuts.WriteTotalTimeoutMultiplier=100; TimeOuts.WriteTotalTimeoutConstant=500; SetCommTimeouts(hcom,&TimeOuts); //设置超时 DCB dcb; GetCommState(hcom,&dcb); dcb.BaudRate=(DWORD)BaudRate; //波特率为38400 dcb.ByteSize=8; //每个字节有8位 dcb.Parity=NOPARITY; //无奇偶校验位 dcb.StopBits=ONESTOPBIT; //一个停止位 PurgeComm(hcom,PURGE_TXCLEAR|PURGE_RXCLEAR);} return TRUE; TimeOuts.ReadTotalTimeoutMultiplier=50;TimeOuts.ReadTotalTimeoutConstant=100;这个稍微设大点点按钮就有点卡了,而且我6楼说的那个功能跟读串口超时有关系,这两者感觉就冲突似的,超时设大了就卡,设很小又达不到那个功能,哎 感觉不像在两个线程中运行似的,是不是与线程中操作UI有关?在ClearCommError之前sleep(如50、100);ClearCommError(hcom,&dwErrorFlags,&ComStat);在ClearCommError之后 判断ComStat.cbInQue,如果超过欲读的字节数(如22)就读,否则继续while等待这样的话 读超时就可用可不用了 我用的是同步读串口的,无法判断ComStat.cbInQue。线程只是用来实时读取串口数据的,操作界面是通过点击按钮的。 我使用 CreateFile 、ReadFile WirteFile 来对串口进行操作,针对我的外设,超时时间设置要给大点,大于200ms 超时。 哪里讲过同步读串口 无法判断ComStat.cbInQue 界面线程读写慢速外设,如果超时比较大,或者死循环读写,或者界面线程Sleep时间比较长,就会出现卡界面的现象。线程理处理,要求和界面线程(主线程)通讯时,不能使用SendMessage这样的同步函数。否则同样会卡界面。当然界面线程,也不能挂起自己,比如和其他线程同步,共享锁,资源被锁住的时候,界面就会卡住。 MFC有许多函数调用了,SendMessage ,不能用于工作线程和主线程通讯。MFC不是多线程安全的。MFC 不能和CreateThread,乃至_beginthread,_beginthreadex一起很好的工作。 ReplaceSel 就是使用SendMessage 的函数之一。 你好,试了下,把所有用到ReplaceSel的地方都去掉了,超时改大了点按钮还是卡啊?这到底怎么解决呢?//设定读超时TimeOuts.ReadIntervalTimeout=1000;TimeOuts.ReadTotalTimeoutMultiplier=0.5;//改成100TimeOuts.ReadTotalTimeoutConstant=1;//改成500了 1)ExitThread(0);和return 0;效果差不多,除非线程函数调用了别的函数;在那个函数里直接退出线程,否则没有必要使用ExitThread(0);2)while(true)这个线程没有推出条件,难道一直工作?3)每次只读22个字节数据,就刷新界面,是否刷新太快了??串口虽然慢,读22个字节还是很快的。4)AppendText在干啥???5)sizeof (buf) 是多少,每次只读22个字节,为何循环终止条件是i<sizeof (buf)6)BuildData(buff);做些什么???7)SetTime();做些什么???设置超时???8)点击按钮都干了啥???? 如果启动线程,那么点击两次,就会启动2个线程工作,每个线程,都无法退出。 点击N此,会启动N个线程工作,这个问题如何解决????PS:以上这些问题,在你的代码里都看不出来,所以看不出哪里会卡界面,需要你自己检查一下! 1)ExitThread(0);和return 0;效果差不多,除非线程函数调用了别的函数;在那个函数里直接退出线程,否则没有必要使用ExitThread(0);//这个删了2)while(true)这个线程没有推出条件,难道一直工作?//因为想一直监控串口有没有数据返回所以用这个,没有退出条件3)每次只读22个字节数据,就刷新界面,是否刷新太快了??//因为串口返回的数据长度不同,但大部分是22就写死了,我不知道怎么根据数据长度来控制显示的长度。串口虽然慢,读22个字节还是很快的。4)AppendText在干啥???//这个是改变输出字符的颜色并显示在编辑框中5)sizeof (buf) 是多少,每次只读22个字节,为何循环终止条件是i<sizeof (buf)//这样写其实长度就是22,跟第三个问题一样。6)BuildData(buff);做些什么???//这个是一个对读出数据进行解析的函数7)SetTime();做些什么???设置超时???//这个是显示系统时间的8)点击按钮都干了啥????//点击按钮执行WriteFile()向串口发送指令,界面上只要点击发送指令的都卡。其他的不卡 如果启动线程,那么点击两次,就会启动2个线程工作,每个线程,都无法退出。 点击N此,会启动N个线程工作,这个问题如何解决????//启动线程只是打开串口的时候开启,只需要启动一次啊关闭线程的时候有关闭线程PS:以上这些问题,在你的代码里都看不出来,所以看不出哪里会卡界面,需要你自己检查一下! 问题都回答了,帮帮看看吧,问题在哪里 NT,2000,XP等系统窗口程序: 界面线程是两个,一个是主线程,一个是主线程的守护线程。++ 1 界面卡和读线程关系不大,问题在别处。2 这与读超时关系不大。建议读线程稍作改动while(true) { DWORD SIZE; COMSTAT ComStat; DWORD dwErrorFlags; memset(buff, 0, sizeof(buff)); ClearCommError(hcom,&dwErrorFlags,&ComStat); if(ComStat->cbInQue < 22)////同步读串口,一样能判断ComStat.cbInQue continue; bReadStat= ReadFile(hcom,buff,22,&SIZE,NULL);TRACE1("hcom=%d",hcom); if(bReadStat) { CString temp; m_ctrlMyRichEdit.ReplaceSel(_T("\r\n")); SetTime(); if(buff[0]==6||buff[0]==21) {temp.Format(_T("%02X "),buff[0]); AppendText((BYTE*)temp.GetBuffer(0),20,RGB(255, 0,0)); } else { for(int i=0;i< sizeof(buff);i++) { temp.Format(_T("%02X "),buff[i]); AppendText((BYTE*)temp.GetBuffer(0),24,RGB(255, 0,0)); } BuildData(buff); } } PurgeComm(hcom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); } 读超时设置随便设置就行 但不能过小TimeOuts.ReadIntervalTimeout=50;TimeOuts.ReadTotalTimeoutMultiplier=50;TimeOuts.ReadTotalTimeoutConstant=100; 在我的电脑上 读线程同时向两个RichEdit、一个Edit写40k字节的数据,界面没感觉有什么影响。从别处找找看吧 找到问题了 bReadStat= ReadFile(hcom,buff,22,&SIZE,NULL);改成dwLength = ComStat.cbInQue ; bReadStat= ReadFile(hcom,buff,dwLength,&SIZE,NULL);大小不能定死,但是不知道为什么不行。另外输出数据for(int i=0;i< dwLength;i++) {temp.Format(_T("%02X "),buff[i]);AppendText((BYTE*)temp.GetBuffer(0),24,RGB(255, 0,0)); } 我用虚拟串口发送一串数据,点击按钮要等一下才能收到数据不知道为什么,连续点击按钮好几次才收到一条数据。设断点dwLength的值也在递增。 大小是能够定死的if(ComStat.cbInQue < ALENGTH)////同步读串口,一样能判断ComStat.cbInQue continue;这样的话就可以读取固定字节的数据。你的程序,一般说来每个循环只能读取1个或0个字节,线程刚切换进去可能多几个。最好在读之前判断一下虚拟串口也是串口,好的虚拟串口像串口一样,按照一定的速率发送数据。你在调试的时候数据让然会进来,dwLength增加也就顺理成章了。cbInQue是进入读缓冲区的数据嘛 请问如何对MessageBox中的确定取消键进行响应? 如何启动一个软件,并且控制其进行一些动作。 问个简单的字符转换问题,请高手回答. 求SQLBulkOperations的 例子。 如何获取当前端口类型(TCP or UDP)? 为什么的我VC6.0的include目录里面没有Graphics.h volatile的用法 紧急求救!明早考试题目! 简答题 --- TCP/IP 协议的工作原理 告诉我如何显示图片,百分送 sql高手,求求你们帮帮忙 如何给Bitmap赋值 请问,如何把一个CString的字符串,复制到粘贴板?
TimeOuts.ReadIntervalTimeout=0;
TimeOuts.ReadTotalTimeoutMultiplier=0.5;
TimeOuts.ReadTotalTimeoutConstant=1;
你好,发现更改读超时可以缓解界面卡的问题,需要设成很小才行,但是这样在while循环里读串口就太快了,并且串口给buff的总是0,我有一个自动应答的功能加了定时器来判断串口是否返回数据判断bReadStat是否为1,而buff被传进了0,bReadStat也是1,这不是我想要的,不知道说的清不清楚,帮忙看看吧,谢谢!
PS:楼主按钮是开线程启动的么?如果不是用线程的话,是会非常卡的。
另外,如果楼主开了线程还卡的话,那么说明楼主电脑估计是单核的。
TimeOuts.ReadIntervalTimeout=50;
TimeOuts.ReadTotalTimeoutMultiplier=50;
TimeOuts.ReadTotalTimeoutConstant=100;把调用CreateFile的那段贴出来看看
hcom=CreateFile(SerialName,GENERIC_READ|GENERIC_WRITE,
0, NULL, OPEN_EXISTING,0, NULL);
int t=GetLastError();
if(hcom==INVALID_HANDLE_VALUE)
{ AfxMessageBox(_T("打开串口失败!"));
return false;
}
else{
//指定端口监测的事件集
SetupComm(hcom,100,100); //输入缓冲区和输出缓冲区的大小都是100
COMMTIMEOUTS TimeOuts;
//设定读超时
TimeOuts.ReadIntervalTimeout=1000;
TimeOuts.ReadTotalTimeoutMultiplier=0.5;
TimeOuts.ReadTotalTimeoutConstant=1;
//在读一次输入缓冲区的内容后读操作就立即返回,
//而不管是否读入了要求的字符。
//设定写超时
TimeOuts.WriteTotalTimeoutMultiplier=100;
TimeOuts.WriteTotalTimeoutConstant=500;
SetCommTimeouts(hcom,&TimeOuts); //设置超时
DCB dcb;
GetCommState(hcom,&dcb);
dcb.BaudRate=(DWORD)BaudRate; //波特率为38400
dcb.ByteSize=8; //每个字节有8位
dcb.Parity=NOPARITY; //无奇偶校验位
dcb.StopBits=ONESTOPBIT; //一个停止位
PurgeComm(hcom,PURGE_TXCLEAR|PURGE_RXCLEAR);}
return TRUE;
TimeOuts.ReadTotalTimeoutConstant=100;这个稍微设大点点按钮就有点卡了,而且我6楼说的那个功能跟读串口超时有关系,这两者感觉就冲突似的,超时设大了就卡,设很小又达不到那个功能,哎
ClearCommError(hcom,&dwErrorFlags,&ComStat);
在ClearCommError之后 判断ComStat.cbInQue,如果超过欲读的字节数(如22)就读,否则继续while等待
这样的话 读超时就可用可不用了
否则同样会卡界面。
当然界面线程,也不能挂起自己,比如和其他线程同步,共享锁,资源被锁住的时候,界面就会卡住。
MFC不是多线程安全的。
MFC 不能和CreateThread,乃至_beginthread,_beginthreadex一起很好的工作。
//设定读超时
TimeOuts.ReadIntervalTimeout=1000;
TimeOuts.ReadTotalTimeoutMultiplier=0.5;//改成100
TimeOuts.ReadTotalTimeoutConstant=1;//改成500了
ExitThread(0);
和
return 0;
效果差不多,除非线程函数调用了别的函数;
在那个函数里直接退出线程,否则没有必要使用ExitThread(0);2)while(true)
这个线程没有推出条件,难道一直工作?
3)
每次只读22个字节数据,就刷新界面,是否刷新太快了??
串口虽然慢,读22个字节还是很快的。
4)
AppendText在干啥???
5)sizeof (buf) 是多少,每次只读22个字节,为何循环终止条件是i<sizeof (buf)
6)BuildData(buff);做些什么???
7)SetTime();做些什么???设置超时???
8)点击按钮都干了啥????
如果启动线程,那么点击两次,就会启动2个线程工作,每个线程,都无法退出。
点击N此,会启动N个线程工作,这个问题如何解决????
PS:
以上这些问题,在你的代码里都看不出来,所以看不出哪里会卡界面,需要你自己检查一下!
ExitThread(0);
和
return 0;
效果差不多,除非线程函数调用了别的函数;
在那个函数里直接退出线程,否则没有必要使用ExitThread(0);//这个删了2)while(true)
这个线程没有推出条件,难道一直工作?//因为想一直监控串口有没有数据返回所以用这个,没有退出条件
3)
每次只读22个字节数据,就刷新界面,是否刷新太快了??//因为串口返回的数据长度不同,但大部分是22就写死了,我不知道怎么根据数据长度来控制显示的长度。
串口虽然慢,读22个字节还是很快的。
4)
AppendText在干啥???//这个是改变输出字符的颜色并显示在编辑框中
5)sizeof (buf) 是多少,每次只读22个字节,为何循环终止条件是i<sizeof (buf)//这样写其实长度就是22,跟第三个问题一样。
6)BuildData(buff);做些什么???//这个是一个对读出数据进行解析的函数
7)SetTime();做些什么???设置超时???//这个是显示系统时间的
8)点击按钮都干了啥????//点击按钮执行WriteFile()向串口发送指令,界面上只要点击发送指令的都卡。其他的不卡
如果启动线程,那么点击两次,就会启动2个线程工作,每个线程,都无法退出。
点击N此,会启动N个线程工作,这个问题如何解决????//启动线程只是打开串口的时候开启,只需要启动一次啊关闭线程的时候有关闭线程
PS:
以上这些问题,在你的代码里都看不出来,所以看不出哪里会卡界面,需要你自己检查一下!
问题都回答了,帮帮看看吧,问题在哪里
界面线程是两个,一个是主线程,一个是主线程的守护线程。
++
2 这与读超时关系不大。建议读线程稍作改动
while(true)
{
DWORD SIZE;
COMSTAT ComStat;
DWORD dwErrorFlags;
memset(buff, 0, sizeof(buff));
ClearCommError(hcom,&dwErrorFlags,&ComStat);
if(ComStat->cbInQue < 22)////同步读串口,一样能判断ComStat.cbInQue
continue;
bReadStat= ReadFile(hcom,buff,22,&SIZE,NULL);TRACE1("hcom=%d",hcom);
if(bReadStat)
{
CString temp;
m_ctrlMyRichEdit.ReplaceSel(_T("\r\n"));
SetTime();
if(buff[0]==6||buff[0]==21)
{temp.Format(_T("%02X "),buff[0]);
AppendText((BYTE*)temp.GetBuffer(0),20,RGB(255, 0,0));
}
else
{
for(int i=0;i< sizeof(buff);i++)
{
temp.Format(_T("%02X "),buff[i]);
AppendText((BYTE*)temp.GetBuffer(0),24,RGB(255, 0,0));
}
BuildData(buff);
}
}
PurgeComm(hcom, PURGE_TXABORT|
PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
}
TimeOuts.ReadIntervalTimeout=50;
TimeOuts.ReadTotalTimeoutMultiplier=50;
TimeOuts.ReadTotalTimeoutConstant=100;
从别处找找看吧
改成dwLength = ComStat.cbInQue ;
bReadStat= ReadFile(hcom,buff,dwLength,&SIZE,NULL);
大小不能定死,但是不知道为什么不行。
另外输出数据for(int i=0;i< dwLength;i++)
{temp.Format(_T("%02X "),buff[i]);
AppendText((BYTE*)temp.GetBuffer(0),24,RGB(255, 0,0));
}
我用虚拟串口发送一串数据,点击按钮要等一下才能收到数据不知道为什么,连续点击按钮好几次才收到一条数据。设断点dwLength的值也在递增。
if(ComStat.cbInQue < ALENGTH)////同步读串口,一样能判断ComStat.cbInQue
continue;
这样的话就可以读取固定字节的数据。
你的程序,一般说来每个循环只能读取1个或0个字节,线程刚切换进去可能多几个。最好在读之前判断一下虚拟串口也是串口,好的虚拟串口像串口一样,按照一定的速率发送数据。你在调试的时候数据让然会进来,dwLength增加也就顺理成章了。cbInQue是进入读缓冲区的数据嘛