当前位置: 首页 > news >正文

使用 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 通信时,有几个关键点需要注意:

  1. 正确初始化文件描述符集

每次调用 select 之前,需要重新初始化文件描述符集(fd_set),因为 select 调用会修改这个集合:

FD_ZERO(&rfds);
FD_SET(fd, &rfds);
  1. 设置超时值

在每次调用 select 之前,需要设置超时值(struct timeval)。同样,select 会修改这个结构体,因此每次调用前都需要重新设置:

struct timeval tv;
tv.tv_sec = timeout_us / 1000000;
tv.tv_usec = timeout_us % 1000000;
  1. 处理 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}
}
  1. 避免文件描述符泄漏

确保在程序结束或不再需要文件描述符时关闭它们,防止资源泄漏:

close(fd);
  1. 多线程环境下的文件描述符使用

如果在多线程环境下使用文件描述符,需要确保对文件描述符的操作是线程安全的。使用互斥锁(mutex)保护对文件描述符的操作,避免竞态条件。

  1. 检查文件描述符的有效性

在调用 select 之前检查文件描述符是否有效,确保文件描述符在整个生命周期中是有效的:

int check_fd_valid(int fd) {return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}
  1. 处理边界情况

处理 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&#xff08;Universal Asynchronous Receiver/Transmitter&#xff09;是一种用于异步串行通信的硬件协议&#xff0c;常用于计算机和外设之间的数据交换…...

干货 | 2024低空经济产业发展白皮书(免费下载)

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

打开nginx连接的php页面报错502

目录 问题描述&#xff1a; 原因&#xff1a; 1. 使用 Unix 域套接字&#xff08;Unix Socket&#xff09; 区别和优势&#xff1a; 2. 使用 TCP/IP 套接字 区别和优势&#xff1a; 如何选择 扩展&#xff1a;Rocky_Linux9.4安装PHP的步骤&#xff1a; 使用Remi存储库…...

Qt之文件操作(QFile、QFileInfo、QTemporaryFile)

文章目录 前言QFile如何使用 QFile QFileInfo如何使用 QFileInfo QTemporaryFile如何使用 QTemporaryFile QFile常用函数QFileInfo常用函数QTemporaryFile常用函数总结 前言 在开发 Qt 应用程序时&#xff0c;我们经常需要进行文件操作&#xff0c;如读取文件、写入文件、获取…...

Python爬虫初试

在Python中&#xff0c;我们可以使用一些强大的库来编写一个功能强大的爬虫&#xff0c; Python 首先安装必要的库&#xff08;如果尚未安装&#xff09; pip install requests beautifulsoup4 import requests from bs4 import BeautifulSoup import osdef download_images(…...

ARM-V9 RME(Realm Management Extension)系统架构之系统初始化流程

安全之安全(security)博客目录导读 目录 一、重置取消 二、应用处理单元&#xff08;PE&#xff09;初始启动 三、MSD初始化 四、GPT初始化 五、初始启动退出&#xff08;由所有应用PE执行&#xff09; 六、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 注释的语法&#xff1a; // 单行注释/*多行注释 *//**文档注释 */ 1.2 注释的特点&#xff1a; 注释不影响程序的执行&#xff0c;在Javac命令进行编译后会将注释去掉 1.3 注释的快捷键 二、字面量详解 2.1 字面量的概念&#xff1a; 计算机是用来处理…...

利用golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置

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

Python爬虫介绍

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

Linux 进程管理

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

【车载测试】CAN协议、CAN- FD协议和FlexRay协议 区别

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

对日期的处理

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

赵丽颖纯白茉莉绽放温柔之美

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

软考高级论文真题“论湖仓一体架构及其应用”

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

CentOS系统查看版本的各个命令

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

[保姆级教程]uniapp实现底部导航栏

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

STM32单片机技术优势与应用指南

1. STM32的崛起背景与技术优势2007年之前&#xff0c;8位单片机市场被8051架构主导&#xff0c;16位市场则有MSP430等产品。这些传统MCU在简单控制领域表现出色&#xff0c;但随着物联网时代的到来&#xff0c;其局限性逐渐显现&#xff1a;性能瓶颈&#xff1a;8位机的处理能力…...

从配准到生成:扩散模型如何革新医学图像跨模态转换

1. 医学图像跨模态转换的技术挑战 医学影像领域长期面临一个核心难题&#xff1a;如何在不同成像模态之间实现高精度转换。比如将核磁共振&#xff08;MRI&#xff09;的软组织图像转换为计算机断层扫描&#xff08;CT&#xff09;的骨骼结构图像&#xff0c;这种需求在放射治…...

如何通过哈氏训练提升孩子的学习能力以应对多动症表现和作业拖延症?

如何运用哈氏训练助力孩子克服多动症表现与作业拖延 哈氏训练是一种有效的应对策略&#xff0c;尤其对有多动症表现和作业拖延症的孩子。首先&#xff0c;这种训练方法可以帮助孩子建立稳定的日常作息&#xff0c;提高他们的注意力和自我控制能力。通过结构化的活动和渐进式的任…...

YOLO26涨点改进| ICCV 2025 | 独家创新首发、注意力改进篇| 引入CBSM通道增强与智能空间映射模块,含多种创新改进,助力图像融合、红外小目标检测、图像分割、图像分类高效涨点

一、本文介绍 🔥本文给大家介绍使用 CBSM通道增强与智能空间映射模块 改进YOLO26网络模型,作用在于对输入特征进行通道增强与空间映射,使浅层图像信息能够更好地适配深层语义特征,从而提升特征表达质量并减少特征不匹配问题。其优势体现在能够有效抑制背景噪声、强化关键…...

泛微Ecology数据库小白必看:三张表搞定待办、已办、办结查询(附完整SQL及字段解释)

泛微Ecology流程查询实战指南&#xff1a;从表结构到SQL优化的完整解析 引言 在日常办公自动化管理中&#xff0c;泛微Ecology系统作为国内主流的工作流平台&#xff0c;承载着企业大量业务流程的运转。但对于刚接触系统管理的技术人员来说&#xff0c;面对复杂的数据库表结构和…...

【openbmc8】mctp pldm

文章目录 1.mctp协议 1.1 mctp通用报文 1.2 mctp over i2c packet format 2.驱动分析 2.1 mctp pcie vdm 2.1 用户层操作代码流程 2.2 用户层操作测试 3.dbus适配 1.mctp协议 1.1 mctp通用报文 谁分配EID谁就是bus owner。mctp建立关联后都用EID(类似ip地址)通信:下图最后…...

Go语言中的正则表达式

Go语言中的正则表达式 1. 正则表达式的基本概念 正则表达式是一种用于匹配字符串中字符组合的模式。在Go语言中&#xff0c;正则表达式通过regexp包来实现。 2. 基本用法 2.1 编译正则表达式 package mainimport ("fmt""regexp" )func main() {// 编译正则…...

ai赋能开发:使用快马平台智能优化openclaw 101抓取控制算法

最近在优化一个机械臂抓取控制项目时&#xff0c;发现传统的手动调参和算法改进效率太低。正好尝试了InsCode(快马)平台的AI辅助开发功能&#xff0c;整个过程让我对智能化编程有了全新认识。下面分享用AI优化OpenClaw 101控制算法的完整经历&#xff1a; 原始问题分析 初始代码…...

内网环境下基于Verdaccio搭建企业级npm私服及自动化依赖包管理实践

1. 为什么企业需要搭建npm私有仓库 最近几年在前端工程化领域&#xff0c;npm已经成为不可或缺的依赖管理工具。但对于企业级开发团队来说&#xff0c;直接使用公共npm仓库会遇到几个棘手问题&#xff1a; 第一是网络隔离问题。很多金融、政务类项目开发环境都是完全离线的内网…...

用仓颉语言搞定编译原理实验:从正则表达式到DFA的保姆级实现(附完整代码)

用仓颉语言实现编译原理实验&#xff1a;从正则表达式到DFA的实战指南 第一次接触编译原理实验时&#xff0c;看着那些晦涩的算法描述和数学符号&#xff0c;我完全不知道如何下手。直到用仓颉语言完整实现了从正则表达式到NFA再到DFA的转换过程&#xff0c;才真正理解了这些概…...