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_SETSIG 和 FASYNC 实现基于信号的中断通知。

示例代码(使用 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 层提交数据。
  • 调试工具:stty、minicom、cat /proc/interrupts、dmesg 等。

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

首发原创文章,作者:王坚‌,如若转载,请注明出处:https://idctop.com/linux%e4%b8%b2%e5%8f%a3%e4%b8%ad%e6%96%ad%e6%80%8e%e4%b9%88%e9%85%8d%e7%bd%ae%ef%bc%9flinux%e4%b8%b2%e5%8f%a3%e4%b8%ad%e6%96%ad%e5%a4%84%e7%90%86%e6%b5%81%e7%a8%8b%e8%af%a6%e8%a7%a3/

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

相关推荐

  • 全世界到底有多少个www根服务器?,中国为何没有根服务器?

    全世界共有13台IPv4域名根服务器,其中1台为主根服务器(美国),另12台为辅根服务器,分布在北美、欧洲和亚洲等地,这个数字自互联网诞生以来基本未变,但很多人不知道,支撑全球域名解析的真正基础设施,远不止这13台物理设备,根服务器的本质:互联网的“总机台”如果把互联网比作一座巨型城市,域名就是每栋建筑的地址……

    2026年8月29日
    600
  • 互联网服务器到底有多少台?,全球服务器数量统计是多少?

    互联网服务器没有一个全国或全球统一的“台数”答案;按物理服务器存量看,行业公开口径大体落在千万台量级,中国是百万台到千万台量级的重要市场,而云主机、容器和边缘实例数量远高于物理机,且随业务弹性变化, 问“多少台”之前,先要问清楚统计的是物理机、云实例,还是机柜里的整机,互联网服务器多少台:先分清“台”指的是什么……

    相关资讯 2026年11月4日
    000
  • linux归档压缩怎么操作?linux常用压缩命令有哪些

    Linux下处理归档压缩的核心在于区分“归档”与“压缩”两个概念,通常使用tar进行打包归档,再结合gzip、bzip2或xz等工具进行压缩,其中tar.gz组合因兼容性好、速度平衡,是绝大多数场景下的首选方案,在Linux系统运维和开发日常中,文件管理不仅仅是简单的复制粘贴,更涉及数据的高效存储与传输,很多新……

    2026年7月10日
    10010
  • 如何彻底卸载Linux下的Resin?Linux卸载Resin完整步骤

    在Linux系统中卸载Resin最稳妥的方式是停止服务进程、删除安装目录并清理环境变量,若需彻底移除则还需清理系统服务配置及数据库连接信息,Resin作为一款经典的Java应用服务器,虽然近年来市场份额被Tomcat和Spring Boot内嵌容器大幅挤压,但在许多遗留系统、老旧企业应用以及特定嵌入式场景中,它……

    2026年7月6日
    20700
  • 服务器1m能承受多少人在线,实际负载怎么算?

    1M带宽的服务器通常只能支撑30到50个轻度访问用户的在线场景,动态网站往往20人左右就已卡顿,简单说,1Mbps约等于128KB/s的传输速度,假设页面均重100KB,每秒只能满足1到2个页面的完整加载,更别提图片、视频或接口并发请求,下面从带宽换算、场景模拟、压力测试到优化方案,一步步把“1M”的真实底线拆……

    2026年8月23日
    600
  • 江苏DNS服务器地址是多少?,如何选择最佳DNS?

    江苏地区的DNS服务器地址并没有一个强制统一的官方值,而是根据你使用的网络运营商(电信、联通、移动)和上网方式(宽带拨号、企业专线、云服务器)有所区别,对于大多数江苏家庭宽带用户,推荐使用运营商的自动分配DNS;对于追求更快解析速度和更高稳定性的用户,主流选择是阿里云DNS(223.5.5.5)和腾讯云DNS……

    2026年10月18日
    000
  • 微信建服务器要花多少钱,费用明细是什么?

    微信建服务器多少钱?答案不是一口价:用微信云开发,年付可能几百到几千;用轻量云服务器自建,通常千元级起步;若涉及物理服务器托管、高防和独享带宽,月付几千到上万都正常, 关键看你的业务量、合规要求和运维能力,钱要花在服务器、带宽、数据库、CDN、备案、认证和防护上,微信建服务器,成本到底由什么构成很多人一上来就问……

    2026年10月15日
    000
  • 联想sd530服务器到底多少钱,性价比怎么样?

    联想SD530服务器的市场价格没有固定数字,主要看配置和采购渠道;一套主流双路满配(双CPU、128G内存、若干硬盘)的市场成交价通常在2万到5万元区间,裸机准系统则从1万元上下起步,为什么联想SD530的价格差这么多联想SD530是2U双路机架服务器,定位是数据中心的通用计算节点,它的价格跨度极大,原因主要有……

    2026年10月6日
    100
  • 服务器太空舱价格多少,一台大概多少钱

    基础款两万上下,标准静音柜六万到十五万,微模块级整套落地通常超过十五万,具体看配置和服务商资质,服务器太空舱价格构成:为何一个柜子能从几万跨到几十万服务器太空舱本质上是一个集成了机柜、散热、供电、消防、监控的密闭模块,替代传统机房土建改造,过去企业要部署服务器,先要腾房间、装空调、做防静电地板、走线、装消防,整……

    2026年10月7日
    000
  • 鹰角服务器究竟延期多少次了,2026还会继续延期吗?

    鹰角网络的游戏延期并非偶发事件,从《明日方舟》活动跳票到《来自星尘》的漫长等待,再到《终末地》的反复测试延期,这家以品质著称的公司在玩家群体中留下了”精益求精但节奏难测”的鲜明印象,据不完全统计,鹰角旗下主要产品在公开测试和版本更新中,较大比例出现过至少一次以上的延期调整,近年来,二次元游戏赛道竞争白热化,玩家……

    2026年10月9日
    100

发表回复

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