Làm thế nào để tôi nhận được toàn bộ một chuỗi trái ngược với 1 ký tự tại một thời điểm trên arduino?


11

Tôi đã làm theo hướng dẫn trên trang web này thành công:

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

và tôi đã có thể có được thông tin liên lạc giữa pi và arudino mega của tôi chính xác như trang web chỉ định.

Tuy nhiên, thay vì gửi một số nguyên biểu thị số lần đèn LED nhấp nháy, tôi muốn gửi văn bản ASCII như sau:

"DI CHUYỂN 5 METERS FORWARD", "TACK LEFT", "DI CHUYỂN 10 METERS BACKWARD" cho arduino từ pi.

Tôi đã viết đoạn mã sau:

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);
    }
}

Tôi đã flash mã trên thành công vào Arduino Mega 2560 của tôi.

Tôi đã chuyển sang thiết bị đầu cuối python của mình trên Raspberry Pi và trong bảng điều khiển tôi đã gõ:

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

Những gì được hiển thị trên Màn hình nối tiếp Arduino của tôi như sau:

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

Nhưng điều tôi muốn là:

Arduino Received: MOVE

Làm cách nào để thay đổi mã ở trên để đưa tất cả các ký tự vào bộ đệm inData?


Bạn có chắc là bạn đã sao chép mã chính xác? Cách tôi nhìn thấy mã của bạn, bất kể trong inData là gì, dòng "Arduino đã nhận" sẽ chỉ được in một lần. Bạn có chắc chắn đó là tất cả trong hàm setup () của bạn không?
NickHalden

Bạn đúng. Tôi đã sửa nó bây giờ. Nhưng vấn đề vẫn còn.
dùng1068636

Câu trả lời:


23

Vấn đề là Arduino đang lặp rất nhanh, nó sẽ thực thi if (numBytesAvailable > 0)dòng nhiều lần giữa mỗi nhân vật đến qua cổng nối tiếp. Vì vậy, ngay khi một nhân vật xuất hiện, nó chộp lấy nó, lặp từ 0 đến 1 và in ra một ký tự.

Điều bạn nên làm là gửi một ký tự kết thúc ('\ n') sau mỗi lệnh từ chương trình Python của bạn. Sau đó, có bộ đệm mã Arduino của bạn mỗi ký tự mà nó nhận được và chỉ hành động trên thông báo một khi nó nhận được ký tự cuối dòng.

Vì vậy, nếu bạn thay đổi mã Python, hãy gửi một ký tự cuối dòng, như vậy:

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

Sau đó, mã Arduino của bạn có thể là một cái gì đó như thế này:

// 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
Ngoài ra, một thay đổi tiềm năng về điều này đối với các cách sử dụng chung chung hơn (như trong C thẳng mà bạn không có lớp Chuỗi tiện lợi) là bạn nhìn vào những gì trong bộ đệm để xem bạn đã nhận được \ n chưa. Bằng cách này bạn giữ mọi thứ trong bộ đệm nội bộ trước khi bạn tạo một bản sao của nó. Nhược điểm ở đây là bộ đệm bên trong phải đủ lớn để cho phép bạn chụp dòng đơn dài nhất của mình. Mặt khác, bạn có khả năng đạt được tốc độ xử lý khi bạn tránh các lượt thích như String (có lẽ là vậy), tính toán lại và phân bổ bộ nhớ để mở rộng chính nó.
Toby Lawrence

Mã của bạn đã làm việc! Tôi đã phải thay đổi một vài dòng như inData = "" và inData + = đã nhận. Tôi không nghĩ trình biên dịch thích nó.
dùng1068636

6

Python script của bạn được gửi đi bốn byte, M, O, V, và E. Làm thế nào mà Arduino phải biết rằng đó là một chuỗi đơn? Hãy xem xét rằng mã Python:

ser.write("MOVE")

hoàn toàn giống hệt nhau để

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

từ quan điểm của Arduino. Các cổng nối tiếp chuyển ký tự, không phải chuỗi.

Trong mã của bạn, Arduino rất nhanh (so với tốc độ 9600 baud), vì vậy mỗi lần gọi Serial.available(), nó chỉ nhìn thấy một trong bốn ký tự đó. Đó là lý do tại sao bạn có đầu ra bạn đã làm.

Những gì bạn cần làm là đưa ra một số cách phân định chuỗi, tức là đánh dấu chúng theo cách nào đó từ Python để Arduino có thể nối thêm các ký tự riêng lẻ mà nó nhận được vào khái niệm chuỗi cấp cao của bạn .

Sử dụng các dòng rất đơn giản: gửi mọi chuỗi kết thúc bằng một ký tự dòng mới ( '\n'). Trên Arduino, đọc các ký tự và nối chúng vào chuỗi của bạn. Khi bạn nhìn thấy một '\n', chuỗi kết thúc và bạn có thể in nó.


Không nối các ký tự riêng lẻ vào một chuỗi chậm hơn là chỉ chờ ký tự dòng mới và đọc toàn bộ chuỗi ký tự trong một lần khi nhận được ký tự dòng mới.
Vivandiere

2
Không chắc chắn những gì bạn đang đề xuất - bạn không thể "chờ" một ký tự dòng mới ngoại trừ bằng cách đọc nó và vào thời điểm bạn đọc nó, bạn cũng nhất thiết phải đọc tất cả các ký tự trước đó (có nghĩa là họ cần phải đã được lưu theo một cách nào đó - cho dù đó là "nối vào chuỗi" hay một số phương pháp lưu chúng khác là tùy thuộc vào bạn).
Jim Paris

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

Đoạn mã trên hoạt động hoàn hảo trên kết nối của tôi giữa Pi và Arduino


1

Sử dụng .readlinethay vì.read

Tôi đã có cùng một vấn đề và điều này đã khắc phục nó ngay lập tức. Hy vọng điều này sẽ giúp!


Đây là một chút mỏng cho một câu trả lời trên EE.SE. Đặc biệt xem xét rằng đây là một chủ đề 2 năm tuổi. Xin hãy giải thích.
Nick Alexeev

Chào mừng đến với ngăn xếp, sam. Chúng tôi rất vui khi có bạn trên tàu. Điều này không giống như nhiều diễn đàn khác, ở chỗ chúng tôi cố gắng hết sức rõ ràng và chi tiết nhất có thể, để mọi người tìm thấy bài viết của chúng tôi trong tương lai có thể nhận được lợi ích tối đa từ kiến ​​thức đó. Bạn có cùng một vấn đề chính xác ? Với những thành phần chính xác ? Và mã chính xác đó ? Điều kiện nào trong thiết lập này làm cho mã của bạn hoạt động và tại sao trước đây nó không hoạt động? Cộng đồng muốn sự giúp đỡ của bạn, cái nhìn sâu sắc của bạn.
Sean Boddy

0

Đây là cách tôi đã làm nó từ ví dụ đầu tiên:

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 = "";
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.