Linux按键驱动测试

文章目录

一、设备节点添加

二、创建驱动文件代码

2.1 核心数据结构

2.2 按键值定义

2.3 关键函数实现

三、创建测试文件

四、测试


一、设备节点添加

        首先在设备树文件中添加pinctrl以及在根目录下添加设备节点。如下:

//创建按键输入的pinctrlpinctrl_key: keygrp {fsl,pins = <MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080 /* KEY0 */>;}; 
//创建按键节点key {#address-cells = <1>;#size-cells = <1>;compatible = "atkalpha-key";pinctrl-names = "default";pinctrl-0 = <&pinctrl_key>;key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>; /* KEY0 */status = "okay";};
};

二、创建驱动文件代码

2.1 核心数据结构

定义结构体,其中包含按键驱动所需的信息,使用atomic_t类型保证按键值的原子操作。

struct key_dev {dev_t devid;               /* 设备号 */struct cdev cdev;          /* cdev结构体 */struct class *class;       /* 类 */struct device *device;     /* 设备 */int major;                 /* 主设备号 */int minor;                 /* 次设备号 */struct device_node *nd;    /* 设备树节点 */int key_gpio;              /* 按键GPIO编号 */atomic_t keyvalue;         /* 按键值 */
};

2.2 按键值定义

驱动中定义了两个按键状态:按下(1)和未按下/无效(0)。

#define KEY0VALUE       1      /* 按键值 */
#define INVAKEY         0      /* 无效的按键值 */

2.3 关键函数实现

首先是GPIO初始化:从设备树获取按键GPIO信息,并配置为输入

static int keyio_init(void)
{keydev.nd = of_find_node_by_path("/key");if (keydev.nd == NULL) {return -EINVAL;}keydev.key_gpio = of_get_named_gpio(keydev.nd, "key-gpio", 0);if (keydev.key_gpio < 0) {printk("can't get key0\r\n");return -EINVAL;}printk("key_gpio=%d\r\n", keydev.key_gpio);/* 初始化key所使用的IO */gpio_request(keydev.key_gpio, "key0");   /* 请求IO */gpio_direction_input(keydev.key_gpio);   /* 设置为输入 */return 0;
}

 按键读取:驱动会阻塞等待按键释放后才返回,进而实现了一次完整按键周期的检测。

static ssize_t key_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{int ret = 0;int value;struct key_dev *dev = filp->private_data;if (gpio_get_value(dev->key_gpio) == 0) {        /* key0按下 */while(!gpio_get_value(dev->key_gpio));       /* 等待按键释放 */atomic_set(&dev->keyvalue, KEY0VALUE);    } else {    atomic_set(&dev->keyvalue, INVAKEY);         /* 无效的按键值 */}value = atomic_read(&dev->keyvalue);ret = copy_to_user(buf, &value, sizeof(value));return ret;
}

三、创建测试文件

        在测试文件中,通过对字符设备文件(/dev/key)进行标准文件操作实现与内核驱动层的交互。程序结构包括四个关键函数:信号处理函数sig_handler()、资源清理函数cleanup_resources()、帮助显示函数show_usage()及主函数main()。在主函数中,程序首先检查命令行参数格式,注册SIGINT信号处理确保可通过Ctrl+C优雅退出,然后打开设备文件获取文件描述符fd,随后进入核心监测循环,通过read()系统调用读取按键状态并使用前后状态比较算法(prev_keyvalue与keyvalue对比)检测按键事件边缘变化,实时输出中文提示信息反馈按键状态。

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include "signal.h"/* 定义按键值 */
#define KEY0VALUE	1
#define INVAKEY		0/* 全局变量 */
static int fd = -1;        /* 文件描述符 */
static int running = 1;    /* 程序运行标志 *//** @description		: 信号处理函数* @param - signum 	: 信号编号* @return 			: 无*/
void sig_handler(int signum)
{if (signum == SIGINT) {printf("\n程序接收到中断信号,正在退出...\n");running = 0;}
}/** @description		: 释放资源* @param - filename: 设备文件名* @return 			: 无*/
void cleanup_resources(const char *filename)
{if (fd >= 0) {if (close(fd) < 0) {printf("文件 %s 关闭失败!\n", filename);} else {printf("已关闭设备文件 %s\n", filename);}}
}/** @description		: 显示使用帮助* @param - name 	: 程序名* @return 			: 无*/
void show_usage(const char *name)
{printf("使用方法: %s <设备文件>\n", name);printf("示例: %s /dev/key\n", name);
}/** @description		: main主程序* @param - argc 	: argv数组元素个数* @param - argv 	: 具体参数* @return 			: 0 成功;其他 失败*/
int main(int argc, char *argv[])
{char *filename;int keyvalue;int prev_keyvalue = INVAKEY;/* 参数检查 */if (argc != 2) {printf("参数错误!\n");show_usage(argv[0]);return -1;}filename = argv[1];/* 注册信号处理函数,捕获Ctrl+C */signal(SIGINT, sig_handler);/* 打开按键设备 */fd = open(filename, O_RDWR);if (fd < 0) {printf("无法打开设备文件 %s!\n", filename);return -1;}printf("按键测试程序已启动\n");printf("按下按键进行测试,按 Ctrl+C 退出程序\n");/* 循环读取按键值数据 */while (running) {if (read(fd, &keyvalue, sizeof(keyvalue)) < 0) {printf("读取按键数据失败\n");break;}/* 按键状态变化检测 */if (keyvalue == KEY0VALUE && prev_keyvalue != KEY0VALUE) {printf("按键被按下,键值 = %d\n", keyvalue);} else if (keyvalue == INVAKEY && prev_keyvalue == KEY0VALUE) {printf("按键已释放\n");}prev_keyvalue = keyvalue;usleep(50000);  /* 短暂延时,降低CPU占用 */}/* 清理资源 */cleanup_resources(filename);printf("程序已退出\n");return 0;
}

四、测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/80803.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5000元可以运行32B大模型的笔记本

5000元可以运行32B 大模型的笔记本 荣耀笔记本 X14 Plus 锐龙版 R7-8845HS -32G -1T 模型名称 模型大小 tokens/s qwq-32b-q4 19GB 2.4 Qwen2.5-Coder-14B- Q8 16GB 4 DeepSeek-R1-Distill-Qwen-7B-Q8 8GB 8.1 DeepSeek-R1-Distill-Llama-8B-Q4 5GB 11.7

arm设备树基础知识

文章目录 前言dts片段通用属性介绍地址大小中断phandlecompatible mmc节点介绍 前言 arm开发&#xff0c;早晚要了解设备树 dts片段 interrupt-parent <0x8005>; model "linux,dummy-virt"; #size-cells <0x02>; #address-cells <0x02>; co…

【C++ 核心知识点面试攻略:从基础到实战(上位机开发视角)】

一、命名空间&#xff08;Namespace&#xff09;相关问题 问题1&#xff1a;C引入命名空间的核心目的是什么&#xff1f;如何通过命名空间解决命名冲突&#xff1f; 答案&#xff1a; C引入命名空间的核心目的是 避免全局作用域中的命名冲突&#xff0c;通过将变量、函数、类…

线性代数与数据学习

The Functions of Deep Learning (essay from SIAM News, December 2018) Deep Learning and Neural Nets

phpstorm用php连接数据库报错

项目场景&#xff1a; phpstorm用php连接数据库 问题描述 用php使用mysql_connect 的时候报错了&#xff0c;没有这个函数 原因分析&#xff1a; php解释器问题&#xff0c;后来查资料得知mysql_connct只适用于php5.5以下解释器。一开始用的7&#xff0c;改成5.3以后还是报…

51c大模型~合集122

我自己的原文哦~ https://blog.51cto.com/whaosoft/13877107 #PHYBench 北大物院200人合作&#xff0c;金牌得主超50人&#xff01;PHYBench&#xff1a;大模型究竟能不能真的懂物理&#xff1f; 本项目由北京大学物理学院朱华星老师、曹庆宏副院长统筹指导。基准设计、…

单片机 + 图像处理芯片 + TFT彩屏 触摸滑动条控件

触摸滑动条控件使用说明 一、项目概述 本项目基于单片机和RA8889/RA6809图形处理芯片的TFT触摸屏滑动条控件。该控件支持水平和垂直滑动条&#xff0c;可自定义外观和行为&#xff0c;并支持回调函数进行值变化通知。 硬件平台&#xff1a;51/ARM均可(测试时使用STC8H8K64U单…

linux离线安装zsh

下载zsh 下载仓库后解压 下载地址&#xff1a;https://github.com/zsh-users/zsh 离线安装 安装方法见INSTALL文件 ./configure --prefix[/usr/local] make make install

机器学习中的数据转换:关键步骤与最佳实践

机器学习中的数据转换&#xff1a;关键步骤与最佳实践 摘要 &#xff1a;在机器学习领域&#xff0c;数据是模型的核心&#xff0c;而数据的转换是构建高效、准确模型的关键步骤之一。本文深入探讨了机器学习中数据转换的重要性、常见的数据类型及其转换方法&#xff0c;以及在…

TDR阻抗会爬坡? 别担心,不是你的错,你只是不够了解TDR!

在背板系统或任何长走线设计里&#xff0c;你大概都碰过这画面&#xff1a; TDR 曲线一开始乖乖在 92 Ω&#xff0c;但越往末端、阻抗越爬越高&#xff0c;来到最高 97 Ω&#xff0c;心里瞬间凉半截 &#x1f612; &#xff0c;「难不成... 板厂又翻车了吗&#xff1f;」 然…

在另外一台可以科学下载的电脑用ollama下载模型后,怎么导入到另外一台服务器的ollama使用

环境&#xff1a; Win10专业版 Ubuntu20.04 问题描述&#xff1a; 在另外一台可以科学下载的电脑用ollama下载模型后&#xff0c;怎么导入到另外一台服务器的ollama使用&#xff0c;原电脑win10上的ollama下载的模型,复制到ubuntu20.04的ollama上推理 解决方案&#xff1a;…

Ethan独立开发产品日报 | 2025-04-27

1. CreateWise AI 旨在提升你工作效率的AI播客编辑器 人工智能播客编辑器&#xff0c;让你的播客制作速度提升10倍&#xff01;它可以自动去除口头语和沉默&#xff0c;生成节目笔记和精彩片段&#xff0c;还能一键制作适合社交媒体分享的短视频——所有这些功能都只需一次点…

解决 shadui组件库Popover 点击后会消失

react用了shadui组件库 <Popover><PopoverTrigger><div className"text-operation-item" onClick{props.callback}><img src{props.imgSrc} width{20} height{20} /></div></PopoverTrigger><PopoverContent className"…

SVC电气设备作用

SVC&#xff08;Static Var Compensator&#xff0c;静止无功补偿器&#xff09;是一种基于电力电子技术的动态无功补偿装置&#xff0c;属于灵活交流输电系统&#xff08;FACTS&#xff09;的核心设备之一。它通过快速调节电网中的无功功率&#xff0c;改善电能质量、稳定系统…

黑马点评商户查询缓存--缓存更新策略

ShopTypeServiceImpl类 代码 package com.hmdp.service.impl;import cn.hutool.json.JSONUtil; import com.hmdp.dto.Result; import com.hmdp.entity.ShopType; import com.hmdp.mapper.ShopTypeMapper; import com.hmdp.service.IShopTypeService; import com.baomidou.myba…

C 语言函数指针与指针函数详解

一、引言 在 C 语言的编程世界中&#xff0c;函数指针和指针函数是两个既强大又容易混淆的概念。它们为 C 语言带来了更高的灵活性和可扩展性&#xff0c;广泛应用于回调函数、动态链接库、状态机等多种场景。深入理解和掌握函数指针与指针函数&#xff0c;对于提升 C 语言编程…

HTML5 新特性详解:语义化标签、表单与音视频嵌入

前言 HTML5作为当前Web开发的核心技术&#xff0c;为开发者提供了更强大、更语义化的工具集。本文将深入探讨HTML5的三大核心特性&#xff1a;语义化标签、增强的表单功能以及原生的音视频支持&#xff0c;帮助开发者构建更现代化、更易维护的网页应用。 一、HTML5语义化标签…

利用HandlerMethodArgumentResolver和注解解析封装用户信息和Http参数

获取用户身份信息详情注解 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** 获取用户身份信息详情注解*/ Retention(RetentionPolicy.RUNTIME) Tar…

OpenCV 图形API(52)颜色空间转换-----将 NV12 格式的图像数据转换为 RGB 格式的图像

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 NV12 (YUV420p) 色彩空间转换为 RGB。该函数将输入图像从 NV12 色彩空间转换到 RGB。Y、U 和 V 通道值的常规范围是 0 到 255。 输出图…

哈工大李治军《操作系统》进程同步与信号量笔记

1.什么是信号量&#xff1f; 定义&#xff1a;记录一些信息&#xff08;即量&#xff09;&#xff0c;并根据这个信息决定睡眠还是唤醒&#xff08;即信号&#xff09;。睡眠和唤醒只是一个信号&#xff08;相当于0和1&#xff09;。 2.问题&#xff1a;一种资源的数量是8&am…