ฉันมีบอร์ด Arduino ที่เชื่อมต่อกับเซ็นเซอร์ จากมอนิเตอร์อนุกรม Arduino IDE ฉันเห็นค่าที่อ่านได้เป็นส่วนใหญ่ 160, 150 เป็นต้น Arduino มี ADC 10 บิต ดังนั้นฉันจึงถือว่าช่วงการอ่านมีค่าตั้งแต่ 0 ถึง 1024

ฉันต้องการดึงข้อมูลการอ่านนั้นไปยังคอมพิวเตอร์ของฉันเพื่อที่ฉันจะได้ดำเนินการต่อไปได้ ต้องทำถึงขั้นนี้ ตอนนี้ ฉันเขียนโปรแกรม c++ เพื่ออ่านบัฟเฟอร์พอร์ตอนุกรมด้วย Windows API (DCB) ความเร็วในการถ่ายโอนของพอร์ตอนุกรมถูกตั้งค่าเป็น 115200 บนทั้ง Arduino IDE และโปรแกรม c++

ฉันจะอธิบายปัญหาของฉันก่อน: เนื่องจากฉันต้องการส่งการอ่านไปยังคอมพิวเตอร์ของฉัน ฉันคาดว่าข้อมูลจะมีลักษณะดังนี้:

124
154
342
232
...

แต่ตอนนี้ดูเหมือน

321
43
5
2
123
...

ดังที่แสดง ข้อมูลจะถูกต่อกัน ฉันรู้เพราะฉันพยายามแสดงมันด้วย[]และข้อมูลก็ยุ่งเหยิงจริงๆ

ส่วนของรหัสที่ทำการอ่านพอร์ตอนุกรมบนคอมพิวเตอร์มีดังนี้:

// Read
int n = 10;
char szBuff[10 + 1] = {0};
DWORD dwBytesRead = 0;

int i;
for (i = 0; i < 200; i++){
    {
        if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
            //error occurred. Report to user.
            printf("Cannot read.\n");
        }
        else{
            printf("%s\n" , szBuff);
        }
    }
}

รหัส Arduino ที่ทำการส่งพอร์ตอนุกรมคือ:

char buffer [10] = { 0 };
int analogIn = 0;
int A0_val = 0;

void setup() {
  Serial.begin(115200);
}

void loop() {
    A0_val = analogRead(analogIn);
    sprintf(buffer, "%d", A0_val);
    Serial.println(buffer);
}

ฉันสงสัยว่าความยุ่งเหยิงของข้อมูลเกิดจากขนาดบัฟเฟอร์ที่แตกต่างกันที่ใช้ในการส่งและรับข้อมูลในพอร์ตอนุกรม ข้อเสนอแนะที่ดีสำหรับขนาดของบัฟเฟอร์และวิธีที่ดียิ่งขึ้นในการรับประกันการส่งข้อมูลที่ถูกต้องสำเร็จคืออะไร?

ขอบคุณมาก ๆ!

ตอบ

รหัสผู้รับของคุณไม่สามารถถือว่าการอ่านครั้งเดียวจากพอร์ตอนุกรมจะทำให้ได้บรรทัดที่สมบูรณ์ (เช่น 2 หรือ 3 หลักตามด้วย '\n' ที่ Arduino ส่งอย่างต่อเนื่อง)

ขึ้นอยู่กับผู้รับในการสังเคราะห์ข้อความทั้งหมดบนแผนกต้อนรับ จากนั้นจึงพยายามใช้เป็นตัวเลขที่มีความหมาย

เนื่องจากอินเทอร์เฟซแบบอนุกรมนั้นช้ามากเมื่อเทียบกับกำลังประมวลผลพีซีโดยเฉลี่ยของคุณ จึงแทบไม่มีประโยชน์ในการอ่านอักขระมากกว่าหนึ่งตัวในแต่ละครั้ง: รอบ CPU นับล้านจะถูกใช้ไปเพื่อรออักขระตัวถัดไป คุณจึงไม่ต้องการ เพื่อตอบสนองต่ออินพุต Arduino อย่างรวดเร็ว

เนื่องจากในกรณีนั้น มันจะไม่ขัดขวางการแสดงเลยแม้แต่น้อย ฉันจึงพบว่าสะดวกกว่าที่จะอ่านทีละอักขระ ที่จะช่วยให้คุณไม่ต้องวุ่นวายกับการเคลื่อนย้ายบิตของสตริงไปรอบๆ อย่างน้อยก็ทำให้การเขียนตัวอย่างการศึกษาง่ายขึ้น

// return the next value received from the arduino as an integer
int read_arduino (HANDLE hserial)
{
    char buffer[4];       // any value longer than 3 digits must come 
                          // from a faulty transmission
                          // the 4th caracter is used for a terminating '\0'
    size_t buf_index = 0; // storage position of received characters
    for (;;)
    {
        char c; // read one byte at a time

        if (!ReadFile(
            hSerial,
            &c,   // 1 byte buffer
            1,    // of length 1 
            NULL, // we will read exactly one byte or die trying,
                  // so length checking is pointless
            NULL)){
            /*
             * This error means something is wrong with serial port config,
             * and I assume your port configuration is hard-coded, 
             * so the code won't work unless you modify and recompile it.
             * No point in keeping the progam running, then.
             */
            fprintf (stderr, "Dang! Messed up the serial port config AGAIN!");
            exit(-1);
        }
        else // our read succeded. That's a start.
        {
            if (c == '\n') // we're done receiving a complete value
            {
                int result; // the decoded value we might return

                // check for buffer overflow
                if (buf_index == sizeof (buffer))
                {
                    // warn the user and discard the input
                    fprintf (stderr,
                        "Too many characters received, input flushed\n");
                }
                else // valid number of characters received
                {
                    // add a string terminator to the buffer
                    buffer[buf_index] = '\0';

                    // convert to integer
                    result = atoi (buffer);

                    if (result == 0)
                    {
/*
 * assuming 0 is not a legit value returned by the arduino, this means the
 * string contained something else than digits. It could happen in case
 * of electricval problems on the line, typically if you plug/unplug the cable
 * while the arduino is sending (or Mr Fluffy is busy gnawing at it).
 */
                        fprintf (stderr, "Wrong value received: '%s'\n", buffer);
                    }
                    else // valid value decoded
                    {
                        // at last, return the coveted value
                        return res; // <-- this is the only exit point
                    }
                }

                // reset buffer index to prepare receiving the next line
                buf_index = 0;
            }
            else // character other than '\n' received
            {
                // store it as long as our buffer does not overflow
                if (buf_index < sizeof (buffer))
                {
                    buffer[buf_index++] = c;
/*
 * if, for some reason, we receive more than the expected max number of
 * characters, the input will be discarded until the next '\n' allow us
 * to re-synchronize.
 */
                }
            }
        }
    }
}

ข้อแม้: นี่เป็นเพียงโค้ดที่อยู่บนหัวของฉัน ฉันอาจจะพิมพ์ผิดไปบ้างแล้ว ดังนั้นอย่าคาดหวังว่ามันจะทำงานหรือคอมไพล์ทันที

ปัญหาพื้นฐานสองสามข้อที่นี่ ประการแรก ไม่น่าเป็นไปได้ที่พีซีจะติดตามข้อมูลบอด 115,200 ได้อย่างน่าเชื่อถือ หากคุณอ่าน ReadFile ครั้งละ 10 ไบต์เท่านั้น ลองใช้อัตราบอดที่ช้าลงและ/หรือเปลี่ยนขนาดบัฟเฟอร์และจำนวนไบต์ต่อการอ่านเป็นสิ่งที่จะได้รับข้อมูลประมาณ 20 มิลลิวินาทีหรือมากกว่า

ประการที่สอง หลังจากที่คุณอ่านข้อมูลบางส่วนแล้ว ให้ใส่ nul ต่อท้ายข้อมูลนั้น

 szBuf[dwBytesRead] = 0;

ก่อนที่คุณจะส่งต่อไปยัง printf หรือรหัสสตริง C อื่น ๆ