gpt4 book ai didi

c++ - 串行通信 - 我无法将传入的 char 数组转换为 int

转载 作者:行者123 更新时间:2023-11-28 06:17:33 25 4
gpt4 key购买 nike

我正在尝试从 Arduino 接收一个数字作为 C++ 中的整数。完整代码如下:

#define STRICT
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Serial.h"
#include <boost\lexical_cast.hpp>
enum { EOF_Char = 27 };

int __cdecl _tmain(int /*argc*/, char** /*argv*/)
{
CSerial serial;
LONG lLastError = ERROR_SUCCESS;

// Attempt to open the serial port (COM4)
lLastError = serial.Open(_T("COM4"), 0, 0, false);

// Setup the serial port (9600,8N1, which is the default setting)
lLastError = serial.Setup(CSerial::EBaud9600, CSerial::EData8, CSerial::EParNone, CSerial::EStop1);

// Register only for the receive event
lLastError = serial.SetMask(CSerial::EEventBreak |
CSerial::EEventCTS |
CSerial::EEventDSR |
CSerial::EEventError |
CSerial::EEventRing |
CSerial::EEventRLSD |
CSerial::EEventRecv);

// Use 'non-blocking' reads, because we don't know how many bytes
// will be received. This is normally the most convenient mode
// (and also the default mode for reading data).
lLastError = serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);

// Keep reading data, until an EOF (CTRL-Z) has been received
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent();

// Save event
const CSerial::EEvent eEvent = serial.GetEventType();


// Handle data receive event
if (eEvent & CSerial::EEventRecv)
{
// Read data, until there is nothing left
DWORD dwBytesRead = 0;
char szBuffer[101];
do
{
// Read data from the COM-port
lLastError = serial.Read(szBuffer, sizeof(szBuffer) - 1, &dwBytesRead);

if (dwBytesRead > 0)
{
// Finalize the data, so it is a valid string
szBuffer[dwBytesRead] = '\0';

// Display the data
printf("%s", szBuffer);


// Check if EOF (CTRL+'[') has been specified
if (strchr(szBuffer, EOF_Char))
fContinue = false;
}
} while (dwBytesRead == sizeof(szBuffer) - 1);
}
} while (fContinue);

// Close the port again
serial.Close();
return 0;
}

我让我的 Arduino 不断发送数字 51。此代码工作正常并始终显示“51”。但是,我想要一个 int 在 C++ 中进行操作。

首先我添加了

std::stringstream str(szBuffer);
int tester;
str >> tester;
printf("My number is: %d\n", tester+1);

紧接着

printf("%s", szBuffer);

典型的结果如下:

51My number is: 52
51My number is: 52
51My number is: 52
51My number is: 52
51My number is: 52
5My number is: 6
1My number is: 2

完美地做了 5 或 6 次后,输出总是将传入的数字连续分隔一两次(我还没有找到具体的模式,但它总是 5-6 和 1-2) .

我的另一个尝试是使用 boost 库:

int tester = boost::lexical_cast<int>(szBuffer);
printf("My number is: %d\n", tester);

紧接着

printf("%s", szBuffer);

我得到了相同的结果(5-6 次正确后出现 1-2 次错误)。我不认为 Arduino 正在发送错误数据,因为只是一个

printf("%s", szBuffer);

永远不会偏离它应该是的数字。转换是否会扰乱数据的接收?谢谢。

编辑:Arduino 代码是:

void setup() {
Serial.begin(9600); // same as in your c++ script
}

void loop() {
Serial.print(51);
delay(1000);
}

最佳答案

对于串行端口,没有一种机制可以让发送器通知接收器作为一个 block 传输了多少字节。 IE。 Serial.print(51); 告诉接收方它发送两个字符作为一个数字时没有“隐藏”标记。您必须向串行协议(protocol)添加某种指示(空格、逗号、行尾、初始字节数等)。

正因为如此,你从serial.Read获取的字符数取决于你要求它读取的字符数(第二个参数)和串口接收的字符数缓冲区,以较小者为准。大多数时候,Arduino 似乎在您调用 serial.Read 之前发送了两个数字,但有时它只能及时输出一个数字……下一次通过循环读取第二个数字。

因此,假设您决定使用换行符来分隔数字。您在 Arduino 端只需更改为 Serial.println(51);。接收端稍微复杂一些。

不知道你的串口库里面有什么。大多数都有某种“读取行”功能,您只需将 serial.Read 调用替换为类似以下内容:

serial.Readline(szBuffer, sizeof(szBuffer) - 1);

它会处理空终止输出。如果它不处理空终止,您需要找到行尾并将其更改为 \0 自己。从现在开始,您的代码将正常工作,因为 serial.Readline 函数将阻塞直到它获取整行。

如果您没有“读取行”或至少没有“读取到此字符”功能,那就有点难了。您必须重复调用 serial.Read,在缓冲区中移动,直到看到行结束符。此外,您还冒着读取下一行的部分或全部的风险,因此您不能在读取完数字后就丢弃读取的所有数据;您必须移动缓冲区中的数据,以便下一行(以及更多)的数据位于缓冲区的开头。


如果您使用的是 Boost(是吗?我看到它没有 CSerial),看起来它有一个 read_until功能。这需要三个参数:您正在读取的流、用于存储数据的流缓冲区以及要停止的内容。在这种情况下,用于存储的流缓冲区是 std::stringstream 中的缓冲区:

std::stringstream buffer;
size_t chars = boost::asio::read_until(serial, buffer.rdbuf(), '\n');
if(chars == 0) return;
int tester;
buffer >> tester;
printf("My number is: %d\n", tester+1);

关于c++ - 串行通信 - 我无法将传入的 char 数组转换为 int,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29955981/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com