Linux环境下使用interrupt方式操作UART
目录
概述
1 Linux环境下UART设备
2 轮询方式操作UART功能实现
2.1 打开串口函数:usr_serial_open
2.2 关闭串口函数: usr_serial_close
2.3 发送数据函数: usr_serial_sendbytes
2.4 接收数据函数: usr_serial_readinterrupt
3 完整代码
3.1 usr_serial.c 文件内容
3.1 usr_serial.h 文件内容
4 编写测试代码
4.1 编写测试代码
4.2 编写测试代码的Makefile
5 测试中断模式下串口数据的发送和接收功能
源代码下载地址:Linux环境下使用interrupt方式操作UART资源-CSDN文库
概述
本文介绍Linux环境下使用interrupt方式操作UART的方法,实现了串口打开,关闭,发送数据,接收数据功能,还编写测试代码,验证该功能。
1 Linux环境下UART设备
在linux环境下,UART作为一个终端设备存在,可使用命令, 系统会罗列出该目录下所有的device,其中以tty开头的设备为终端设备。串口也是这些设备之一。
ls /dev/ -l
执行该命令后,可以看见许多以tty开头的设备:

user根据板卡的信息,找到对应的端口,然后才能使用这些串口,笔者使用是基于iMX6ull芯片的板卡,板卡上COM1被用于调试终端,COM3可作为用户终端。

2 轮询方式操作UART功能实现
2.1 打开串口函数:usr_serial_open
函数参数
| 参数 | 描述 |
|---|---|
| port | 终端设备: /dev/tty0 |
| baudrate | 波特率: 1200/2400/4800 ... /115200 |
| databit | 数据bit位: /5/6/7/8 |
| stopbit | 停止位:"1" / "1.5" / "2" |
| parity | 奇偶位使能: 'N' / 'E' / 'O' |
函数实现方法:
代码 43行: 打开端口
代码 49行: 保存termios数据结构中,旧的参数
代码 51行:设置当前用户参数

源代码:
int usr_serial_open( char *port, unsigned int baudrate, unsigned int databit, const char *stopbit, char parity)
{int err;fd = open (port, O_RDWR | O_NOCTTY | O_NDELAY);if (-1 == fd) {fprintf(stderr, "cannot open port %s\n", port);return (-1);}tcgetattr (fd, &termios_old); /* save the form termios value */err = set_portattr (baudrate, databit, stopbit, parity);if ( err ) {fprintf ( stderr, "\nport %s cannot set baudrate at %d\n",port, baudrate);}usr_baudrate = baudrate;return fd;
}
2.2 关闭串口函数: usr_serial_close
函数实现方法:
代码 64行: 恢复termios default参数
代码 65行:关闭fd端口

void usr_serial_close( void )
{/* flush output data before close and restore old attribute */tcsetattr(fd, TCSADRAIN, &termios_old);close(fd);
}
2.3 发送数据函数: usr_serial_sendbytes
函数参数
| 参数 | 描述 |
|---|---|
| *data | 存贮数据的数组 |
| datalength | 发送的数据长度 |
函数实现方法:
代码 72行: 使用write函数发送数据

2.4 接收数据函数: usr_serial_readinterrupt
函数参数
| 参数 | 描述 |
|---|---|
| *data | 存贮数据的数组 |
| datalength | 接收的数据长度 |
函数实现方法:
代码 100~102行: 配置接收中断
代码 104行: 使用read函数写数据

unsigned int usr_serial_readinterrupt (void *data, unsigned int datalength)
{int total_len = 0;/*** caculate the time of 5 characters and get the maxim* with 3ms and 5 ch's time*/tv_timeout.tv_sec = 0;tv_timeout.tv_usec = ( (CH_TO_WAIT * CH_BITS) * (1000000/usr_baudrate));while(1){FD_ZERO (&fs_read);FD_SET (fd, &fs_read);select (fd + 1, &fs_read, NULL, NULL, &tv_timeout);total_len = read(fd, data, datalength);if (total_len > 0) {printf("Receive %d bytes: %.*s\n", total_len, (char*)data);return total_len;}}return total_len;}
3 完整代码
代码文件命名为usr_serial, 包含两个文件
usr_serial.c usr_serial.h
3.1 usr_serial.c 文件内容
/***************************************************************
Copyright 2024-2029. All rights reserved.
文件名 : 01_usr_serial.c
作者 : tangmingfei2013@126.com
版本 : V1.0
描述 : linux 串口应用程序接口
其他 : 无
日志 : 初版V1.0 2024/03/01***************************************************************/
#include "usr_serial.h"/* Private define ------------------------------------------------------------*/
#define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2)
#define TIMEOUT_USEC 0#define CH_TO_WAIT 5
#define CH_BITS 11/* Private variables ---------------------------------------------------------*/
static unsigned int fd; static struct timeval tv_timeout;
static struct termios termios_old;
static struct termios termios_new;static fd_set fs_read;
static unsigned int usr_baudrate;/* Private function prototypes -----------------------------------------------*/
static speed_t baudrate_to_Bxx (unsigned int baudrate);
static void set_data_bit (unsigned int databit);
static unsigned int set_portattr ( unsigned int baudrate,unsigned int databit, const char *stopbit,char parity);int usr_serial_open( char *port, unsigned int baudrate, unsigned int databit, const char *stopbit, char parity)
{int err;fd = open (port, O_RDWR | O_NOCTTY | O_NDELAY);if (-1 == fd) {fprintf(stderr, "cannot open port %s\n", port);return (-1);}tcgetattr (fd, &termios_old); /* save the form termios value */err = set_portattr (baudrate, databit, stopbit, parity);if ( err ) {fprintf ( stderr, "\nport %s cannot set baudrate at %d\n",port, baudrate);}usr_baudrate = baudrate;return fd;
}void usr_serial_close( void )
{/* flush output data before close and restore old attribute */tcsetattr(fd, TCSADRAIN, &termios_old);close(fd);
}unsigned int usr_serial_sendbytes (void * data, unsigned int datalength)
{unsigned int total_len = 0;total_len = write(fd, data, datalength);return (total_len);
}int usr_serial_readbytes (void *data, unsigned int datalength)
{unsigned int total_len = 0;total_len = read(fd, data, datalength);if (total_len > 0) {printf("Receive %d bytes: %.*s\n", total_len, (char*)data);}return (total_len);
}unsigned int usr_serial_readinterrupt (void *data, unsigned int datalength)
{int total_len = 0;/*** caculate the time of 5 characters and get the maxim* with 3ms and 5 ch's time*/tv_timeout.tv_sec = 0;tv_timeout.tv_usec = ( (CH_TO_WAIT * CH_BITS) * (1000000/usr_baudrate));while(1){FD_ZERO (&fs_read);FD_SET (fd, &fs_read);select (fd + 1, &fs_read, NULL, NULL, &tv_timeout);total_len = read(fd, data, datalength);if (total_len > 0) {printf("Receive %d bytes: %.*s\n", total_len, (char*)data);return total_len;}}return total_len;}static void set_data_bit (unsigned int databit)
{termios_new.c_cflag &= ~CSIZE;switch (databit) {default:case 8:termios_new.c_cflag |= CS8;break;case 7:termios_new.c_cflag |= CS7;break;case 6:termios_new.c_cflag |= CS6;break;case 5:termios_new.c_cflag |= CS5;break;}
}static void set_stopbit (const char *stopbit)
{if (0 == strcmp (stopbit, "1")) {termios_new.c_cflag &= ~CSTOPB; /* 1 stop bit */}else if (0 == strcmp (stopbit, "1.5")) {termios_new.c_cflag &= ~CSTOPB; /* 1.5 stop bits */}else if (0 == strcmp (stopbit, "2")) {termios_new.c_cflag |= CSTOPB; /* 2 stop bits */}else {termios_new.c_cflag &= ~CSTOPB; /* 1 stop bit */}
}static void set_parity (char parity)
{switch (parity) {case 'N': /* no parity check */termios_new.c_cflag &= ~PARENB;break;case 'E': /* even */termios_new.c_cflag |= PARENB;termios_new.c_cflag &= ~PARODD;break;case 'O': /* odd */termios_new.c_cflag |= PARENB;termios_new.c_cflag |= ~PARODD;break;default: /* no parity check */termios_new.c_cflag &= ~PARENB;break;}
}static speed_t baudrate_to_Bxx (unsigned int baudrate)
{switch (baudrate) {case 0:return (B0);case 50:return (B50);case 75:return (B75);case 110:return (B110);case 134:return (B134);case 150:return (B150);case 200:return (B200);case 300:return (B300);case 600:return (B600);case 1200:return (B1200);case 2400:return (B2400);case 9600:return (B9600);case 19200:return (B19200);case 38400:return (B38400);case 57600:return (B57600);case 115200:return (B115200);default:return (B9600);}
}static void set_baudrate (unsigned int baudrate)
{speed_t speed;speed = baudrate_to_Bxx (baudrate); /* set baudrate */cfsetispeed(&termios_new, speed); // set input speedcfsetospeed(&termios_new, speed); // set output speed
}static unsigned int set_portattr ( unsigned int baudrate, // 1200 2400 4800 9600 .. 115200unsigned int databit, // 5, 6, 7, 8const char *stopbit, // "1", "1.5", "2"char parity) // N(o), O(dd), E(ven)
{bzero(&termios_new, sizeof (termios_new));cfmakeraw (&termios_new);set_baudrate (baudrate);termios_new.c_cflag |= CLOCAL | CREAD; /* | CRTSCTS */set_data_bit (databit);set_parity (parity);set_stopbit (stopbit);termios_new.c_cc[VTIME] = 1; /* unit: 1/10 second. */termios_new.c_cc[VMIN] = 255; /* minimal characters for reading */return (tcsetattr (fd, TCSANOW, &termios_new));
}/* End of this file */
3.1 usr_serial.h 文件内容
#ifndef __USR_SERIAL_H
#define __USR_SERIAL_H#include <termios.h> /* tcgetattr, tcsetattr */
#include <stdio.h> /* perror, printf, puts, fprintf, fputs */
#include <unistd.h> /* read, write, close */
#include <fcntl.h> /* open */
#include <sys/signal.h>
#include <sys/types.h>
#include <string.h> /* bzero, memcpy */
#include <limits.h> /* CHAR_MAX */#ifdef __cplusplus
extern "C" {
#endifint usr_serial_open( char *port, unsigned int baudrate, unsigned int databit, const char *stopbit, char parity);
void usr_serial_close( void );unsigned int usr_serial_sendbytes (void * data, unsigned int datalength);
int usr_serial_readbytes (void *data, unsigned int datalength);
unsigned int usr_serial_readinterrupt (void *data, unsigned int datalength);#ifdef __cplusplus
}
#endif#endif /* __USR_SERIAL_H */
4 编写测试代码
4.1 编写测试代码
代码实现功能介绍:
代码 39行:初始化串口设备,设置baud,数据位,停止位等参数
代码 48行:从串口读取数据
代码 55行:向串口写数据

4.2 编写测试代码的Makefile
代码实现功能介绍:
代码 2行:编译器地址
代码 3行:linux内核地址
代码 3行:链接的.o文件名
代码 6行:生成可执行型文件

5 测试中断模式下串口数据的发送和接收功能
使用Make命令编译代码,然后将生成的可执行性文件copy到NFS的共享目录下,然后在板卡中执行。
在代码中,定义要发送的数据如下:
strcpy(buf, "I am from iMX.6ULL board, hello world! \r\n");

PC端,使用串口调试助手接收数据,详细信息如下:

相关文章:
Linux环境下使用interrupt方式操作UART
目录 概述 1 Linux环境下UART设备 2 轮询方式操作UART功能实现 2.1 打开串口函数:usr_serial_open 2.2 关闭串口函数: usr_serial_close 2.3 发送数据函数: usr_serial_sendbytes 2.4 接收数据函数: usr_serial_readinterr…...
修改Android打包apk的名字和目录
app打包生成apk后通常需要进行备份,但是要区分好哪个apk是什么版本的、什么时候打包的,以方便以后区分使用。 最开始的想法是把版本号、创建时间这些加在apk文件名上即可,但是公司要求apk使用一个固定的名称,那我怎么保存版本号信…...
管理 PostgreSQL 中配置参数的各种方法
管理 PostgreSQL 中配置参数的各种方法 1. 概述 PostgreSQL提供了一个配置文件 postgresql.conf 让用户自定义参数。您可能需要更改一些参数来调整性能或在工作环境中部署 PostgreSQL 服务器。在这篇博文中,我们将探索管理这些参数的不同方法。 2. 以不同方式管理…...
Linux命令-continue命令(结束本次循环,继续执行下一个for,while或until循环。)
概要 continue [n]主要用途 结束本次循环,继续执行下一个for,while或until循环;可指定从第几层循环继续执行。 参数 n(可选):大于等于1的整数,用于指定从第几层循环继续执行。 返回值 返回…...
智能部署之巅:Amazon SageMaker 引领机器学习革新
本篇文章授权活动官方亚马逊云科技文章转发、改写权,包括不限于在 亚马逊云科技开发者社区, 知乎,自媒体平台,第三方开发者媒体等亚马逊云科技官方渠道。 (全球 TMT 2023年12月6日讯)亚马逊云科技在 2023 re:Invent 全…...
国内哪个工具可以平替chatgpt?国内有哪些比较好用的大模型gpt?
我自己试用了很多的平台,发现三个比较好的大模型平台,对普通用户也比较的友好的,而且返回内容相对来说,正确率更高的,并且相关场景插件比较丰富的国内厂商。 本文说的,是我自己觉得的,比较有主观…...
python如何打包py文件为exe
要将Python程序打包为可执行文件(.exe),您可以使用一些第三方工具。以下是两个常用的工具:PyInstaller和cx_Freeze。 使用PyInstaller PyInstaller是一个流行的Python打包工具,可以将Python程序及其所有依赖项打包为…...
yolov9网络结构图
文章目录 配置文件主干分支backbone预测头headyolov9网络结构图 系列文章目录 论文链接:👿 YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information代码链接:👿 https://github.com/WongKinYiu/yolov9…...
Spark 核心API
核心 API spark core API 指的是 spark 预定义好的算子。无论是 spark streaming 或者 Spark SQL 都是基于这些最基础的 API 构建起来的。理解这些核心 API 也是写出高效 Spark 代码的基础。 Transformation 转化类的算子是最多的,学会使用这些算子就应付多数的数…...
OpenLayers线性渐变和中心渐变(径向渐变)
目录 1.前言2.添加一个面要素3.线性渐变3.1 第一个注意点3.2 第二个注意点 4.中心渐变(径向渐变)5.总结 1.前言 OpenLayers官网有整个图层的渐变示例,但是没有单个要素的渐变示例,我们这里来补充一下。OpenLayers中的渐变是通过fi…...
[210. 课程表 II] 拓扑排序模板(DFS+BFS)
Problem: 210. 课程表 II 文章目录 思路解题方法Code 思路 本题是经典拓扑排序模板,通过DFS和BFS两种方式进行实现。 解题方法 DFS DFS方法的重点在于如何标记节点状态,初做题者如果只用未访问和已访问两种状态很容易陷入死结。正确的做法是使用三种状…...
我的第一个python web 网站
# -*- coding: utf-8 -*-import http.server import socketserver from datetime import datetimePORT 8000import sys# ...class MyHandler(http.server.SimpleHTTPRequestHandler):def do_GET(self):if self.path /:# 如果路径是根路径,返回页面内容self.send_r…...
产品展示型wordpress外贸网站模板
孕婴产品wordpress外贸网站模板 吸奶器、待产包、孕妇枕头、护理垫、纸尿裤、孕妇装、孕婴产品wordpress外贸网站模板。 https://www.jianzhanpress.com/?p4112 床品毛巾wordpress独立站模板 床单、被套、毛巾、抱枕、靠垫、围巾、布艺、枕头、乳胶枕、四件套、浴巾wordpre…...
四信全球化拓展再启新篇!LoRa传感器与云平台领航智能感知时代
随着科技浪潮的不断推进,物联网已逐渐融入我们的生活。刚刚结束的MWC24盛会上,四信带来了一系列前沿技术成果,不仅将5G技术成功扩展至当前市场主流类型的终端,更携手联通、ASR等业界巨头,在连接、5G RedCap、AI、LoRa以…...
阿里云k8s环境下,因slb限额导致的发布事故
一、背景 阿里云k8s容器,在发布java应用程序的时候,客户端访问出现500错误。 后端服务是健康且可用的,网关层大量500错误请求,slb没有流入和流出流量。 经过回滚,仍未能解决错误。可谓是一次血的教训,特…...
【STM32+OPENMV】矩形识别
一、准备工作 有关OPENMV最大色块追踪及与STM32通信内容,详情见【STM32HAL】与OpenMV通信 二、所用工具 1、芯片:STM32F103C8T6 2、CUBEMX配置软件 3、KEIL5 4、OPENMV 三、实现功能 寻找黑色矩形,并将最大矩形的四个边缘坐标发送给STM…...
在吗?腾讯云服务器优惠价格表曝光_2023年3月报价请过目!
腾讯云服务器多少钱一年?61元一年起,2核2G3M配置,腾讯云2核4G5M轻量应用服务器165元一年、756元3年,4核16G12M服务器32元1个月、312元一年,8核32G22M服务器115元1个月、345元3个月,腾讯云服务器网txyfwq.co…...
Revit-二开之创建Plane-(7)
2016版本的Plane 2017版本的Plane 2018版本及以上版本的Plane 由此可见2017版本是一个分水岭 #if REVIT2016Plane plane = new Plane(uiDoc.Document.ActiveView...
【操作系统学习笔记】文件管理1.2
【操作系统学习笔记】文件管理1.2 参考书籍: 王道考研 视频地址: Bilibili 文件的逻辑结构 无结构文件 文件内部的数据就是一系列的二进制流或字符流组成,又称流式文件,例如 .text 文件 有结构文件 由一组相似的记录组成,又称记录式文件…...
算法归纳【数组篇】
目录 二分查找1. 前提条件:2. 二分查找边界 2.移除元素有序数组的平方长度最小的子数组59.螺旋矩阵II54. 螺旋矩阵 二分查找 参考链接 https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html#%E6%80%9D%E8%B7%AF 1. 前提条件: 数…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
