使用 select 进行 UART 通信的注意事项
文章目录
- 引言
- UART 通信中的 `select` 函数
- `select` 函数的工作原理
- 使用 `select` 进行 UART 通信的注意事项
- 示例代码
引言
UART(Universal Asynchronous Receiver/Transmitter)是一种用于异步串行通信的硬件协议,常用于计算机和外设之间的数据交换。在嵌入式系统中,UART 通信非常常见,用于连接传感器、微控制器、调制解调器等设备。为了实现高效的 UART 通信,通常需要使用非阻塞式 I/O 操作,这时候 select
函数就派上用场了。
UART 通信中的 select
函数
select
函数允许我们同时监控多个文件描述符,并在这些文件描述符变为可读、可写或发生错误时通知程序。这样可以避免程序在等待 I/O 操作时被阻塞,提高系统的响应速度和效率。
select
函数的工作原理
- 监控文件描述符:
select
接受一组文件描述符,并监控这些文件描述符的状态。 - 阻塞等待:可以设置阻塞等待或非阻塞等待,直到文件描述符变为可读、可写或发生错误,或者达到超时时间。
- 返回事件:
select
返回后,程序可以检查哪些文件描述符变为可读、可写或发生错误,并进行相应的处理。
使用 select
进行 UART 通信的注意事项
在使用 select
进行 UART 通信时,有几个关键点需要注意:
- 正确初始化文件描述符集
每次调用 select
之前,需要重新初始化文件描述符集(fd_set
),因为 select
调用会修改这个集合:
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
- 设置超时值
在每次调用 select
之前,需要设置超时值(struct timeval
)。同样,select
会修改这个结构体,因此每次调用前都需要重新设置:
struct timeval tv;
tv.tv_sec = timeout_us / 1000000;
tv.tv_usec = timeout_us % 1000000;
- 处理
select
的返回值
检查 select
的返回值以确定是否有文件描述符变为可读、可写或出错:
int ret = select(fd + 1, &rfds, NULL, NULL, &tv);
if (ret == -1) {// Handle error
} else if (ret == 0) {// Handle timeout
} else {if (FD_ISSET(fd, &rfds)) {// Handle readable data}
}
- 避免文件描述符泄漏
确保在程序结束或不再需要文件描述符时关闭它们,防止资源泄漏:
close(fd);
- 多线程环境下的文件描述符使用
如果在多线程环境下使用文件描述符,需要确保对文件描述符的操作是线程安全的。使用互斥锁(mutex)保护对文件描述符的操作,避免竞态条件。
- 检查文件描述符的有效性
在调用 select
之前检查文件描述符是否有效,确保文件描述符在整个生命周期中是有效的:
int check_fd_valid(int fd) {return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}
- 处理边界情况
处理 read
返回 0
的情况,这通常表示文件结束或没有数据可用:
ssize_t bytesRead = read(fd, buff, len);
if (bytesRead == -1) {// Handle read error
} else if (bytesRead == 0) {// Handle EOF or no data
}
示例代码
以下是综合了上述注意事项的改进代码示例:
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <unistd.h>
#include <errno.h>
#include <stdint.h>
#include <stdarg.h>
#include <fcntl.h>
#include <pthread.h>void ota_info(const char *fmt, ...) {va_list args;va_start(args, fmt);vprintf(fmt, args);printf("\n");va_end(args);
}int check_fd_valid(int fd) {return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}int uart_read(int fd, uint8_t *buff, int len, int timeout_us)
{int ret;struct timeval tv;fd_set rfds;memset(buff, 0, len);// Debug log to print fd value before selectota_info("uart_read: fd=%d, timeout_us=%d, thread_id=%ld", fd, timeout_us, pthread_self());// Check if fd is validif (!check_fd_valid(fd)) {ota_info("Invalid file descriptor: %d", fd);return -1;}FD_ZERO(&rfds);FD_SET(fd, &rfds);memset(&tv, 0, sizeof(tv));tv.tv_sec = timeout_us / 1000000;tv.tv_usec = timeout_us % 1000000;ret = select(fd + 1, &rfds, NULL, NULL, &tv);if (ret == -1) {// Select itself failedota_info("select() failed. ret %d, errno %d, %m", ret, errno);return -1;} else if (ret == 0) {// Timeout occurred without any file descriptor becoming readyota_info("select() timed out.");return 0; // Indicate timeout}if (FD_ISSET(fd, &rfds)) {ssize_t bytesRead = read(fd, buff, len);if (bytesRead == -1) {// Error during readota_info("read() failed. errno %d, %m", errno);return -1;} else if (bytesRead == 0) {// EOF reached or no data availableota_info("read() returned 0, no data available or EOF reached.");return 0;}// Return actual bytes readota_info("read() succeeded. bytesRead=%ld, thread_id=%ld", bytesRead, pthread_self());return bytesRead;} else {// This branch should not be reachable given the checks aboveota_info("select() returned with no file descriptor ready.");return 0;}
}int main() {// Example usageint fd = 0; // Example file descriptor, should be initialized properlyuint8_t buffer[256];int len = 256;int timeout_us = 5000000; // 5 secondsint result = uart_read(fd, buffer, len, timeout_us);if (result > 0) {printf("Read %d bytes\n", result);} else if (result == 0) {printf("Timeout or no data available\n");} else {printf("Error occurred\n");}return 0;
}
通过遵循这些注意事项,可以确保在使用 select
函数进行 UART 通信时,代码更加健壮和可靠,减少出现难以复现的错误的可能性。希望这篇博客能帮助你在项目中更好地使用 select
函数进行 UART 通信。
相关文章:
使用 select 进行 UART 通信的注意事项
文章目录 引言UART 通信中的 select 函数select 函数的工作原理使用 select 进行 UART 通信的注意事项示例代码 引言 UART(Universal Asynchronous Receiver/Transmitter)是一种用于异步串行通信的硬件协议,常用于计算机和外设之间的数据交换…...

干货 | 2024低空经济产业发展白皮书(免费下载)
【1】关注本公众号,转发当前文章到微信朋友圈 【2】私信发送 2024低空经济产业发展白皮书 【3】获取本方案PDF下载链接,直接下载即可。 如需下载本方案PPT/WORD原格式,诚挚邀请您微信扫描以下二维码加入方案驿站知识星球,获取上…...

打开nginx连接的php页面报错502
目录 问题描述: 原因: 1. 使用 Unix 域套接字(Unix Socket) 区别和优势: 2. 使用 TCP/IP 套接字 区别和优势: 如何选择 扩展:Rocky_Linux9.4安装PHP的步骤: 使用Remi存储库…...
Qt之文件操作(QFile、QFileInfo、QTemporaryFile)
文章目录 前言QFile如何使用 QFile QFileInfo如何使用 QFileInfo QTemporaryFile如何使用 QTemporaryFile QFile常用函数QFileInfo常用函数QTemporaryFile常用函数总结 前言 在开发 Qt 应用程序时,我们经常需要进行文件操作,如读取文件、写入文件、获取…...
Python爬虫初试
在Python中,我们可以使用一些强大的库来编写一个功能强大的爬虫, Python 首先安装必要的库(如果尚未安装) pip install requests beautifulsoup4 import requests from bs4 import BeautifulSoup import osdef download_images(…...
ARM-V9 RME(Realm Management Extension)系统架构之系统初始化流程
安全之安全(security)博客目录导读 目录 一、重置取消 二、应用处理单元(PE)初始启动 三、MSD初始化 四、GPT初始化 五、初始启动退出(由所有应用PE执行) 六、RMSD初始化 七、PE进入丢失上下文的低功耗状态 本博客提供了R…...

软件工程考试题备考
文章目录 前言一、二、1.2 总结 前言 一、 B D C 类图、对象图、包图 其他系统及用户 功能需求 用例 人、硬件或其他系统可以扮演的角色7. D C 数据 原型/系统原型;瀑布 A 功能;功能需求 D 数据存储;圆形/圆角矩形;矩形 C T;T;F C C B C D C …...

一款基于WordPress开发的高颜值的自适应主题Puock
主题特性 支持白天与暗黑模式 全局无刷新加载 支持博客与CMS布局 内置WP优化策略 一键全站变灰 网页压缩成一行 后台防恶意登录 内置出色的SEO功能 评论Ajax加载 文章点赞、打赏 支持Twemoji集成 支持QQ登录 丰富的广告位 丰富的小工具 自动百度链接提交 众多页面模板 支持评论…...
浙教版 七年级下册 科学复习干货
七年级下册 浙教版科学 复习干货 文章目录 七年级下册 浙教版科学 复习干货第 I 章人类 H u m a n Human Human人类生殖系统胚胎发育、娩出过程青春期 动物 A n i m a l Animal Animal生长时期有性生殖无性生殖 植物 P l a n t Plant Plant种子结构种子萌发芽花有性生殖无性…...
罗盘时钟lua迷你世界
--罗盘时钟 --星空露珠工作室制作 --作者:韩永旗 --数字换中文 local zhChar {一,二,三,四,五,六,七,八,九} function formatNumber( num ) if type(num)~number then return num..is not a num end if num>99 then return num..不是两位数 end if num0 then return 零 el…...

【Java】Java基础语法
一、注释详解 1.1 注释的语法: // 单行注释/*多行注释 *//**文档注释 */ 1.2 注释的特点: 注释不影响程序的执行,在Javac命令进行编译后会将注释去掉 1.3 注释的快捷键 二、字面量详解 2.1 字面量的概念: 计算机是用来处理…...

利用golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置
文章目录 前言一、prometheus发现方式二、监控指标注册架构图三、部分代码展示1.核心思想2.代码目录3、程序入口函数剖析4、settings配置文件5、初始化配置文件及consul6、全局变量7、配置config8、公共方法目录common9、工具目录tools10、service层展示11、命令行参数12、Make…...

Python爬虫介绍
Python 作为一种广泛应用的编程语言,在 Web 开发、大数据开发、人工智能开发和嵌入式开发等领域都有着重要的应用。 Python 的易学性、清晰性和可移植性等特点使它得到很多技术人士的喜爱。对于数据科学和机器学习领域的程序员来说,Python 提供了强大的…...

Linux 进程管理
一、查看进程 使用ps -aux进行查看,其中a表示列出所有进程信息,u以用户格式显示进程信息,x显示后台进程参数,也可以使用| grep 进行进程的筛选 以下是显示进程后的示意 USER为进程执行的用户 PID为进程号 %CPU为该进程的cpu占用…...

【车载测试】CAN协议、CAN- FD协议和FlexRay协议 区别
【上半场电动化,下半场智能化】 一、CAN协议 和 CAN- FD协议的区别 CAN(Controller Area Network)协议是一种广泛用于汽车和工业控制系统等领域的现场总线协议。CAN- FD(Flexible Data Rate)协议是对CAN协议的扩展&am…...

对日期的处理
对日期的处理 对编码进行统一,在脚本最开始: # -*- coding: utf-8 -*-这里涉及到两个操作,一个是将数据进行标准化,比如有些日期是2024/05/06这并不符合日期的标准格式,需要转换成这样的2024-05-06 def tran_std(st…...

赵丽颖纯白茉莉绽放温柔之美
赵丽颖纯白茉莉,绽放温柔之美在这个繁忙喧嚣的娱乐圈,赵丽颖以其独特的魅力,成为了无数人心中的白月光。近日,赵丽颖工作室发布了一组live图,她身着一袭温柔白裙,宛如一朵盛开的纯白茉莉花,美得…...

软考高级论文真题“论湖仓一体架构及其应用”
论文真题 随着5G、大数据、人工智能、物联网等技术的不断成熟,各行各业的业务场景日益复杂,企业数据呈现出大规模、多样性的特点,特别是非结构化数据呈现出爆发式增长趋势。在这一背景下,企业数据管理不再局限于传统的结构化OLTP…...

CentOS系统查看版本的各个命令
cat /etc/centos-release 查看CentOS版本 uname -a 命令的结果分别代表:当前系统的内核名称、主机名、内核发型版本、节点名、系统时间、硬件名称、硬件平台、处理器类型以及操作系统名称 cat /proc/version 命令用于查看Linux内核的版本信息。执行该命令后…...

[保姆级教程]uniapp实现底部导航栏
文章目录 前置准备工作安装HBuilder-X新建uniapp项目教程使用HBuilder-X启动uniapp项目教程 实现底部导航栏package.json中配置导航栏详细配置内容 前置准备工作 安装HBuilder-X 详细步骤可看上文》》 新建uniapp项目教程 详细步骤可看上文》》 使用HBuilder-X启动uniapp项…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...