C读取调用阻塞串行端口操作

标签 c serial-port termios

我正在尝试在 Linux 中编写一个 C 程序,以通过串行端口从微 Controller 发送和接收数据。作为测试,我已将微 Controller 配置为立即回显发送的所有字符。我已经验证这在 minicom 中有效,也可以使用“cat”和“echo”发送和接收数据。

但是,当我尝试在 C 程序中执行相同操作时,我的读取调用将永远阻塞。我将串行端口设置为非规范模式,MIN 为“1”,TIME 为“0”。我的 minicom 测试证明微 Controller 在输入字符时返回字符,所以我希望在 write 调用发送字符后读取返回。我将我的代码与几个在线示例进行了比较,但没有发现任何遗漏的地方。我尝试了以下代码的几种排列,但没有成功。有人能发现问题吗?

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>

#define UART_SPEED B115200

char buf[512];

void init_serial (int fd)
{
    struct termios termios;
    int res;

    res = tcgetattr (fd, &termios);
    if (res < 0) {
        fprintf (stderr, "Termios get error: %s\n", strerror (errno));
        exit (-1);
    }

    cfsetispeed (&termios, UART_SPEED);
    cfsetospeed (&termios, UART_SPEED);

    termios.c_iflag &= ~(IGNPAR | IXON | IXOFF);
    termios.c_iflag |= IGNPAR;

    termios.c_cflag &= ~(CSIZE | PARENB | CSTOPB | CREAD | CLOCAL);
    termios.c_cflag |= CS8;
    termios.c_cflag |= CREAD;
    termios.c_cflag |= CLOCAL;

    termios.c_lflag &= ~(ICANON | ECHO);
    termios.c_cc[VMIN] = 1;
    termios.c_cc[VTIME] = 0;

    res = tcsetattr (fd, TCSANOW, &termios);
    if (res < 0) {
        fprintf (stderr, "Termios set error: %s\n", strerror (errno));
        exit (-1);
    }
}

int main (int argc, char **argv)
{
    int fd;
    int res;
    int i;

    if (argc < 2) {
        fprintf (stderr, "Please enter device name\n");
        return -1;
    }

    fd = open (argv[1], O_RDWR | O_NOCTTY);
    if (fd < 0) {
        fprintf (stderr, "Cannot open %s: %s\n", argv[1], strerror(errno));
        return -1;
    }

    init_serial (fd);

    res = write (fd, "P=20\r\n", 6);
    if (res < 0) {
        fprintf (stderr, "Write error: %s\n", strerror(errno));
        return -1;
    }
    tcdrain (fd);

    res = read (fd, buf, 512);
    printf ("%d\n", res);
    if (res < 0) {
        fprintf (stderr, "Read error: %s\n", strerror(errno));
        return -1;
    }

    for (i=0; i<res; i++) {
        printf ("%c", buf[i]);
    }

    return 0;
}

最佳答案

您可能想插入一些延迟,或循环等待输入。

设置比特率后,某些类型的 UART 硬件会以新速度获取一两个字符以同步到新速度。写入时可能会丢失前几个字符。

六个字符写入后,立即发出读取,超时为 0.1 秒。 write() 中的所有字符都可能在 read() 之前完成传输,更不用说远程设备响应的任何时间了。

例如,一种解决方案是:

init_serial (fd);
usleep (100000);   // delay 0.1 seconds (Linux) so term parameters have time to change

res = write (fd, "P=20\r\n", 6);
if (res < 0) {
    fprintf (stderr, "Write error: %s\n", strerror(errno));
    return -1;
}
tcdrain (fd);
usleep (250000);  // delay 0.25 for device to respond and return data

res = read (fd, buf, 512);

另一种方法是继续阅读,直到到达足够数量的字符或经过合理的时间。

关于C读取调用阻塞串行端口操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7396255/

相关文章:

c - 当 ICANON 处于非规范模式时如何避免退格

c - 如何在c中操作整数类型的位?

python - 使用 PySerial 发送 ASCII 命令

java - Arduino - Serial.read() 无法读取两位数数据?

c - 如何更改 linux 终端中的回显字符

c - termios 在嵌入式设备上截断的串行数据

在 C 中创建定时器

compression - 为什么这个C程序填充驱动器C :\?

c - 使用预处理器将 char 数组替换为索引

c++ - 模拟串口