按键驱动代码
时间: 2025-08-18 19:50:34 浏览: 2
编写按键驱动程序通常涉及到内核模块的开发,以及用户空间应用程序与硬件交互的部分。以下是一个基于Linux系统的按键驱动程序开发的示例,包括内核模块和用户空间的应用程序。
### 内核模块代码
内核模块负责与硬件直接交互,读取按键的状态。下面是一个简单的按键驱动程序示例,它注册了一个字符设备,并提供了打开和读取操作。
```c
// button_drv.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/gpio.h>
#define DEVICE_NAME "button_drv"
#define CLASS_NAME "button"
static int majorNumber;
static struct class* buttonClass = NULL;
static struct device* buttonDevice = NULL;
// 按键GPIO编号
#define BUTTON_GPIO 17
// 按键值
static char key_value = '0';
// 按键操作结构体
struct button_operations {
int (*init)(void);
int (*read)(char *key_val);
};
// 按键操作实例
static struct button_operations *p_button_opr;
// 按键初始化
static int button_init(void) {
if (!gpio_is_valid(BUTTON_GPIO)) {
printk(KERN_ALERT "Invalid GPIO %d\n", BUTTON_GPIO);
return -ENODEV;
}
if (gpio_request(BUTTON_GPIO, "sysfs") < 0) {
printk(KERN_ALERT "Failed to request GPIO %d\n", BUTTON_GPIO);
return -ENODEV;
}
gpio_direction_input(BUTTON_GPIO);
gpio_export(BUTTON_GPIO, false);
return 0;
}
// 按键读取
static int button_read(char *key_val) {
int val = gpio_get_value(BUTTON_GPIO);
*key_val = val ? '1' : '0';
return 0;
}
// 文件操作
static int dev_open(struct inode *inodep, struct file *filep) {
return 0;
}
static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset) {
char key_val;
p_button_opr->read(&key_val);
if (copy_to_user(buffer, &key_val, 1)) {
return -EFAULT;
}
return 1;
}
static struct file_operations fops = {
.open = dev_open,
.read = dev_read,
};
// 初始化驱动
static int __init button_drv_init(void) {
majorNumber = register_chrdev(0, DEVICE_NAME, &fops);
if (majorNumber < 0) {
printk(KERN_ALERT "Failed to register a major number\n");
return majorNumber;
}
buttonClass = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(buttonClass)) {
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to register device class\n");
return PTR_ERR(buttonClass);
}
buttonDevice = device_create(buttonClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
if (IS_ERR(buttonDevice)) {
class_destroy(buttonClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to create the device\n");
return PTR_ERR(buttonDevice);
}
p_button_opr = kmalloc(sizeof(struct button_operations), GFP_KERNEL);
if (!p_button_opr) {
device_destroy(buttonClass, MKDEV(majorNumber, 0));
class_destroy(buttonClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to allocate memory for button operations\n");
return -ENOMEM;
}
p_button_opr->init = button_init;
p_button_opr->read = button_read;
p_button_opr->init();
printk(KERN_INFO "Button driver has been loaded\n");
return 0;
}
// 清理驱动
static void __exit button_drv_exit(void) {
kfree(p_button_opr);
device_destroy(buttonClass, MKDEV(majorNumber, 0));
class_unregister(buttonClass);
class_destroy(buttonClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
gpio_unexport(BUTTON_GPIO);
gpio_free(BUTTON_GPIO);
printk(KERN_INFO "Button driver has been unloaded\n");
}
module_init(button_drv_init);
module_exit(button_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux driver for a button.");
```
### 用户空间应用程序代码
用户空间应用程序通过读取字符设备来获取按键状态。
```c
// button_app.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main() {
int fd;
char key_value;
fd = open("/dev/button_drv", O_RDONLY);
if (fd < 0) {
perror("Failed to open the device");
return -1;
}
while (1) {
if (read(fd, &key_value, 1) != 1) {
perror("Failed to read the device");
close(fd);
return -1;
}
printf("Key value: %c\n", key_value);
}
close(fd);
return 0;
}
```
### Makefile
为了编译这个驱动程序,你需要一个Makefile。
```makefile
obj-m += button_drv.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
```
### 安装和测试
1. 编译驱动程序:
```bash
make
```
2. 加载驱动程序到内核:
```bash
sudo insmod button_drv.ko
```
3. 创建设备节点(如果系统没有自动创建):
```bash
sudo mknod /dev/button_drv c $(cat /proc/devices | grep button_drv | awk '{print $1}') 0
```
4. 运行用户空间应用程序:
```bash
./button_app
```
5. 卸载驱动程序:
```bash
sudo rmmod button_drv
```
6. 清理编译文件:
```bash
make clean
```
以上代码和步骤提供了一个基本的框架,你可以根据具体的硬件需求进行扩展和修改。例如,如果你使用的是不同的GPIO引脚或者需要支持多个按键,你可能需要调整初始化和读取函数中的逻辑。此外,对于更复杂的硬件,可能还需要处理中断和去抖动等高级特性。
阅读全文
相关推荐















