如何在arduino上一次接收整个字符串而不是1个字符?


11

我已成功遵循此网站上的指示:

http://www.doctormonk.com/2012/04/raspberry-pi-and-arduino.html

而且我完全能够按照网站的指定在pi和arudino mega之间进行通信。

但是,我不是要发送表示LED闪烁次数的整数,而是要发送ASCII文本,例如:

从pi到arduino的“向前移动5米”,“向左转”,“向后移动10米”。

我写了以下代码:

char inData[64];
char inChar=-1;

void setup(){
   Serial.begin(9600);
   Serial.begin("Waiting for Raspberry Pi to send a signal...\n");
}


void loop(){
    byte numBytesAvailable= Serial.available();

    // if there is something to read
    if (numBytesAvailable > 0){
        // store everything into "inData"
        int i;
        for (i=0;i<numBytesAvailable;i++){
            inChar= Serial.read();
            inData[i] = inChar;
        }

        inData[i] = '\0';


        Serial.print("Arduino Received: ");
        Serial.println(inData);
    }
}

我成功地在代码上方闪过了我的Arduino Mega 2560。

我在Raspberry Pi上和键入的控制台中切换到python终端:

import serial
ser = serial.Serial('/dev/ttyACM1',9600)
ser.write("MOVE")

我的Arduino串行监视器上显示的内容如下:

Arduino Received: M
Arduino Received: O
Arduino Received: V
Arduino Received: E

但是我想要的是:

Arduino Received: MOVE

如何更改上面的代码以将所有字符放入inData缓冲区?


您确定已正确复制了代码?我看代码的方式,无论inData中有什么,“ Arduino Received”行只会被打印一次。您确定所有这些都在setup()函数中吗?
NickHalden

你是对的。我现在修复了。但是问题仍然存在。
user1068636

Answers:


23

问题在于Arduino的循环速度如此之快,它将if (numBytesAvailable > 0)在通过串行端口到达的每个字符之间执行几次该行。因此,一旦一个字符到达,它将抓住它,从零循环到一个,并打印出一个字符。

您应该做的是在Python程序中的每个命令之后发送一个换行符('\ n')。然后让您的Arduino代码缓冲收到的每个字符,并在收到行尾字符后才对消息进行操作。

因此,如果您更改Python代码,请发送行尾字符,如下所示:

import serial
ser = serial.Serial('/dev/ttyACM1',9600)
ser.write("MOVE\n")

然后您的Arduino代码可以是这样的:

// Buffer to store incoming commands from serial port
String inData;

void setup() {
    Serial.begin(9600);
    Serial.println("Waiting for Raspberry Pi to send a signal...\n");
}

void loop() {
    while (Serial.available() > 0)
    {
        char recieved = Serial.read();
        inData += recieved; 

        // Process message when new line character is recieved
        if (recieved == '\n')
        {
            Serial.print("Arduino Received: ");
            Serial.print(inData);

            inData = ""; // Clear recieved buffer
        }
    }
}

1
另外,对于更通用的用法(例如,在C语言中没有便利的String类的情况),这可能会导致您窥视缓冲区中的内容以查看是否收到\ n。这样,您可以将所有内容保留在内部缓冲区中,然后再进行复制。这里的缺点是内部缓冲区必须足够大才能让您捕获最长的单行。否则,您可能会提高处理速度,因为可以避免像String这样的操作(大概是这样),即重新计算和分配内存以扩展自身。
托比·劳伦斯

您的代码成功了!我不得不更改几行,例如收到的inData =“”和inData + =。我认为编译器不喜欢它。
user1068636 2012年

6

你的Python脚本发送四个字节,MOV,和E。Arduino应该如何知道那是一个字符串?考虑一下Python代码:

ser.write("MOVE")

完全一致的,以

ser.write("MO")
ser.write("VE")

从Arduino的角度来看。串行端口传输字符,而不是字符串。

在您的代码中,Arduino的速度非常快(与9600的波特率相比),因此每次调用时Serial.available(),它只会看到这四个字符之一。这就是为什么获得输出的原因。

您需要做的是用某种方法来分隔字符串,即从Python以某种方式对其进行标记,以便Arduino可以将接收到的各个字符附加到字符串的高级概念中。

使用行很简单:发送以换行符('\n')结尾的每个字符串。在Arduino上,读取字符并将其附加到字符串中。看到时'\n',字符串结束,可以打印。


将单个字符追加到字符串中的速度不会比等待换行符慢,并且在接收到换行符时一次性读取整个字符序列。
Vivandiere

2
不确定您的建议是什么-您不能“等待”换行符,除非阅读,并且在阅读时,您也必须阅读所有先前的字符(这意味着他们需要已通过某种方式保存-不管是“附加到字符串”还是其他保存方式由您决定)。
吉姆·巴黎

2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

上面的代码在我与Pi和Arduino之间的连接上非常有效


1

使用.readline代替.read

我遇到了同样的问题,并且马上解决了。希望这对您有所帮助!


对于EE.SE的答案,这有点薄。特别是考虑到这是2年的历史了。请详细说明。
尼克·阿列克谢耶夫

欢迎来到堆叠,山姆。我们很高兴有您加入。这与许多其他论坛不同,因为我们会尽力使自己尽可能清晰明了,以使每个将来找到我们写作的人都可以从该知识中获得最大的收益。您是否有完全相同的问题?有那些确切的成分?那确切的代码?此设置中的哪些条件可使您的代码正常工作,为什么以前不起作用?社区需要您的帮助见解。
肖恩·博迪

0

这是我在第一个示例中所做的:

String readString;

void setup()
{
    Serial.begin(9600); // initialization
}

void loop()
{
    char incomingByte;
    while (Serial.available() > 0)
    {
        delay(10); // if the data came
        incomingByte = Serial.read(); // read byte
        //Serial.println(incomingByte);
        readString += incomingByte;
    }

    if(readString != "")
    {
        Serial.print("arduino recived this : ");
        Serial.println(readString);
    }
    readString = "";
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.