You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SAMA5D3开发板USB设备读写:数据读取方法与写入验证问询

Hey there! Let's work through your two questions about reading from and verifying writes to your USB-connected device on the SAMA5D3 board. First, let's break down the issues in your current code and fix them step by step.

1. How to Read Data from the Device

Your current reading logic has a couple of key issues that are preventing you from getting data properly:

  • Uninitialized/incorrect termios configuration: The speed variable isn't assigned a value, and setting c_iflag/c_oflag to speed doesn't make sense. For custom baud rates with BOTHER, you need to set c_ispeed and c_ospeed directly.
  • Timing issue with FIONREAD: You're checking for available bytes immediately after writing, but the device might not have sent a response yet—especially in non-blocking mode.
  • Non-blocking mode pitfalls: Using O_NONBLOCK means read will return immediately if no data is ready, which is why you're hitting the "error" case often.

Here's how to fix this:

Step 1: Fix the Termios Configuration

First, properly set up your serial port parameters (adjust baud rate to match your device):

struct termios usb_parm;
// Initialize with current port settings
tcgetattr(fd1, &usb_parm);

// Reset flags and set custom baud rate with BOTHER
usb_parm.c_cflag &= ~CBAUD;
usb_parm.c_cflag |= BOTHER;
usb_parm.c_ispeed = 9600; // Set your desired baud rate here
usb_parm.c_ospeed = 9600;

// Configure for raw mode (tweak based on your device's requirements)
usb_parm.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
usb_parm.c_oflag &= ~OPOST;
usb_parm.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
usb_parm.c_cflag &= ~(CSIZE | PARENB);
usb_parm.c_cflag |= CS8; // 8 data bits

// Apply settings immediately
retval = tcsetattr(fd1, TCSANOW, &usb_parm);
if (retval != 0) {
    perror("Failed to set serial attributes");
    close(fd1);
    return -1;
}

Step 2: Improve the Reading Logic

Instead of checking FIONREAD once, use select() to wait for data to arrive (this handles timing properly, whether you use blocking or non-blocking mode):

char read_buff[64] = {0}; // Fixed-size buffer with room for null terminator
int bytes_read = 0;
fd_set readfds;
struct timeval tv;

// Wait up to 2 seconds for a response
tv.tv_sec = 2;
tv.tv_usec = 0;
FD_ZERO(&readfds);
FD_SET(fd1, &readfds);

int select_ret = select(fd1 + 1, &readfds, NULL, NULL, &tv);
if (select_ret > 0 && FD_ISSET(fd1, &readfds)) {
    int byteavailable = 0;
    ioctl(fd1, FIONREAD, &byteavailable);
    if (byteavailable > 0) {
        bytes_read = read(fd1, read_buff, sizeof(read_buff) - 1); // Leave space for null terminator
        if (bytes_read > 0) {
            read_buff[bytes_read] = '\0'; // Ensure valid string
            printf("Read buff=%s\n", read_buff);
            printf("Bytes read=%d\n", bytes_read);
        } else {
            perror("Read failed");
        }
    }
} else if (select_ret == 0) {
    printf("Timeout: No data received from device\n");
} else {
    perror("Select error");
}
2. How to Confirm Data Was Successfully Written to the Device

To verify your write was successful, you need to check two key things: the return value of write(), and optionally wait for device acknowledgment.

Step 1: Validate the Write Return Value

The write() function returns the number of bytes actually written. Compare this to the number of bytes you intended to send (note: don't send the null terminator unless your device expects it—use strlen() instead of sizeof()):

char write_buff[] = "q,e";
int expected_bytes = strlen(write_buff);
int bytes_written = write(fd1, write_buff, expected_bytes);

if (bytes_written == expected_bytes) {
    printf("Successfully wrote all %d bytes: %s\n", bytes_written, write_buff);
} else if (bytes_written == -1) {
    perror("Write failed entirely");
} else {
    printf("Only wrote %d of %d bytes\n", bytes_written, expected_bytes);
}

Step 2: Wait for Data to Be Transmitted

Use tcdrain() to ensure all data in the output buffer is sent to the device before proceeding:

tcdrain(fd1); // Blocks until all output is transmitted

Step 3: (Optional) Read a Device Acknowledgment

Many devices send an ACK message after receiving valid data. If your device does this, use the reading logic from question 1 to listen for this ACK as confirmation the data was received and processed.

Full Corrected Code

Here's the complete, fixed version of your main function:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/select.h>

int main() 
{
    int fd1, retval;
    struct termios usb_parm;

    // Open port with O_RDWR (simpler than separate read/write flags)
    fd1 = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
    if (fd1 > 0) {
        printf("Device detected\n");
    } else {
        perror("Failed to open port");
        return -1;
    }

    // Configure serial port parameters
    tcgetattr(fd1, &usb_parm);

    // Set custom baud rate
    usb_parm.c_cflag &= ~CBAUD;
    usb_parm.c_cflag |= BOTHER;
    usb_parm.c_ispeed = 9600;
    usb_parm.c_ospeed = 9600;

    // Set raw mode
    usb_parm.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
    usb_parm.c_oflag &= ~OPOST;
    usb_parm.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    usb_parm.c_cflag &= ~(CSIZE | PARENB);
    usb_parm.c_cflag |= CS8;

    // Apply settings
    retval = tcsetattr(fd1, TCSANOW, &usb_parm);
    if (retval != 0) {
        perror("Failed to set serial attributes");
        close(fd1);
        return -1;
    }

    // Flush pending data
    tcflush(fd1, TCIOFLUSH);

    // Write data to device
    char write_buff[] = "q,e";
    int expected_bytes = strlen(write_buff);
    int bytes_written = write(fd1, write_buff, expected_bytes);

    if (bytes_written == expected_bytes) {
        printf("Successfully wrote all %d bytes: %s\n", bytes_written, write_buff);
        tcdrain(fd1); // Wait for transmission to finish
    } else {
        perror("Write failed");
        close(fd1);
        return -1;
    }

    // Read response
    char read_buff[64] = {0};
    int bytes_read = 0;
    fd_set readfds;
    struct timeval tv;

    tv.tv_sec = 2;
    tv.tv_usec = 0;
    FD_ZERO(&readfds);
    FD_SET(fd1, &readfds);

    int select_ret = select(fd1 + 1, &readfds, NULL, NULL, &tv);
    if (select_ret > 0 && FD_ISSET(fd1, &readfds)) {
        int byteavailable = 0;
        ioctl(fd1, FIONREAD, &byteavailable);
        if (byteavailable > 0) {
            bytes_read = read(fd1, read_buff, sizeof(read_buff) - 1);
            if (bytes_read > 0) {
                read_buff[bytes_read] = '\0';
                printf("Read buff=%s\n", read_buff);
                printf("Bytes read=%d\n", bytes_read);
            } else {
                perror("Read failed");
            }
        }
    } else if (select_ret == 0) {
        printf("Timeout: No response from device\n");
    } else {
        perror("Select error");
    }

    close(fd1);
    return 0;
}

内容的提问来源于stack exchange,提问作者user9478215

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:08:09