Linux按键驱动测试方式

 更新时间:2025年05月15日 09:56:12   作者:忧虑的乌龟蛋  
这篇文章主要介绍了Linux按键驱动测试方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一、设备节点添加

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

如下:

//创建按键输入的pinctrl
		pinctrl_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;
}

四、测试

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Centos6.9安装vsftpd并配置多用户的方法

    Centos6.9安装vsftpd并配置多用户的方法

    本篇文章主要介绍了Centos6.9安装vsftpd并配置多用户的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Apache配置文件中的deny与allow小结

    Apache配置文件中的deny与allow小结

    这篇文章主要介绍了Apache配置文件中的deny与allow小结,本文着重讲解了deny和allow的执行顺序问题,需要的朋友可以参考下
    2015-01-01
  • Apache 安装和使用文档

    Apache 安装和使用文档

    Apache安装和使用文档
    2009-11-11
  • Linux系统中安装Git全过程

    Linux系统中安装Git全过程

    文章介绍了在Linux系统中安装Git的两种方法:使用包管理器安装和从源代码编译安装,包管理器安装简单快捷,但可能无法安装特定版本的Git;从源代码编译安装可以安装特定版本并进行自定义配置,但需要手动编译,两种方法各有优缺点,具体选择取决于用户需求
    2025-03-03
  • linux下终端分屏使用的两种方法(screen和tmux)

    linux下终端分屏使用的两种方法(screen和tmux)

    这篇文章主要给大家介绍了关于在linux下终端分屏使用的两种方法,分别是利用screen和tmux,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-06-06
  • Linux下Apache服务的部署和配置

    Linux下Apache服务的部署和配置

    这篇文章介绍了Linux下Apache服务的部署和配置,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12
  • CentOS8下的root密码快速修改方法

    CentOS8下的root密码快速修改方法

    这篇文章主要介绍了CentOS8版本的root密码快速修改方法,本文图文并茂通过实例讲解的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • linux之普通用户与root用户之间切换方法

    linux之普通用户与root用户之间切换方法

    下面小编就为大家带来一篇linux之普通用户与root用户之间切换方法。小编觉得挺不错的。现在就分享给大家。也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • LINUX安全设置之关于GRUB加密图文教程全解

    LINUX安全设置之关于GRUB加密图文教程全解

    关于LINUX的启动装载程序GRUB加密,算是一件很平常的工作。但是今天我在网上查这个东西,发现好多人都写的很简单,而且方法都比较过时。所以,在此我更新下GRUB加密。和大家分享下。
    2010-03-03
  • 深入浅析Linux轻量级自动运维工具-Ansible

    深入浅析Linux轻量级自动运维工具-Ansible

    这篇文章主要介绍了Linux轻量级自动运维工具-Ansible的相关知识,需要的朋友可以参考下
    2017-09-09

最新评论