linux串口中断怎么配置?linux串口中断处理流程详解

在 Linux 系统中,串口(UART/Serial Port)通信通常可以通过轮询(Polling)中断(Interrupt)方式实现,中断方式效率更高,因为它允许 CPU 在等待数据时执行其他任务,直到硬件触发中断才处理数据。

以下是关于 Linux 串口中断的详细说明,包括:

【北京迅为】嵌入式学习之Linux驱动(第十七期_串口_全新升级)_基于RK3568开发板
加载中
【北京迅为】嵌入式学习之Linux驱动(第十七期_串口_全新升级)_基于RK3568开发板
  1. 用户空间如何通过中断方式读写串口
  2. 内核空间如何实现串口中断驱动
  3. 常见问题与调试技巧

用户空间:使用中断方式读写串口

在用户空间,Linux 提供了两种主要机制来实现“非阻塞”或“事件驱动”的串口通信:

使用 select() / poll() / epoll()

这是最常用、最推荐的方式,虽然它不是真正的“硬件中断”,但它通过内核的事件通知机制模拟了中断行为,避免忙等待。

示例代码(使用 select):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <string.h>
int open_serial_port(const char device) {
    int fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (fd < 0) {
        perror("open");
        return -1;
    }
    return fd;
}
int main() {
    int fd = open_serial_port("/dev/ttyS0");
    if (fd < 0) return 1;
    // 配置串口(略,实际需设置波特率、数据位等)
    struct termios tty;
    tcgetattr(fd, &tty);
    cfsetispeed(&tty, B9600);
    cfsetospeed(&tty, B9600);
    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
    tty.c_cflag &= ~CRTSCTS;
    tty.c_cflag |= CREAD | CLOCAL;
    tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    tty.c_iflag &= ~(IXO

linux串口中断怎么配置?linux串口中断处理流程详解

N | IXOFF | IXANY); tty.c_iflag &= ~(INLCR | ICRNL | IGNCR); tty.c_oflag &= ~OPOST; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0; tcsetattr(fd, TCSANOW, &tty); fd_set readfds; struct timeval timeout; while (1) { FD_ZERO(&readfds); FD_SET(fd, &readfds); timeout.tv_sec = 1; timeout.tv_usec = 0; int ret = select(fd + 1, &readfds, NULL, NULL, &timeout); if (ret < 0) { perror("select"); break; } else if (ret == 0) { printf("Timeoutn"); continue; } if (FD_ISSET(fd, &readfds)) { char buf[256]; ssize_t n = read(fd, buf, sizeof(buf)); if (n > 0) { printf("Received %d bytes: ", n); fwrite(buf, 1, n, stdout); printf("n"); } } } close(fd); return 0; }

✅ 优点:简单、可移植、无需修改内核。
❌ 缺点:不是真正的硬件中断,仍由内核调度。


使用 SIGIO 信号(真实中断通知)

Linux 支持通过 F_SETSIGFASYNC 实现基于信号的中断通知。

示例代码(使用 SIGIO):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <signal.h>
#include <string.h>
volatile sig_atomic_t got_data = 0;
void sigio_handler(int sig) {
    got_data = 1;
}
int main() {
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    // 配置串口(同上,略)
    // 设置进程组 ID 以便接收 SIGIO
    fcntl(fd, F_SETOWN, getpid());
    // 启用异步 I/O 和信号通知
    int flags = f

linux串口中断怎么配置?linux串口中断处理流程详解

cntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | FASYNC); // 设置信号类型为 SIGIO fcntl(fd, F_SETSIG, SIGIO); struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigio_handler; sigaction(SIGIO, &sa, NULL); char buf[256]; while (1) { if (got_data) { got_data = 0; ssize_t n = read(fd, buf, sizeof(buf)); if (n > 0) { printf("Received: "); fwrite(buf, 1, n, stdout); printf("n"); } } usleep(10000); // 避免忙等待 } close(fd); return 0; }

⚠️ 注意:SIGIO 需要内核支持,并且某些嵌入式平台可能未启用。


内核空间:实现串口中断驱动

如果你需要编写 Linux 内核模块来处理串口中断,你需要实现一个字符设备驱动,并注册中断服务程序(ISR)。

基本步骤:

  1. 分配并初始化 uart_port 结构。
  2. 注册中断处理函数。
  3. 实现 uart_ops 中的 .tx_empty.set_termios 等回调。
  4. 在中断服务程序中读取 FIFO 数据,并通过 tty_flip_buffer_push() 提交给 TTY 层。

示例:简化的中断处理函数

static irqreturn_t my_uart_isr(int irq, void dev_id) {
    struct my_uart_port port = dev_id;
    unsigned int status;
    // 读取状态寄存器
    status = readl(port->membase + UART_REG_LSR);
    if (status & UART_LSR_DR) {
        // 数据就绪,从数据寄存器读取
        unsigned char data = readb(port->membase + UART_REG_DATA);
        // 将数据放入 TTY 翻转缓冲区
        tty_insert_flip_string(&port->tty->port, &data, 1);
        tty_flip_buffer_push(&port->tty->port);
    }
    if (status & UART_LSR_THRE) {
        //

linux串口中断怎么配置?linux串口中断处理流程详解

发送寄存器为空,可以继续发送 if (!uart_circ_empty(&port->tty->port.xmit)) { // 发送下一个字节 unsigned char ch = port->tty->port.xmit[port->tty->port.xmit_head]; writeb(ch, port->membase + UART_REG_DATA); port->tty->port.xmit_head = (port->tty->port.xmit_head + 1) & (UART_XMIT_SIZE - 1); } } return IRQ_HANDLED; }

注册中断:

int ret = request_irq(irq_number, my_uart_isr, IRQF_SHARED, "my_uart", port);
if (ret) {
    dev_err(&pdev->dev, "Failed to request IRQ %dn", irq_number);
    return ret;
}

常见问题与调试

问题 可能原因 解决方案
收不到中断 中断未使能、引脚复用错误 检查设备树(DTS)中 UART 引脚配置
数据错乱 波特率不匹配、FIFO 未清空 检查波特率设置,清除 FIFO
中断频繁触发 噪声干扰、未屏蔽错误中断 检查 LSR 寄存器,屏蔽错误中断
用户空间收不到数据 TTY 层未正确推送 检查 tty_flip_buffer_push() 是否调用

  • 用户空间:推荐使用 select()/poll() 实现高效非阻塞 I/O,或使用 SIGIO 实现信号驱动。
  • 内核空间:需实现完整的 UART 驱动框架,注册中断服务程序,并通过 TTY 层提交数据。
  • 调试工具sttyminicomcat /proc/interruptsdmesg 等。

如需进一步深入某一部分(如设备树配置、DMA 支持、低功耗模式等),欢迎继续提问!

首发原创文章,作者:王坚‌,如若转载,请注明出处:https://test.idctop.com/article/487158.html

(0)
excel分数函数怎么用?excel求平均分公式
上一篇 2026年7月12日 13:54
linux系统如何查看硬盘?linux检测硬盘命令
下一篇 2026年7月12日 13:56

相关推荐

  • 手工迷你打印机好用吗,便携热敏打印机怎么连接手机

    手工迷你打印机作为连接数字创意与实体制作的关键工具,极大地提升了手账记录、标签制作及个性化设计的效率,其核心价值在于通过便携式设计与移动端互联,打破了传统打印设备的体积与操作限制,实现了随时随地的高精度输出,这类设备不仅满足了现代用户对即时性和个性化的双重需求,更通过低廉的耗材成本和丰富的软件生态,重新定义了桌……

    2026年2月21日
    13900
  • 一台500m服务器一个月多少钱,怎么选?

    一台500M带宽服务器的月租费用通常在800元到3000元之间,具体取决于硬件配置、线路类型和附加服务, 这个价格区间覆盖了从入门级单线到高防BGP的多数场景,实际成交价会因机房促销和租用时长有所浮动,500M服务器一个月多少钱?价格差异来自这些因素很多人问“500M服务器一个月多少钱”,其实答案很难用一个固定……

    2026年7月23日
    2100
  • API怎么使用教程?API接口调用方法详解

    API使用的核心在于通过HTTP协议发送标准化请求,获取结构化数据,关键在于理解鉴权机制、参数规范及错误处理逻辑,很多开发者在面对API文档时,往往感到头大如斗,觉得那是只有资深工程师才能读懂的天书,API(应用程序接口)就像是一个餐厅的服务员,你只需要告诉它你需要什么菜(发送请求),它就把做好的菜端给你(返回……

    2026年6月13日
    8100
  • Apache配置2个域名怎么做?Apache多域名配置教程

    Apache服务器配置两个域名的核心在于正确启用虚拟主机功能,并确保DNS解析与服务器文件路径的精准对应,通过修改httpd.conf主配置文件开启虚拟主机支持,随后在extra/httpd-vhosts.conf文件中定义两个独立的<VirtualHost *:80>区块,分别指定不同的Serve……

    2026年3月21日
    10400
  • 安装操作系统怎么操作?Linux系统安装教程详解

    成功安装Linux操作系统的核心在于选择正确的安装媒介与合理的分区规划,这直接决定了系统的稳定性与后续的使用体验,Linux安装并非简单的“下一步”操作,而是一个涉及硬件兼容性检查、引导模式配置、存储架构设计以及初始化用户环境构建的系统工程, 掌握UEFI引导模式与GPT分区格式的搭配,以及Swap分区与物理内……

    2026年3月21日
    11600
  • WOW怀旧服一个服务器多少人,服务器人数上限是多少?

    在《魔兽世界》怀旧服中,一个标准服务器的承载人数通常在1万到1.5万角色左右,但同一时间活跃在线人数会控制在5000人以内,暴雪通过技术手段限制单服人口以维持游戏生态平衡,而玩家实际感受到的“人多”或“人少”,更多取决于阵营比例、等级分布和位面系统,服务器容量的底层逻辑:为什么是1万人暴雪对怀旧服服务器的设计遵……

    2026年8月22日
    300
  • app与网站的关系是什么,WSA与CDN有什么区别

    App与网站已从早期的独立并行发展,转向深度的技术融合与架构统一,而WSA(Web Services Architecture或Web System Architecture,泛指Web服务架构)作为连接二者的核心骨架,结合CDN(内容分发网络)的加速机制,共同构成了现代互联网应用的性能基石,App与网站的关系……

    2026年3月17日
    11800
  • 服务器运行Java项目一般占多少内存,如何优化内存?

    服务器运行Java项目一般占多少内存,并没有固定数字,但多数中小型项目在512MB到2GB堆内存之间就能稳定运行,这个范围取决于项目规模、框架选择、并发量以及JVM参数的配置方式,把内存规划当作”按需分配”而不是”越大越好”,才是解决问题的核心思路,先搞清楚Java进程的内存构成Java项目的内存占用和普通程序……

    2026年8月22日
    000
  • dz论坛linux怎么搭建?linux部署discuz教程

    在Linux服务器上部署DZ论坛,核心在于选择轻量级环境搭配Nginx反向代理,并严格配置伪静态规则,这能确保论坛在高并发下依然保持秒级响应,很多站长在迁移或新建Discuz! X系列论坛时,往往习惯性地沿用Windows IIS环境,或者在Linux上盲目安装Apache,这种惯性思维在2026年的Web生态……

    2026年7月5日
    8000
  • iWebFusion美国独立服务器$219/月性能如何?美国VPS推荐性价比高

    iWebFusion美国独立服务器以$219/月的入门价格提供44核高性能配置,是平衡预算与算力需求的理想选择,尤其适合高并发Web应用及大规模数据处理场景,在云计算市场日益内卷的2026年,选择独立服务器不再仅仅是为了拥有“独占资源”,更是为了在成本可控的前提下获得极致的性能稳定性,iWebFusion推出的……

    2026年6月30日
    1800

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注