我有一个在Windows上运行的应用程序,它将通过串行端口发送数据。 这是代码:
m_hCommPort= ::CreateFile(L"\\\\.\\COM3",
GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING,0,0);
if(m_hCommPort == INVALID_HANDLE_VALUE)
{
printf("COM error: %d\n", GetLastError());
}
config.DCBlength = sizeof(config);
if((GetCommState(m_hCommPort, &config) == 0))
{
CloseHandle(m_hCommPort);
printf("Get configuration port has a problem.\n");
return FALSE;
}
config.BaudRate = 9600;
config.StopBits = ONESTOPBIT;
config.Parity = PARITY_NONE;
config.ByteSize = DATABITS_8;
config.fDtrControl = 0;
config.fRtsControl = 0;
if (!SetCommState(m_hCommPort, &config))
{
CloseHandle(m_hCommPort);
printf( "Failed to Set Comm State Reason: %d\n",GetLastError());
return E_FAIL;
}
以下是仅发送(工作)(连续发送)
的代码while(1)
{
Sleep(5000);
int isWritten = WriteFile(m_hCommPort, txData, 9/*(DWORD)sizeof(txData)*/, &dwBytesWritten, NULL);
printf("isWritten: %d, dwBytesWritten: %d \n", isWritten, dwBytesWritten);
}
在此之后我也添加了接收数据的代码,然后发送不工作。我的意思是无法通过UART发送数据。 WriteFile()似乎没有被执行,它被卡住了。 在这里我添加了一个线程来接收数据,是线程导致问题吗?还是我需要做别的事?
void ReceiverThread(void *param)
{
DWORD dwRead=0;
BOOL fWaitingOnRead = FALSE;
OVERLAPPED osReader = {0};
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL)
printf("Error creating overlapped event; abort.\n");
while(1)
{
if (!ReadFile(m_hCommPort, &Byte, 1, &dwRead, &osReader)) {
if (GetLastError() != ERROR_IO_PENDING) // read not delayed?
printf("Error in communications; report it.\n");
else
fWaitingOnRead = TRUE;
}
else {
rxData[rxHeadIndex++]= Byte;
rxHeadIndex = (rxHeadIndex) & QUEUE_MASK;
}
}
}
SetCommMask (m_hCommPort, EV_RXCHAR/ | EV_ERR); //receive character event
_beginthread(ReceiverThread,0,NULL);
while(1)
{
Sleep(5000);
int isWritten = WriteFile(m_hCommPort, txData, 9/*(DWORD)sizeof(txData)*/, &dwBytesWritten, NULL);
printf("isWritten: %d, dwBytesWritten: %d \n", isWritten, dwBytesWritten);
}
提前致谢。 阿肖克
答案 0 :(得分:2)
我前一段时间遇到过类似的问题。
我发现如果串行端口当前正在进行WriteFile(..)
,ReadFile(..)
会阻止。如果ReadFile(..)
阻塞,如果没有要读取的数据,那么这就是一个问题。
我通过使用函数ClearCommError(..)
检查串行缓冲区中是否有可用数据来解决问题。这可确保ReadFile(..)
可以立即读取内容并且不会不必要地阻止设备。尝试将ReceiverThread
更改为以下内容:
void ReceiverThread(void *param)
{
DWORD dwRead=0;
COMSTAT comStat;
char buffer[1024];
while (m_hCommPort != INVALID_HANDLE_VALUE)
{
if ((ClearCommError(m_hCommPort, NULL, &comStat) != FALSE) && (comStat.cbInQue > 0))
{
/* todo: ensure buffer is big enough to contain comStat.cbInQue bytes! */
if (ReadFile(m_hCommPort, buffer, comStat.cbInQue, &dwRead, NULL) != FALSE)
{
/* do something with data in buffer */
}
}
/* avoid busy-wait */
if (comStat.cbInQue == 0)
{
SleepEx(1, FALSE);
}
}
}
这种方式ReadFile(..)
仅在数据可用时调用,同时WriteFile(..)
可以发送数据而不会被阻止。
很遗憾,我无法阻止ClearCommError(..)
阻止,所以我使用SleepEx(1, FALSE);
解决方法来避免忙碌等待,从而使ReceiverThread
吃掉了{{1}} CPU。
答案 1 :(得分:1)
config.fDtrControl = 0;
config.fRtsControl = 0;
这些设置会关闭DTR和RTS握手线。大多数串行设备都会关注这些信号。假设机器未通电,他们在DTR信号关闭时不会发送任何内容。假设机器未准备好接收任何数据,并且在RTS信号关闭时不会发送任何内容。
所以你观察到的是完全正常的。
由于该设备似乎是正常的"并且 注意握手线,您要配置DCB让设备驱动程序自动控制这些信号。修正:
config.fDtrControl = DTR_CONTROL_ENABLE;
config.fRtsControl = RTS_CONTROL_HANDSHAKE;
也是Putty和HyperTerminal等终端模拟器的默认设置。首先使用这样的程序以确保接线和设备正常工作。如果您无法在此类程序中显示任何设备数据,那么它也无法使用您的程序。如果全部检出,则还将fDsrSensitivity,fOutxCtsFlow和fOutxDsrFlow属性设置为TRUE,以便您反过来注意设备的握手信号。