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

嵌入式Linux实战:用wait_event和wake_up实现按键驱动(附完整代码)

嵌入式Linux按键驱动开发深入理解wait_event与wake_up机制在嵌入式Linux开发中设备驱动程序的编写是连接硬件与操作系统的关键环节。按键驱动作为最常见的外设驱动之一其实现方式直接影响系统响应速度和资源利用率。本文将深入探讨如何利用Linux内核提供的wait_event和wake_up机制构建一个高效、低功耗的按键驱动程序。1. 等待队列机制的核心原理Linux内核的等待队列wait queue是一种重要的任务调度机制它允许进程在特定条件不满足时主动放弃CPU直到条件满足后被唤醒。这种机制在设备驱动开发中尤为关键特别是对于需要响应硬件中断的驱动场景。1.1 等待队列的工作流程等待队列的基本工作流程可以分为三个关键阶段初始化阶段创建并初始化等待队列头wait queue head休眠阶段进程检查条件不满足时进入休眠状态唤醒阶段中断处理函数或其他上下文修改条件并唤醒等待进程// 典型的内核等待队列使用模式 static DECLARE_WAIT_QUEUE_HEAD(my_wait_queue); static bool condition false; // 在驱动读函数中 wait_event_interruptible(my_wait_queue, condition); // 在中断处理函数中 condition true; wake_up_interruptible(my_wait_queue);1.2 关键数据结构解析Linux内核中与等待队列相关的主要数据结构包括wait_queue_head_t等待队列头结构用于管理等待的进程列表wait_queue_entry等待队列条目代表一个等待的进程task_struct进程描述符包含进程状态等信息等待队列操作的核心函数对比函数名称可中断性超时支持唤醒条件wait_event不可中断无condition为真wait_event_interruptible可中断无condition为真或被信号中断wait_event_timeout不可中断支持condition为真或超时wait_event_interruptible_timeout可中断支持condition为真、超时或被信号中断2. 按键驱动的完整实现2.1 硬件抽象层设计在开始编码前我们需要先设计好硬件抽象层这将使驱动更容易移植到不同平台struct gpio_key_config { int gpio_num; // GPIO编号 const char *name; // 按键名称 struct gpio_desc *desc; // GPIO描述符 int irq_num; // 中断号 bool active_low; // 是否低电平有效 };2.2 驱动初始化流程完整的驱动初始化应包括以下步骤获取设备树或平台数据申请GPIO资源配置GPIO方向申请中断初始化等待队列创建设备节点static int __init gpio_key_init(void) { // 1. 初始化等待队列 init_waitqueue_head(gpio_key_wait); // 2. 申请GPIO key_desc gpiod_get(pdev-dev, key, GPIOD_IN); if (IS_ERR(key_desc)) { dev_err(pdev-dev, Failed to get GPIO descriptor\n); return PTR_ERR(key_desc); } // 3. 申请中断 irq gpiod_to_irq(key_desc); ret request_irq(irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpio_key, NULL); if (ret) { dev_err(pdev-dev, Failed to request IRQ\n); goto err_free_gpio; } // 4. 创建设备节点 misc_register(gpio_key_dev); return 0; err_free_gpio: gpiod_put(key_desc); return ret; }2.3 中断处理与唤醒机制中断服务程序(ISR)是按键驱动的核心它负责检测按键状态变化并唤醒等待的进程static irqreturn_t gpio_key_isr(int irq, void *dev_id) { struct gpio_key_config *config dev_id; int val gpiod_get_value(config-desc); // 消抖处理 if (time_before(jiffies, last_jiffies DEBOUNCE_TIME)) return IRQ_HANDLED; last_jiffies jiffies; // 记录按键事件 key_event.gpio config-gpio_num; key_event.value val ^ config-active_low; key_event.timestamp ktime_get_ns(); // 设置条件并唤醒等待队列 atomic_set(key_pressed, 1); wake_up_interruptible(gpio_key_wait); return IRQ_HANDLED; }3. 用户空间接口设计3.1 驱动文件操作实现驱动需要提供标准的文件操作接口特别是read函数它将使用等待队列机制static ssize_t gpio_key_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { int ret; // 等待按键事件 ret wait_event_interruptible(gpio_key_wait, atomic_read(key_pressed)); if (ret) return ret; // 复制数据到用户空间 if (copy_to_user(buf, key_event, sizeof(key_event))) return -EFAULT; // 重置按键状态 atomic_set(key_pressed, 0); return sizeof(key_event); }3.2 高级IO控制接口除了基本的read操作我们还可以实现ioctl接口来提供更多控制功能#define GPIO_KEY_GET_DEBOUNCE _IOR(K, 0, int) #define GPIO_KEY_SET_DEBOUNCE _IOW(K, 1, int) static long gpio_key_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret 0; switch (cmd) { case GPIO_KEY_GET_DEBOUNCE: ret put_user(debounce_time, (int __user *)arg); break; case GPIO_KEY_SET_DEBOUNCE: ret get_user(debounce_time, (int __user *)arg); break; default: ret -ENOTTY; } return ret; }4. 性能优化与调试技巧4.1 按键消抖策略比较按键消抖是按键驱动中必须处理的问题以下是几种常见消抖方法的对比方法实现复杂度精确度CPU占用适用场景硬件RC滤波低中无简单应用定时器中断中高中通用场景工作队列延迟中高低低功耗设备内核定时器高高低精确控制4.2 调试技巧与常见问题在开发过程中可能会遇到以下典型问题及解决方案中断风暴问题症状系统响应变慢CPU占用率高原因按键抖动导致频繁中断解决增加硬件滤波或软件消抖唤醒失败问题症状进程一直阻塞在wait_event检查点确认condition在中断中被正确设置检查wake_up调用是否正确确认没有竞态条件性能优化建议对于高频按键场景考虑使用内核fasync机制避免在中断上下文中进行复杂操作使用原子操作保护共享数据// 使用原子变量优化condition检查 static atomic_t key_pressed ATOMIC_INIT(0); // 在read中 wait_event_interruptible(gpio_key_wait, atomic_read(key_pressed)); // 在中断中 atomic_set(key_pressed, 1); wake_up_interruptible(gpio_key_wait);在实际项目中我发现按键驱动的稳定性往往取决于消抖算法的选择和中断处理的优化。通过合理设置消抖时间和使用原子操作可以显著提高驱动的可靠性。

相关文章:

嵌入式Linux实战:用wait_event和wake_up实现按键驱动(附完整代码)

嵌入式Linux按键驱动开发:深入理解wait_event与wake_up机制 在嵌入式Linux开发中,设备驱动程序的编写是连接硬件与操作系统的关键环节。按键驱动作为最常见的外设驱动之一,其实现方式直接影响系统响应速度和资源利用率。本文将深入探讨如何利…...

Llama-3.2V-11B-cot参数详解:11B模型显存占用分析与INT4量化部署指南

Llama-3.2V-11B-cot参数详解:11B模型显存占用分析与INT4量化部署指南 1. 模型概述 Llama-3.2V-11B-cot 是一个支持系统性推理的视觉语言模型,基于LLaVA-CoT论文实现。这个模型结合了图像理解和逐步推理能力,能够对输入的视觉内容进行深度分…...

bug.n多显示器支持完全指南:跨屏工作流优化方案

bug.n多显示器支持完全指南:跨屏工作流优化方案 【免费下载链接】bug.n Tiling Window Manager for Windows 项目地址: https://gitcode.com/gh_mirrors/bu/bug.n bug.n 作为一款专为 Windows 设计的平铺窗口管理器(Tiling Window Manager&#x…...

马尔可夫预测实战:用Python模拟药店市场份额变化(附完整代码)

马尔可夫预测实战:用Python模拟药店市场份额变化(附完整代码) 在医药行业,准确预测市场份额变化是制定营销策略的关键。想象一下,你负责管理一家连锁药店,需要根据历史销售数据预测未来三个季度A、B、C三家…...

C++ WebServer内存管理最佳实践:Buffer类设计与资源释放

C WebServer内存管理最佳实践:Buffer类设计与资源释放 【免费下载链接】WebServer C Linux WebServer服务器 项目地址: https://gitcode.com/gh_mirrors/web/WebServer 在C Linux WebServer开发中,内存管理是保证服务器稳定性和性能的核心环节。本…...

SMOTE算法实战:从零手搓Python代码,实现自定义数量样本生成

1. 为什么需要SMOTE算法? 做机器学习项目时,经常会遇到类别不平衡的问题。比如在信用卡欺诈检测中,正常交易占99%,欺诈交易只有1%。这种数据直接扔给模型训练,结果往往不太理想 - 模型会倾向于预测多数类,因…...

MCP(Model Context Protocol)深度解析:让 AI Agent 真正走向标准化的“USB-C 接口“

摘要 Model Context Protocol(MCP)是 Anthropic 于 2024 年 11 月开源的 AI 工具调用标准协议,被誉为 AI 领域的"USB-C 接口"。它通过统一的 Host-Client-Server 分层架构与 JSON-RPC 2.0 消息格式,彻底解决了大语言模…...

actionlint 安全检查:快速检测脚本注入和硬编码凭据的完整指南

actionlint 安全检查:快速检测脚本注入和硬编码凭据的完整指南 【免费下载链接】actionlint :octocat: Static checker for GitHub Actions workflow files 项目地址: https://gitcode.com/gh_mirrors/ac/actionlint actionlint 是一款强大的 GitHub Actions…...

别再手动调参了!用sklearn的GridSearchCV搞定随机森林回归,附空气质量预测实战代码

告别低效调参!用GridSearchCV自动化优化随机森林回归模型 调参是机器学习项目中最耗时却又无法回避的环节。记得刚入行时,我曾连续三天手动调整随机森林的参数,每次运行模型后修改几个数值,再重新训练评估。这种"盲人摸象&qu…...

WuliArt Qwen-Image Turbo高清输出:1024×1024下可安全裁切至9:16/1:1/16:9多比例

WuliArt Qwen-Image Turbo高清输出:10241024下可安全裁切至9:16/1:1/16:9多比例 提示:本文所有生成图像均为10241024分辨率,可通过安全裁切适配多种比例需求 1. 项目简介 WuliArt Qwen-Image Turbo是一款专为个人GPU优化的高性能文生图系统。…...

Vue-H5-Template Mock数据方案:前端开发与后端接口并行

Vue-H5-Template Mock数据方案:前端开发与后端接口并行 【免费下载链接】vue-h5-template :tada:vue搭建移动端开发,基于vue-cli4.0webpack 4vant ui sass rem适配方案axios封装,构建手机端模板脚手架 项目地址: https://gitcode.com/gh_mirrors/vu/…...

告别轮询!用STM32F407的串口空闲中断+DMA实现高效数据收发(标准库实战)

STM32F407串口通信革命:基于空闲中断与DMA的高效数据帧处理实战 在嵌入式系统开发中,串口通信就像设备与外界对话的"嘴巴"和"耳朵"。传统方式下,这个对话过程常常让CPU忙得不可开交——每接收一个字节就要打断CPU一次&am…...

Qwen2.5-VL-7B-Instruct效果验证:手写体发票识别+金额数字校验+税务编码匹配

Qwen2.5-VL-7B-Instruct效果验证:手写体发票识别金额数字校验税务编码匹配 今天我们来实测一个非常实用的场景:用Qwen2.5-VL-7B-Instruct多模态大模型,来处理那些让人头疼的手写发票。 想象一下,财务同事每天要面对一堆手写单据…...

AI 时代,媒介宣发也该换种“玩法”了

如果你经常逛技术社区,可能已经发现一个趋势:现在聊 AI 落地,大家不再只盯着大模型参数,而是开始关心一个更实际的问题——这东西到底能帮我们解决什么具体业务场景的痛点。作为技术人,我最近正好接触到一个很有意思的…...

前端日志美化指南:ansi_up + Vue实现控制台风格日志展示

前端日志美化指南:ansi_up Vue实现控制台风格日志展示 在复杂的现代Web应用中,日志系统是开发者调试和监控的"眼睛"。然而,当我们将后端生成的彩色日志直接呈现在前端时,常常会遇到ANSI颜色代码显示为乱码的问题。这不…...

CAN总线开发必知:报文发送类型全解析(含Cycle/Event/CE/IfActive对比)

CAN总线开发实战:四种报文发送类型深度解析与应用指南 在汽车电子开发领域,CAN总线作为车载网络的骨干技术,其报文发送机制的设计直接影响着系统性能和可靠性。对于刚接触CAN总线开发的工程师而言,理解不同报文发送类型的特点和适…...

java中间件无法连接数据库

文章目录环境症状问题原因解决方案环境 系统平台:N/A 版本:4.5.8 症状 java中间件连接瀚高数据库报如下错误: 连接失败 您必须改变数据库设置 com.highgo.jdbc.util.PSQLException: SCRAM authentication is not supported by this drive…...

Excel批量生成序列号的3种高效方法,告别手动输入!

1. 为什么需要批量生成序列号? 在日常办公中,我们经常需要处理大量数据。比如制作员工工号、产品编号、订单流水号等,这些场景都需要生成连续的序列号。手动输入不仅效率低下,还容易出错。我曾经负责过一个项目,需要为…...

从光流到TOF:ArduPilot EKF3如何玩转室内定位?手把手教你配置非GPS导航源

室内无人机定位实战:ArduPilot EKF3融合光流与TOF的深度配置指南 当GPS信号被钢筋混凝土阻隔,如何让无人机在室内环境中保持精准定位?这不仅是技术挑战,更是工程实践的艺术。本文将带您深入ArduPilot的EKF3扩展卡尔曼滤波系统&…...

如何配置Bosun监控规则:10个实战技巧详解

如何配置Bosun监控规则:10个实战技巧详解 【免费下载链接】bosun Time Series Alerting Framework 项目地址: https://gitcode.com/gh_mirrors/bo/bosun Bosun作为一款强大的时间序列告警框架(Time Series Alerting Framework)&#x…...

git-open:如何在5分钟内掌握这个高效的Git仓库快速访问神器

git-open:如何在5分钟内掌握这个高效的Git仓库快速访问神器 【免费下载链接】git-open Type git open to open the GitHub page or website for a repository in your browser. 项目地址: https://gitcode.com/gh_mirrors/gi/git-open git-open是一款轻量级命…...

实现支持纳秒级精度的时间引擎(C++)

## 前言在游戏服务器开发中,定时器是一个核心组件,用于处理各种定时任务,如心跳检测、超时处理、定时刷新等。本文将介绍如何在 C 中实现一个支持纳秒级精度、在单独线程中运行的时间引擎。## 需求分析我们需要实现一个时间引擎,具…...

别再递归了!用C++手把手教你实现二叉排序树的非递归查找与插入(附完整代码)

从递归到迭代:C实现二叉排序树的高效操作指南 二叉排序树(Binary Search Tree, BST)作为数据结构课程中的经典内容,其递归实现往往让初学者感到直观易懂。但当面对大规模数据或系统资源受限的场景时,递归调用的栈开销可…...

Local AI MusicGen惊艳效果展示:AI生成赛博朋克风背景音乐作品集

Local AI MusicGen惊艳效果展示:AI生成赛博朋克风背景音乐作品集 1. 开启AI音乐创作新纪元 想象一下,你正在制作一个赛博朋克风格的短视频,需要一段充满未来感的背景音乐。传统方式可能需要花费数百元购买版权音乐,或者花几个小…...

【Kylin】V10虚拟机界面“捉迷藏”?手把手教你用命令行解锁VMware最佳分辨率

1. 当Kylin V10遇上VMware:分辨率引发的"捉迷藏"游戏 刚在VMware里装好Kylin V10,满心欢喜准备大展拳脚,结果发现桌面图标大得像马赛克,系统设置界面的保存按钮居然玩起了"捉迷藏"——这种场景我太熟悉了。去…...

RakNet多平台部署实战:Windows、Linux、Mac、iOS和Android全攻略

RakNet多平台部署实战:Windows、Linux、Mac、iOS和Android全攻略 【免费下载链接】RakNet RakNet is a cross platform, open source, C networking engine for game programmers. 项目地址: https://gitcode.com/gh_mirrors/ra/RakNet RakNet是一款跨平台、…...

基于LangChain的RAG与Agent智能体开发 - LangChain提示词模版

大家好,我是小锋老师,最近更新《2027版 基于LangChain的RAG与Agent智能体 开发视频教程》专辑,感谢大家支持。本课程主要介绍和讲解RAG,LangChain简介,接入通义千万大模型 ,Ollama简介以及安装和使用&…...

SAP物料主数据管理:如何优雅地扩展MAKTX字段而不影响系统稳定性?

SAP物料主数据管理:如何优雅地扩展MAKTX字段而不影响系统稳定性? 在大型企业ERP系统实施中,物料描述字段(MAKTX)的40字符限制常常成为业务部门的痛点。当需要包含规格参数、多语言描述或特殊标识时,这个看似简单的字段扩展需求背…...

Emojicode标准库s包完全指南:文件、字符串、线程等核心功能详解

Emojicode标准库s包完全指南:文件、字符串、线程等核心功能详解 【免费下载链接】emojicode 😀😜🔂 World’s only programming language that’s bursting with emojis 项目地址: https://gitcode.com/gh_mirrors/em/emojicode…...

Express TypeScript Boilerplate错误处理机制:从异常捕获到友好响应的完整指南

Express TypeScript Boilerplate错误处理机制:从异常捕获到友好响应的完整指南 【免费下载链接】express-typescript-boilerplate A delightful way to building a RESTful API with NodeJs & TypeScript by w3tecch 项目地址: https://gitcode.com/gh_mirror…...