定时握手的问题
程序在和下位机通信,插入两个COM口,我现在想实现在通信的过程当中如果将某一个COM拔出,然后再插回去,怎么让它马上继续获取数据,现在我写了个方法,如果一个COM被拔出,然后给所有COM定时发送数据,如果你再将它插入回去,则重新开启该串口进行数据的获取,但是现在出问题了,这个方法可以实现,但是一旦我拔下一个后,另一个获取数据就好卡好卡了,我将代码贴出来,大家帮我分析一下,谢谢了。
- C/C++ code
int GetCommNum() { int _u_connectmode=0; DWORD dwactlen; DWORD dwLength=0; int len=1; unsigned char *psendbuf=new unsigned char[len]; unsigned char *recvBuf=new unsigned char[1024]; psendbuf[0]=0xff; HAND temphand; BOOL temp; Lhand.connect=false; Rhand.connect=false; for(int i=1;i<13;i++) { (temphand.Port).Format(_T("COM%d"),i); temp=OpenPort(57600,8,ONESTOPBIT,NOPARITY,&temphand); if (temp == false) { continue; } else { PurgeComm(temphand.hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); //清除收/发缓冲区 WriteFile(temphand.hComm,psendbuf,len,&dwactlen,NULL); ReadFile(temphand.hComm,recvBuf,1024,&dwLength,NULL); //其实我们接收到的命令应答只是一个字节 if(recvBuf[1]=='L') // { Lhand.connect=true; Lhand.Port=temphand.Port; } else if(recvBuf[1]=='R') // { Rhand.connect=true; Rhand.Port=temphand.Port; } if(Lhand.connect==true && Rhand.connect==true) //左右手同时插入 { delete psendbuf; delete recvBuf; ClosePort(&temphand); return 3; } ClosePort(&temphand); } }
这个是获取串口的,遍历一遍所有的串口。
- C/C++ code
void CInitData::OnTimer(UINT nIDEvent) { CConnectPort CP; CString Finger1,Finger2,Finger3,Finger4,Finger5,Finger6,Finger7,Finger8,Finger9,Finger10,Finger11,Finger12,Finger13,Finger14,Finger15,Finger16,Finger17,Finger18,Finger19,Finger20,Finger21,Finger22,Finger23,Finger24,Finger25,Finger26,Finger27,Finger28,Finger29,Finger30,Finger31,Finger32,Finger33,Finger34,Finger35,Finger36,Finger37,Finger38,Finger39,Finger40,Finger41,Finger42,Finger43; UpdateData(FALSE); Util util; switch(nIDEvent) { case 1: //左手连接,开始接收数据 BOOL flag; flag= CP.GetData(0xff,16,3,&Lhand); Finger1.Format("%d",Lhand.ADCData[0]); Finger2.Format("%d",Lhand.ADCData[1]); Finger3.Format("%d",Lhand.ADCData[2]); Finger4.Format("%d",Lhand.ADCData[3]); Finger5.Format("%d",Lhand.ADCData[4]); Finger6.Format("%d",Lhand.ADCData[5]); Finger7 = "0"; SetDlgItemText(IDC_EDIT1,Finger1); //给InitData初始化窗体的左手拇指初始化文本框赋值 SetDlgItemText(IDC_EDIT2,Finger2); //给InitData初始化窗体的左食指指初始化文本框赋值 SetDlgItemText(IDC_EDIT3,Finger3); //给InitData初始化窗体的左中指指初始化文本框赋值 SetDlgItemText(IDC_EDIT4,Finger4); //给InitData初始化窗体的左无名指指初始化文本框赋值 SetDlgItemText(IDC_EDIT5,Finger5); //给InitData初始化窗体的左手小指初始化文本框赋值 SetDlgItemText(IDC_EDIT6,Finger6); //给InitData初始化窗体的左手手腕前初始化文本框赋值 if(!flag) { CP.ClosePort(&Lhand); CP.GetCommNum(); CP.OpenPort(57600,8,ONESTOPBIT,NOPARITY,&Lhand); } break; case 2: BOOL flag2; flag2 = CP.GetData(0xff,16,3,&Rhand); Finger22.Format("%d",Rhand.ADCData[0]); Finger23.Format("%d",Rhand.ADCData[1]); Finger24.Format("%d",Rhand.ADCData[2]); Finger25.Format("%d",Rhand.ADCData[3]); Finger26.Format("%d",Rhand.ADCData[4]); Finger27.Format("%d",Rhand.ADCData[5]); Finger28 = "0"; SetDlgItemText(IDC_EDIT22,Finger22); SetDlgItemText(IDC_EDIT23,Finger23); SetDlgItemText(IDC_EDIT24,Finger24); SetDlgItemText(IDC_EDIT25,Finger25); SetDlgItemText(IDC_EDIT26,Finger26); SetDlgItemText(IDC_EDIT27,Finger27); SetDlgItemText(IDC_EDIT28,Finger28); if(!flag2) { CP.ClosePort(&Rhand); CP.GetCommNum(); CP.OpenPort(57600,8,ONESTOPBIT,NOPARITY,&Rhand); } break; } CDialog::OnTimer(nIDEvent);}
这个时间方法里我分别对两个串口接收数据,定时为
SetTimer(1,10,NULL);
SetTimer(2,10,NULL);
CP.GetData(0xff,16,3,&Lhand);这个方法是给下位机发送协议0xff的,接收的数据存放在HAND Lhand,Rhand这两个结构体的ADCData里。GetData这个方法返回一个BOOL型,如果为false,说明没有接收到数据,那么就调用GetCommNum()方法进行串口的重新遍历,直到重新插入串口进行获取数据,现在问题来了,我开始将两个串口同时插上,很正常,接收数据很流畅,但是我一旦拔出一个,那么另一个接收就好卡好卡了,后来我找到了原因,把CP.GetCommNum();这个遍历方法一屏蔽掉,拔出一个另一个就很流畅,没有问题,但是这个一屏蔽掉你把拔出来的串口再插回去就没用了,大家伙帮帮忙吧。只剩下这点分了,都拿出来了
[解决办法]
我没有仔细看代码,我的理解是:
不管有多少个com,基本上一个线程对应一个com的通讯,这样容易处理一些。
每个线程在和com通讯的过程中,其实就是读和写两个操作,不管是读还是写,如果失败了,则持续地重试,直到成功。当然如果有对应的错误号码返回,比如是windows异常导致无法通讯就需要重新打开这个com后再重新通讯,如果只是外面的设备拔掉了,我猜应该是读写的一般失败,只是重试就可以了。如果外面的设备拔掉了,如果再插上还需要重新开始协议的通讯,则程序也需要做相应的协议初始化工作,而不能只是简单地重试
[解决办法]
3楼++
多线程能解决这个问题,你在定时器里做耗时遍历,这样就造成接数据卡住了!