串口通信,比如接收6个字节,会触发两次,第一次接收6个字节,第二次接收0个字节
使用API编程,异步通信方式。
计算机仅仅从串口读数据,不用向串口写数据,因此比较简单。
思路:使用一个辅助线程来读串口。
发现问题:当设备向计算机发送数据时候,比如发送6个字节,计算机会接收两次,第一次接收6个字节,第二次接收0个字节。
这里,我给出主要代码:
一、打开串口1,以及串口主要设置信息:
g_hCom1 = CreateFile("COM1",
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL
);
波特率9600,校验,缓冲区大小,超时等等,都设置好。
//超时
tmOuts.ReadIntervalTimeout = 500;
tmOuts.ReadTotalTimeoutMultiplier = 0;
tmOuts.ReadTotalTimeoutConstant = 1000;
//设置触发事件为
SetCommMask(hCom, EV_RXCHAR);
二、监控串口1的线程,主要代码:
UINT WatchComm1Thread(LPVOID pParam)
{
DWORD dwMask, dwTransfered;
OVERLAPPED ol;
memset(&ol, 0, sizeof(OVERLAPPED));
ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
while(1)
{
if(!WaitCommEvent(g_hCom1 , &dwMask, &ol))//语句1
{
if(GetLastError() == ERROR_IO_PENDING)
GetOverlappedResult(g_hCom1, &ol, &dwTransfered, TRUE);//语句2
}
if((dwMask & EV_RXCHAR) == EV_RXCHAR)
{
int iReadLen = ReadComm1();//语句3
}
}
}
三、读串口函数ReadComm1()主要代码:
int ReadComm1()
{
DWORD dwError, dwRecvedLen = 0, dwTansfered;
COMSTAT comStat;
OVERLAPPED olRead1;
memset(&olRead1, 0, sizeof(OVERLAPPED));
olRead1.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ClearCommError(g_hCom1, &dwError, &comStat);
if(comStat.cbInQue > 0)
{
if(!ReadFile(g_hCom1, g_RecvBuf1, comStat.cbInQue, &dwRecvedLen, &olRead1))
{
if(GetLastError() == ERROR_IO_PENDING)
GetOverlappedResult(g_hCom1, &olRead1, &dwTansfered, TRUE);
}
}
CloseHandle(olRead1.hEvent);
return (int)dwRecvedLen;
}
/////////////////////////////////////////
我开始调试了:
我在“语句1”设置断点。
程序运行起来,很快执行到“语句1”处,单步运行,使其执行到“语句2”,再单步运行,因为设备一直不向计算机发送数据,“语句2”一直不会返回,这些都表明程序是好的。
设备向计算机发送6个字节,“语句2”立即返回,通过单步,可以发现“语句3”读取了6个字节,一切正常。然后继续单步,使其运行到“语句1”处,单步运行,使其执行到“语句2”,再单步运行,却发现“语句2”立即返回,(可是现在并串口中没有数据可读啊,“语句2”为什么会立即返回呢),再单步,程序符合“if((dwMask & EV_RXCHAR) == EV_RXCHAR)”的条件,运行到“语句3”,解下来就可以发现“语句3”读到了0个字节,怎么回事?
问题点数:60、回复次数:10Top
1 楼CUG122032(烫烫烫烫烫烫?烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫?烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫)回复于 2006-03-04 17:01:33 得分 0
为什么不用MScomm呢?Top
2 楼js_gary(李祥)回复于 2006-03-04 17:09:30 得分 0
you could try to use SearialCOM Class
may be which could help you anythingTop
3 楼south2000(south2000)回复于 2006-03-04 17:25:28 得分 0
用MScomm,程序给其他人使用的时候要涉及到控件的注册问题。
SearialCOM我不知道,也不想用。Top
4 楼BBirdlyh(BBird)回复于 2006-03-05 00:17:46 得分 60
EV_RXCHAR
A character was received and placed in the input buffer
串口向计算机发送六个字节,系统会受到六次EV_RXCHAR消息,第一次你就收了六个字节,以后的五次就只能收0字节了
至于为什么只受到2次EV_RXCHAR,我觉得原因应该是
if(!ReadFile(g_hCom1, g_RecvBuf1, comStat.cbInQue, &dwRecvedLen, &olRead1))
{
if(GetLastError() == ERROR_IO_PENDING)
GetOverlappedResult(g_hCom1, &olRead1, &dwTansfered, TRUE);
}
这里做了GetOverlappedResult的缘故,只有第一次和最后一次被受到了
另:其实SearialCOM真的很好用,而且和你的程序很相似,可以比较一下Top
5 楼south2000(south2000)回复于 2006-03-05 11:01:04 得分 0
BBirdlyh(BBird),感谢你的分析。
我又调试看了看,发现情况不像你说的那样,不像你分析语句GetOverlappedResult那样。
在int ReadComm1()函数中,“if(GetLastError() == ERROR_IO_PENDING)”,“GetOverlappedResult(g_hCom1, &olRead1, &dwTansfered, TRUE);”这两句都没有执行,
也就是说,在读串口的时候,一次性就读完了comStat.cbInQue数量的字节,ReadFile语句返回了TRUE。
呵呵。
Top
6 楼south2000(south2000)回复于 2006-03-06 11:18:20 得分 0
我发现,如果设备仅仅向计算机发送一个字节的话,就不会出现触发两次的情况,而是仅仅触发一次,然后正确接收到数据。
请问这是怎么回事?Top
7 楼jjiaming(阿熊)回复于 2006-03-06 13:08:12 得分 0
我觉得BBirdlyh(BBird)言之有理Top
8 楼south2000(south2000)回复于 2006-03-08 19:43:21 得分 0
没有人知道么?Top
9 楼BBirdlyh(BBird)回复于 2006-03-09 12:41:47 得分 0
正是因为你一次读完了6个字节,但没有阻止EV_RXCHAR消息,所以下次还会去处理
但安道理来说应该会受到6次,我所说的GetOverlappedResult的情况是在分析你为什么会受到2次
还有一个函数是用来清除接下来的EV_RXCHAR 或是其他消息的,也就是说你第一次收到EV_RXCHAR后,全部读出6个字节,然后调用该函数清除后续的EV_RXCHAR消息,msdn上有(DEVICE IO)你可以查一下
一般最好的办法是一次只收一个字节,然后攒着,知道受到要求的字节数并且验证正确再向处理模块发消息处理Top
10 楼shmily1280(锄禾)回复于 2006-03-09 13:45:02 得分 0
同意楼上的
可以一个一个读
完了之后再处理.否则在语句3处加个对comStat.cbInQue是否为空的判断
另:BBirdlyh(BBird)说的没错Top




