首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

linux 串口编程 阻塞

Linux串口编程中的阻塞是指在进行串口通信时,程序会等待直到某个条件满足才会继续执行。阻塞操作通常用于同步I/O操作,即程序在执行I/O操作时会暂停,直到操作完成。

基础概念

  • 串口(Serial Port):一种串行通信接口,用于设备之间的数据传输。
  • 阻塞I/O:当程序调用一个I/O操作时,如果该操作不能立即完成,程序会进入等待状态,直到操作完成。

相关优势

  1. 简单易用:阻塞I/O编程模型相对简单,易于理解和实现。
  2. 实时性:对于需要实时响应的应用,阻塞I/O可以确保数据及时处理。

类型

  • 完全阻塞:程序在等待I/O操作完成期间完全停止执行。
  • 部分阻塞:程序在等待I/O操作完成期间可以执行其他非关键任务。

应用场景

  • 嵌入式系统:在资源受限的环境中,阻塞I/O可以简化编程模型。
  • 实时系统:需要确保数据及时处理的场景。

遇到的问题及原因

问题:程序在读取串口数据时长时间阻塞,无法响应其他事件。

原因:

  1. 没有设置超时:默认情况下,串口读取操作会一直阻塞,直到有数据到达。
  2. 数据传输不稳定:串口通信可能因为硬件问题或信号干扰导致数据传输不稳定。

解决方法

设置读取超时

通过设置超时时间,可以在指定时间内没有数据到达时退出阻塞状态。

代码语言:txt
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>

int main() {
    int fd;
    struct termios options;

    // 打开串口设备
    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1) {
        perror("open_port: Unable to open /dev/ttyS0");
        return -1;
    }

    // 获取当前串口配置
    tcgetattr(fd, &options);

    // 设置波特率
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);

    // 设置数据位、停止位和校验位
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    // 设置输入模式
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    // 设置输出模式
    options.c_oflag &= ~OPOST;

    // 应用配置
    tcsetattr(fd, TCSANOW, &options);

    // 设置读取超时
    struct timeval timeout;
    timeout.tv_sec = 5;  // 5秒超时
    timeout.tv_usec = 0;
    tcsetattr(fd, TCSANOW, &timeout);

    char buffer[256];
    int n = read(fd, buffer, sizeof(buffer));
    if (n > 0) {
        buffer[n] = '\0';
        printf("Received data: %s\n", buffer);
    } else {
        printf("Read timeout or error occurred.\n");
    }

    close(fd);
    return 0;
}

使用非阻塞I/O

通过设置串口为非阻塞模式,可以在没有数据到达时立即返回。

代码语言:txt
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>

int main() {
    int fd;
    struct termios options;

    // 打开串口设备
    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1) {
        perror("open_port: Unable to open /dev/ttyS0");
        return -1;
    }

    // 获取当前串口配置
    tcgetattr(fd, &options);

    // 设置波特率
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);

    // 设置数据位、停止位和校验位
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    // 设置输入模式
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    // 设置输出模式
    options.c_oflag &= ~OPOST;

    // 设置非阻塞模式
    options.c_cc[VTIME] = 0;
    options.c_cc[VMIN] = 0;

    // 应用配置
    tcsetattr(fd, TCSANOW, &options);

    char buffer[256];
    int n;
    while (1) {
        n = read(fd, buffer, sizeof(buffer));
        if (n > 0) {
            buffer[n] = '\0';
            printf("Received data: %s\n", buffer);
        } else if (n == -1 && errno == EAGAIN) {
            // 没有数据到达,继续循环
            usleep(100000);  // 等待100毫秒
        } else {
            perror("read");
            break;
        }
    }

    close(fd);
    return 0;
}

通过上述方法,可以有效解决Linux串口编程中的阻塞问题,提高程序的响应性和稳定性。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

共4个视频
Linux Shell编程基础
研究僧
共53个视频
3.Linux运维学科--Shell编程
腾讯云开发者课程
共0个视频
网络编程专题
jaydenwen123
共0个视频
Linux进阶
运维小路
领券