艹艹艹!!!耍帅自己用API写串口,结果现在出糗了~~~

thundersung 2014-03-10 04:54:21
定期读写串口程序。自己为了锻炼所以用API了。
但是,现象是设备上电,然后打开程序,一切正常。设备断电再上电,读线程readfile就基本上读不到任何东西了。。。而调试设备的哥们儿说他也没收到任何我writefile的字符。。。关键还有!特么啥函数返回值还是getlasterror都特么没错误!!!

不多说了!贴代码吧。。。

这个是第一次创建COM口的处理,CommWatchProc是监听线程,CommRequestProc是定期向设备发请求并查看是否掉线的线程。
		hComArray[iLoop] = CreateFile(szComPort, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);

if (hComArray[iLoop] == INVALID_HANDLE_VALUE)
{
return;
}
SetCommMask(hComArray[iLoop], EV_RXCHAR|EV_TXEMPTY );
SetupComm(hComArray[iLoop], 10240, 10240);
PurgeComm(hComArray[iLoop], PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
COMMTIMEOUTS commTimeOuts;
commTimeOuts.ReadIntervalTimeout = MAXDWORD;
commTimeOuts.ReadTotalTimeoutConstant = 0;
commTimeOuts.ReadTotalTimeoutMultiplier = 0;
commTimeOuts.WriteTotalTimeoutConstant = 2000;
commTimeOuts.WriteTotalTimeoutMultiplier = 50;
SetCommTimeouts(hComArray[iLoop], &commTimeOuts);
DCB dcb;
dcb.BaudRate = 115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fBinary = TRUE;
dcb.fParity = FALSE;
SetCommState(hComArray[iLoop], &dcb);

CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CommWatchProc, (LPVOID)(&iComIndexArray[iLoop]), 0, &dwThreadID);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CommRequestProc, (LPVOID)(&iComIndexArray[iLoop]), 0, &dwThreadID);


这个是监听。bufferGlobalArray和Backup都是全局的,为了拼接没有一次全发过来的字符串而准备的,mutexArray相应位置放的是共享信号量。ProcessRcvBuffer是具体处理字符串的函数,可以无视。
UINT CommWatchProc(LPVOID lpPara)
{
try
{
int iComIndex = *(int*)lpPara;
InitializeCriticalSection(&mutexArray[iComIndex]);
memset(bufferGlobalArray[iComIndex], 0, 10240);
memset(bufferGlobalBackupArray[iComIndex], 0, 10240);
iBufferGlobalStartIndexArray[iComIndex] = 0;
iBufferGlobalEndIndexArray[iComIndex] = -1;
HANDLE hEventWait100 = CreateEvent(NULL, TRUE, FALSE, NULL);
BYTE buffer[1024] = {0};
OVERLAPPED osReader = {0};
COMSTAT comStat = {0};
DWORD dwByteRead = 0, dwLastError = 0, dwWaitRet = 0, dwError = 0;
BOOL bThreadDone = FALSE, bRet = TRUE, bWaitingOnRead = FALSE;
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
while (!bThreadDone)
{
SetLastError(ERROR_SUCCESS);
if (!bWaitingOnRead)
{
bRet = ReadFile(hComArray[iComIndex], buffer, 1024, &dwByteRead, &osReader);
if (!bRet)
{
dwLastError = GetLastError();
if (ERROR_IO_PENDING == dwLastError)
bWaitingOnRead = TRUE;
else
{
bThreadDone = TRUE;
continue;
}
}
else
{
if (dwByteRead)
ProcessRcvBuffer(buffer, dwByteRead, iComIndex);
}
}
if (bWaitingOnRead)
{
dwWaitRet = WaitForSingleObject(osReader.hEvent, INFINITE);
switch (dwWaitRet)
{
case WAIT_OBJECT_0:
SetLastError(ERROR_SUCCESS);
bRet = GetOverlappedResult(hComArray[iComIndex], &osReader, &dwByteRead, FALSE);
if (!bRet)
{
dwLastError = GetLastError();
if (dwLastError == ERROR_OPERATION_ABORTED)
continue;
else if (dwLastError == ERROR_IO_INCOMPLETE)
{
WaitForSingleObject(hEventWait100, 100);
continue;
}
else
bThreadDone = TRUE;
}
else
{
if (dwByteRead)
ProcessRcvBuffer(buffer, dwByteRead, iComIndex);
}
bWaitingOnRead = FALSE;
break;
case WAIT_TIMEOUT:
WaitForSingleObject(hEventWait100, 100);
break;
default:
break;
}
}
memset(buffer, 0, 1024);
WaitForSingleObject(hEventWait100, 100);
}
CloseHandle(osReader.hEvent);
CloseHandle(hEventWait100);
DeleteCriticalSection(&mutexArray[iComIndex]);
}
catch (...)
{
}

return 0;
}


这个是定期询问设备的。
UINT CommRequestProc(LPVOID lpPara)
{
try
{
int iComIndex = *((int*)lpPara), iLoop = 0, iLoopAnother = 0;
CString szComPort;
szComPort.Format(TEXT("\\\\.\\COM%d"), iComIndex+1);
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//...
for (;;)
{
if (!ComIsAvailable(hComArray[iComIndex]))
{
CloseHandle(hComArray[iComIndex]);
hComArray[iComIndex] = INVALID_HANDLE_VALUE;
TerminateThread(hWatchThreadArray[iComIndex], 1);
CloseHandle(hWatchThreadArray[iComIndex]);
hWatchThreadArray[iComIndex] = INVALID_HANDLE_VALUE;
BOOL bLoop = TRUE;
while (bLoop)
{
hComArray[iComIndex] = CreateFile(szComPort, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);
if (hComArray[iComIndex] == INVALID_HANDLE_VALUE)
{
CloseHandle(hComArray[iComIndex]);
WaitForSingleObject(hEvent, 5000);
}
else
{
SetCommMask(hComArray[iComIndex], EV_RXCHAR|EV_TXEMPTY );
SetupComm(hComArray[iComIndex], 10240, 10240);
PurgeComm(hComArray[iComIndex], PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
COMMTIMEOUTS commTimeOuts;
commTimeOuts.ReadIntervalTimeout = MAXDWORD;
commTimeOuts.ReadTotalTimeoutConstant = 0;
commTimeOuts.ReadTotalTimeoutMultiplier = 0;
commTimeOuts.WriteTotalTimeoutConstant = 2000;
commTimeOuts.WriteTotalTimeoutMultiplier = 50;
SetCommTimeouts(hComArray[iComIndex], &commTimeOuts);
DCB dcb;
dcb.BaudRate = 115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fBinary = TRUE;
dcb.fParity = FALSE;
SetCommState(hComArray[iComIndex], &dcb);
DWORD dwThreadID = 0;
hWatchThreadArray[iComIndex] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CommWatchProc, lpPara, 0, &dwThreadID);
bLoop = FALSE;
}
}
}
//定期询问设备
}
CloseHandle(hEvent);
}
catch (...)
{
DWORD dwLastError = GetLastError();
}
return 0;
}


ComIsAvailable是用来看这个端口对应的设备是不是突然断电了的。
BOOL ComIsAvailable(HANDLE hCom)
{
BOOL bRet = TRUE;
DWORD dwLastError = 0, dwBytesWritten = 0;
BYTE byNothing[4] = {0};
DWORD dwSize = sizeof(byNothing);
OVERLAPPED overlapped = {0};
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
SetLastError(0);
if (!WriteFile(hCom, byNothing, dwSize, &dwBytesWritten, &overlapped))
{
dwLastError = GetLastError();
if (ERROR_IO_PENDING == dwLastError)
{
SetLastError(0);
while(!GetOverlappedResult(hCom, &overlapped, &dwBytesWritten, TRUE))
{
dwLastError = GetLastError();
if (dwLastError == ERROR_IO_INCOMPLETE)
continue;
else
{
bRet = FALSE;
break;
}
}
}
}
CloseHandle(overlapped.hEvent);
return bRet;
}




...全文
176 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
thundersung 2014-03-12
  • 打赏
  • 举报
回复
引用 12 楼 thundersung 的回复:
[quote=引用 10 楼 schlafenhamster 的回复:] 就是说 BOOL ComIsAvailable(HANDLE hCom) 没有问题, 是下位机的问题.
不过,现在有另外一个问题,有的时候,我的ProcessSndBuffer中GetOverlappedResult会卡顿一下,然后返回TRUE,而这个时候却发现我写进去的字符个数是0,也就是dwBytesWritten和m_osWrite.InternalHigh都等于0,但GetLastError却是0,我是根据m_osWrite.Internal等于258觉得这个函数超时了。我把GetOverlappedResult的最后一个等待的参数设定为FALSE,那么第一次循环时返回FALSE,LastError是Incomplete,第二次循环就返回TRUE了,但仍然写进去0个字符。[/quote] 这个问题要顶起来!
thundersung 2014-03-11
  • 打赏
  • 举报
回复
引用 8 楼 schlafenhamster 的回复:
"首先是WriteFile返回FALSE,LastError是PENDING" WriteFile返回FALSE时,能不能重新初始化comm
呵呵,原因大概不是我上位机的问题。 我在判断端口是否掉的时候,是通过WriteFile缩编写四个0然后看LastError是不是等于FileNotFound的。 好像是主板在接收到不能识别的数据时处理卡死了。俺把这四个用于探试的0换成实际的有CRC、头尾的命令就能够正常热插拔了。 结贴给分啦!
schlafenhamster 2014-03-11
  • 打赏
  • 举报
回复
"首先是WriteFile返回FALSE,LastError是PENDING" WriteFile返回FALSE时,能不能重新初始化comm
thundersung 2014-03-11
  • 打赏
  • 举报
回复
引用 6 楼 schlafenhamster 的回复:
// close Comm PurgeComm(m_idComDev,PURGE_TXABORT | PURGE_RXABORT| PURGE_TXCLEAR | PURGE_RXCLEAR); // if (ClearCommError(m_idComDev,&dwErrorFlags,&ComStat)) { //ComStat filled if (dwErrorFlags) { if (dwErrorFlags & CE_RXOVER) AfxMessageBox("Receive Queue overflow"); else if(dwErrorFlags & CE_OVERRUN) AfxMessageBox("Receive Overrun Error"); else if(dwErrorFlags & CE_RXPARITY) AfxMessageBox("Receive Parity Error"); else if(dwErrorFlags & CE_FRAME ) AfxMessageBox("Receive Framing error"); else if(dwErrorFlags & CE_BREAK) AfxMessageBox("Break Detected"); else AfxMessageBox("CE_OTHERS"); }
这些代码是放在Request线程的!ComIsAvailable判断后?我这么做了,ClearCommError返回的error是0,没有ce_break。 我昨个和设备debug发现,重新上电后我发的东西他收不到,而我的所有api返回值包括lasterror都“正确”,首先是WriteFile返回FALSE,LastError是PENDING,GetOverlappedResult返回TRUE,dwBytesWritten为具体数值,m_osWrite里Internal也是0,InternalHigh等于dwBytesWritten。一切正常。。。
thundersung 2014-03-11
  • 打赏
  • 举报
回复
引用 10 楼 schlafenhamster 的回复:
就是说 BOOL ComIsAvailable(HANDLE hCom) 没有问题, 是下位机的问题.
不过,现在有另外一个问题,有的时候,我的ProcessSndBuffer中GetOverlappedResult会卡顿一下,然后返回TRUE,而这个时候却发现我写进去的字符个数是0,也就是dwBytesWritten和m_osWrite.InternalHigh都等于0,但GetLastError却是0,我是根据m_osWrite.Internal等于258觉得这个函数超时了。我把GetOverlappedResult的最后一个等待的参数设定为FALSE,那么第一次循环时返回FALSE,LastError是Incomplete,第二次循环就返回TRUE了,但仍然写进去0个字符。
thundersung 2014-03-11
  • 打赏
  • 举报
回复
引用 10 楼 schlafenhamster 的回复:
就是说 BOOL ComIsAvailable(HANDLE hCom) 没有问题, 是下位机的问题.
感觉是的。我只是把这个函数里面写的字符串替换成有头有尾有校验的数据串了,然后就能正常收发了。
schlafenhamster 2014-03-11
  • 打赏
  • 举报
回复
就是说 BOOL ComIsAvailable(HANDLE hCom) 没有问题, 是下位机的问题.
schlafenhamster 2014-03-10
  • 打赏
  • 举报
回复
// close Comm PurgeComm(m_idComDev,PURGE_TXABORT | PURGE_RXABORT| PURGE_TXCLEAR | PURGE_RXCLEAR); // if (ClearCommError(m_idComDev,&dwErrorFlags,&ComStat)) { //ComStat filled if (dwErrorFlags) { if (dwErrorFlags & CE_RXOVER) AfxMessageBox("Receive Queue overflow"); else if(dwErrorFlags & CE_OVERRUN) AfxMessageBox("Receive Overrun Error"); else if(dwErrorFlags & CE_RXPARITY) AfxMessageBox("Receive Parity Error"); else if(dwErrorFlags & CE_FRAME ) AfxMessageBox("Receive Framing error"); else if(dwErrorFlags & CE_BREAK) AfxMessageBox("Break Detected"); else AfxMessageBox("CE_OTHERS"); }
schlafenhamster 2014-03-10
  • 打赏
  • 举报
回复
ClearCommError 或 Purge
thundersung 2014-03-10
  • 打赏
  • 举报
回复
引用 2 楼 schlafenhamster 的回复:
发生了“CE_BREAK错误” 需清除
哦!这个在哪里处理啊?是需要在ReadFile前SetCommMask然后当逻辑&CE_BREAK非0后清除吗?清除操作都包括什么呀?
thundersung 2014-03-10
  • 打赏
  • 举报
回复
另外,由于下位机没收到东西,所以把咱写的函数也贴上了。
void ProcessSndBuffer(BYTE *buffer, DWORD size, int comIndex)
{
	try
	{
		SetLastError(0);
		OVERLAPPED m_osWrite;
		COMSTAT ComStat;
		DWORD dwErrorFlags, dwBytesWritten, dwRes;
		BOOL bWriteStat;
		memset(&m_osWrite, 0, sizeof(m_osWrite));
		m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
		ClearCommError(hComArray[comIndex], &dwErrorFlags, &ComStat);
		PurgeComm(hComArray[comIndex], PURGE_TXABORT | PURGE_TXCLEAR);
		bWriteStat = WriteFile(hComArray[comIndex], buffer, size, &dwBytesWritten, &m_osWrite);
		if(!bWriteStat)
		{
			DWORD dwLastError = GetLastError();
			if(GetLastError() == ERROR_IO_PENDING)
			{
				SetLastError(0);
				while(!GetOverlappedResult(hComArray[comIndex], &m_osWrite, &dwBytesWritten, TRUE))
				{
					DWORD dwError = GetLastError();
					if (dwError == ERROR_IO_INCOMPLETE)
						continue;
					else
						break;
				}
			}
		}
		dwRes = GetLastError();
		CloseHandle(m_osWrite.hEvent);
	}
	catch (...)
	{
	}
}
过程基本上都是bWriteStat等于FALSE,然后GetLastError等于PENDING,而GetOverlappedResult一次就返回TRUE了,dwBytesWritten也不等于零。m_osWrite.Internal等于零。看上去好像没什么不对的,但设备就特么没收到东西。。。重新启动软件,就能够写进去了。。。
schlafenhamster 2014-03-10
  • 打赏
  • 举报
回复
发生了“CE_BREAK错误” 需清除
thundersung 2014-03-10
  • 打赏
  • 举报
回复
这个程序,把设备断电了,再上电后,第一个readfile就只偶尔能读到两三次数据,然后就一直是返回TRUE而dwByteRead等于0。关了程序再重启(不动设备),就能一直读数据了。。。。。。
C#串口介绍以及简单串口通信程序设计实现 源代码和串口程序介绍连接:https://www.cnblogs.com/JiYF/p/6618696.html 本站积分太贵,自己变得。。直接到连接地址下载代码 周末,没事干,个简单的串口通信工具,也算是本周末曾来过,废话不多,直接到主题 串口介绍   串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。(至于再详细,自己百度) 串口应用:   工业领域使用较多,比如:数据采集,设备控制等等,好多都是用串口通信来实现!你要是细心的话,你会发现,目前家用国网智能电能表就具备RS485通信总线(串行总线的一种)与RS232可以相互转化(当然一般,非专业的谁也不会闲的蛋疼,趴电表上瞎看,最多也就看看走了多少度电) RS232 DB9介绍: 1.示意图 2.针脚介绍: 载波检测(DCD) 接受数据(RXD) 发数据(TXD) 数据终端准备好(DTR) 信号地线(SG) 数据准备好(DSR) 请求发送(RTS) 清除发送(CTS) 振铃指示(RI) 3.实物图: 以下是我购买XX公司的一个usb转串口线:这个头就是一个公头,另一端是一个usb口 笨小孩串口工具运行图: 1.开启程序 2.发送一行字符串HelloBenXH,直接将针脚的发送和接收链接起来就可以测试了(针脚2 接受数据(RXD) 和3 发数据(TXD))直接链接, C#代码实现:采用SerialPort 1.实例化一个SerialPort [csharp] view plain copy 在CODE上查看代码片派生到我的代码片 private SerialPort ComDevice = new SerialPort(); 2.初始化参数绑定接收数据事件 [csharp] view plain copy 在CODE上查看代码片派生到我的代码片 public void init() { btnSend.Enabled = false; cbbComList.Items.AddRange(SerialPort.GetPortNames()); if (cbbComList.Items.Count > 0) { cbbComList.SelectedIndex = 0; } cbbBaudRate.SelectedIndex = 5; cbbDataBits.SelectedIndex = 0; cbbParity.SelectedIndex = 0; cbbStopBits.SelectedIndex = 0; pictureBox1.BackgroundImage = Properties.Resources.red; ComDevice.DataReceived += new SerialDataReceivedEventHandler(Com_DataReceived);//绑定事件 }

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧