我目前正在尝试编写一个程序,该程序将从串行通信端口上的Arduino HC-05模块读取蓝牙输出。
http://cdn.makezine.com/uploads/2014/03/hc_hc-05-user-instructions-bluetooth.pdf
当我打开Putty终端并告诉它听COM4时,我能够看到Arduino上运行的程序正在打印的输出。
但是,当我运行以下程序尝试以编程方式处理串行端口上的传入数据时,我会显示输出。
#include <Windows.h>
#include <string>
#include <atltrace.h>
#include <iostream>
int main(int argc, char** argv[]) {
HANDLE hComm = CreateFile(
L"COM4",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
NULL,
0
);
if (hComm == INVALID_HANDLE_VALUE) {
std::cout << "Error opening COM4" << std::endl;
return 1;
}
DWORD dwRead;
BOOL fWaitingOnRead = false;
OVERLAPPED osReader = { 0 };
char message[100];
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL) {
std::cout << "Error creating overlapping event" << std::endl;
return 2;
}
while (1) {
if (!fWaitingOnRead) {
if (!ReadFile(
hComm,
&message,
sizeof(message),
&dwRead,
NULL
)) {
if (GetLastError() != ERROR_IO_PENDING) {
std::cout << "Communications error" << std::endl;
return 3;
}
}
else {
message[100] = '\0';
std::cout << message << std::endl;
}
}
}
return 0;
}
我已经对句柄和ReadFile函数调用进行了更改,以便它将在无限循环中同步进行调用。但是,Visual Studio会弹出警告,说明程序已停止工作,然后要求调试或关闭程序。我的假设是它必须在某处停止或者无法在堆栈的某处执行某些WindowsAPI函数。
任何帮助,指示,非常感谢。
答案 0 :(得分:1)
那是因为message
的类型错误。
要包含字符串,它应该是一个字符数组,而不是一个指向字符的指针数组。
此外,要将其视为字符串,您需要将最后一个字符后面的数组元素设置为'\0'
。 ReadFile
会将其读取的字符数放入dwRead
。
此外,您似乎没有正确使用重叠的I / O.这个简单的程序不需要重叠的I / O - 删除它。 (正如@EJP所指出的,你正在检查错误的ERROR_IO_PENDING。也可以删除它。)
答案 1 :(得分:1)
至少IMO,使用重叠的I / O来完成这项工作是非常严重的过度杀伤力。你可以使它工作,但你需要付出很多额外的努力,而且可能很少完成。
在Windows下使用comm端口的重要一点是将超时设置为至少有一半有意义的值。当我第一次这样做时,我开始将所有值设置为1
,期望这会有点工作,但可能消耗过多的CPU时间,所以我想尝试更高的值来保留响应速度足够快,同时降低CPU使用率。
所以,我写了some code,只是将COMMTIMEOUTS
结构中的所有值都设置为1,并设置通信端口来发送/读取数据。
我从来没有尝试过更长的超时来尝试降低CPU使用率,因为即使在我第一次写这篇文章(可能是Pentium II,或其左右)时使用的机器上,它也是功能性的,并且消耗了太少的CPU时间需要关心 - 我无法真正看到机器完全空闲和传输数据之间的区别。可能存在可以证明更多工作合理的情况,但至少对于我所拥有的任何需求,它似乎是充足的。
答案 2 :(得分:0)
在您的计划中查看以下评论:
if (!fWaitingOnRead) {
if (!ReadFile( // here you make a non-blocking read.
hComm,
message,
sizeof(*message),
&dwRead,
&osReader
)) {
// Windows reports you should wait for input.
//
if (GetLastError() != ERROR_IO_PENDING) {
std::cout << "Communications error" << std::endl;
return 3;
}
else { // <-- remove this.
// insert call to GetOverlappedcResult here.
std::cout << message << std::endl;
}
}
}
return 0; // instead of waiting for input, you exit.
}
调用ReadFile()
后,必须插入GetOverlappedResult(hComm, &osReader, &dwBytesRceived, TRUE)
的调用,等待读取操作完成,缓冲区中有一些字节。
如果您不想过早退出,还需要在程序中设置一个循环。
如果您不想进行重叠I / O(这是明智的决定),请不要将OVERLAPPED指针传递给ReadFile。 ReadFile将阻塞,直到它有一些数据给你。那么您显然不需要致电GetOverlappedresult()
对于串行端口,您还需要填写DCB结构。 https://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx
您可以使用BuildCommDCB()
对其进行初始化。 MS doc CallGetCommState(hComm, &dcb)
中有一个链接,用于初始化串口硬件。串口需要知道您的应用需要哪种波特率等。