欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > Linux按键驱动测试

Linux按键驱动测试

2025/4/30 2:18:41 来源:https://blog.csdn.net/weixin_63577471/article/details/147580451  浏览:    关键词: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;
}

四、测试

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词