Linux按键输入实验-按键功能完善
一. 简介
前面一篇文章实现了 按键的字符设备驱动代码框架,文章地址如下:
Linux按键输入实验-按键的字符设备驱动代码框架-CSDN博客
本文在 字符设备驱动框架实现的基础上,加入按键GPIO的初始化功能。
二. Linux按键输入实验-按键的GPIO初始化
1. 驱动代码完善
这里在前面按键的字符设备驱动代码框架的基础上,添加按键的GPIO初始化代码。
打开 11_key工程代码,key.c文件添加 GPIO初始化代码后如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>#define KEY_CNT 1
#define KEY_NAME "key"
#define INVALID_VALUE 0x00 //按键未按下值
#define VALID_VALUE 0x01 //按键按下值 static int key_open(struct inode *inode, struct file *filp);
ssize_t key_read(struct file * filp, char __user * buf, size_t count, loff_t * ppos);
int key_close(struct inode * inode, struct file * filp);//按键的设备结构体
struct key_dev{dev_t devid; //主设备号+次设备号int major; //主设备号int minor; //次设备号struct cdev key_cdev;struct class* key_class;struct device* device;struct device_node * dev_node;//设备节点int gpio_number;//gpio编号atomic_t key_value; //按键值//这里使用原子变量作为按键值类型
};struct key_dev key;static const struct file_operations key_fops = {.open = key_open,.owner = THIS_MODULE,.read = key_read,.release = key_close,
};/* 打开设备函数*/
static int key_open(struct inode *inode, struct file *filp)
{filp->private_data = &key;return 0;
}/* 从设备中读取数据函数*/
ssize_t key_read(struct file * filp, char __user * buf, size_t count, loff_t * ppos)
{int ret = 0, value = 0;struct key_dev* dev = filp->private_data;if(0 == gpio_get_value(dev->gpio_number)) //按键被按下{while(!gpio_get_value(dev->gpio_number));atomic_set(&dev->key_value, VALID_VALUE);} else //按键未按下{atomic_set(&dev->key_value, INVALID_VALUE);}value = atomic_read(&dev->key_value);ret = copy_to_user(buf, &value, sizeof(value));if(ret < 0){printk("kernel send to app for data failed!\n");return -1;}return 0;
}/* 关闭设备函数 */
int key_close(struct inode * inode, struct file * filp)
{return 0;
}/*按键的GPIO初始化函数*/
static int key_gpio_init(struct key_dev* dev)
{int ret = 0;/*1. 获取按键的设备节点*/dev->dev_node = of_find_node_by_path("/key");if(NULL == dev->dev_node){printk("find device node failed!\n");ret = -EINVAL;goto find_devnode;}/*2. 获取GPIO编号 */dev->gpio_number = of_get_named_gpio(dev->dev_node, "key-gpio", 0);if((dev->gpio_number) < 0){printk("get device number failed!\n");ret = -EINVAL;goto get_dev_number;}/*3.请求IO */ret = gpio_request(dev->gpio_number, "key");if(ret < 0){printk("gpio_request failed!\n");goto gpio_request;}/*4. 设置GPIO为输入功能*/ret = gpio_direction_input(dev->gpio_number);if(ret < 0){printk("set input io\n");goto set_input_io;}return 0;set_input_io:gpio_free(dev->gpio_number);
gpio_request:
get_dev_number:
find_devnode:return ret;
}/*模块入口函数*/
static int __init key_init(void)
{ int ret = 0;key.major = 0;//按键值初始化atomic_set(&key.key_value, INVALID_VALUE);/*1. 申请设备号*/if(key.major) //如果给出主设备号,则注册设备号{key.devid = MKDEV(key.major, 0);ret = register_chrdev_region(key.devid, KEY_CNT, KEY_NAME); }else //否则申请设备号{ret = alloc_chrdev_region(&key.devid, 0, KEY_CNT, KEY_NAME);key.major = MAJOR(key.devid);key.minor = MINOR(key.devid);}printk("major: %d minor: %d\n", key.major,key.minor);if(ret < 0){printk("devid apply failed!\n");goto devid_failed;}/*2. 设备初始化,添加设备*/key.key_cdev.owner = THIS_MODULE;cdev_init(&key.key_cdev, &key_fops);ret = cdev_add(&key.key_cdev, key.devid, KEY_CNT);if(ret < 0){printk("cdev_add failed!\n");goto cdev_init_failed;}/*3. 自动创建设备节点*/key.key_class = class_create(THIS_MODULE, KEY_NAME);if (IS_ERR(key.key_class)) {printk(KERN_ERR "class_create failed!\n");ret = PTR_ERR(key.key_class);goto class_create_failed;}key.device = device_create(key.key_class, NULL, key.devid, NULL, KEY_NAME);if (IS_ERR(key.device)) {printk(KERN_ERR "class_create failed!\n");ret = PTR_ERR(key.device);goto device_create_failed;}/*4. 按键的GPIO初始化*/key_gpio_init(&key);return 0;device_create_failed:class_destroy(key.key_class);
class_create_failed: cdev_del(&key.key_cdev);
cdev_init_failed:unregister_chrdev_region(key.devid, KEY_CNT);
devid_failed:return ret;
} /*模块出口函数*/
static void __exit key_exit(void)
{/*1. 释放设备编号 */gpio_free(key.gpio_number);/*2. 删除设备*/cdev_del(&key.key_cdev);/*3. 注销设备号 */unregister_chrdev_region(key.devid, KEY_CNT);/*4. 摧毁设备/摧毁类*/device_destroy(key.key_class, key.devid);class_destroy(key.key_class);
}/*模块入口与出口*/
module_init(key_init);
module_exit(key_exit);
MODULE_LICENSE("GPL"); //驱动License
MODULE_AUTHOR("WeiWuXian"); //作者
2. 编译驱动
对上面驱动代码进行编译:
wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/11_key$ make
make -C /home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/wangtian/zhengdian_Linux/Linux_Drivers/11_key modules
make[1]: 进入目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”CC [M] /home/wangtian/zhengdian_Linux/Linux_Drivers/11_key/key.oBuilding modules, stage 2.MODPOST 1 modulesCC /home/wangtian/zhengdian_Linux/Linux_Drivers/11_key/key.mod.oLD [M] /home/wangtian/zhengdian_Linux/Linux_Drivers/11_key/key.ko
make[1]: 离开目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”
wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/11_key$
可以看出,驱动模块可以正常编译。
三. 编写测试应用程序
按键驱动程序的测试,需要用到应用程序,这里编写测试(应用)程序。可以参考前面实验中的测试程序 led_app.c的实现,这里创建 key_app.c文件。
key.app.c文件代码完成后如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>#define INVALID_VALUE 0x00 //按键未按下值
#define VALID_VALUE 0x01 //按键按下值 /*
*测试按键是否按下
* 运行命令: ./key_app /dev/key
*/
int main(int argc, char* argv[])
{int fd = 0;char * device_name = NULL;int key_value = 0;if(argc != 2){printf("main's param number error!\n");return -1;}device_name = argv[1];fd = open(device_name, O_RDWR);if(fd < 0){printf("open led device failed!\n");return -1;}while(1){read(fd, &key_value, sizeof(key_value));if(VALID_VALUE == key_value) //按键被按下{printf("Key0 Press: key_value: %d\n", key_value);}}close(fd);return 0;
}
编译测试程序:
ubuntu进入 11_key工程目录下,对测试程序进行编译:
wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/11_key$ arm-linux-gnueabihf-gcc key_app.c -o key_app
测试程序也可以编译通过。接下来就是对驱动模块进行测试,测试按键功能是否可用。
相关文章:
Linux按键输入实验-按键功能完善
一. 简介 前面一篇文章实现了 按键的字符设备驱动代码框架,文章地址如下: Linux按键输入实验-按键的字符设备驱动代码框架-CSDN博客 本文在 字符设备驱动框架实现的基础上,加入按键GPIO的初始化功能。 二. Linux按键输入实验-按键的GPIO…...
二分查找讲解
关于我为什么要写单独开一篇文章写二分,实际上那么多困难的算法,比如线段树,并查集等等都没有难倒我,我最近却被二分难倒了,而且是两次,两次在赛场上做不出来二分的应用题,于是我决定写一篇二分查找的算法总结.刚接触算法的时候本来是要写一篇的,但后面因为各种原因搁置了,现在…...
跨区域复制建筑UI输入框脚本迷你世界
--复制区域文件 --设置坐标起点,终点 --创建区域 --获取坐标id,data --星空露珠工作室制作 local pos1{x-16,y7,z28} local pos2{x28,y44,z-9} local block{num0} local str{} local str0{} local num0 local count0 local ui6 --几个输入框 local romath.random(…...
取消退出流程控制方法
在自动化设备动作流程中,人为任意想取消当前动作,常见方法是使用全局变量,实时检测变量决定退出。这里介绍一个System.Threading空间下的 CancellationTokenSource类,他可以设置超时,设置信息等封装 基本使用超时和手…...
力扣-跳跃游戏
问题 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 解答 class Solu…...
李沐动手学习深度学习——3.2练习
以下是个人理解,希望进行讨论求解。 练习 1. 如果我们将权重初始化为零,会发生什么。算法仍然有效吗? 根据SGD算法公式如上,第一次迭代的值可知w只与b相关,而对于b的迭代更新,只是与b的初始值相关&#x…...
代码随想录Day20 | Leetcode77 组合
题目 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。你可以按 任何顺序 返回答案。示例 1: 输入:n 4, k 2 输出: [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ]示例 2: 输入:n 1, k 1 …...
Android Duplicate class 排除重复类
一、起因: 在迭代开发的时候,发现2个ijk很多类重复。但又2个库实现的功能是不一样,目前不能合并。但又想保留2个功能。需要排除其中一个库。 二、报错如何下图: 三、解决方法: 3.1 在terminal 也就是命令行处输入 …...
【Kubernetes】服务(Service)是什么?有什么用?有哪些类型?
系列文章目录 K8s中的Namespace是什么? Kubernetes 集群的组件介绍 Kubernetes 对象是什么? Pod——k8s中最重要的对象之一 Kubernetes 和 Docker 之间有什么区别? 部署安装 K8s 为什么要关闭 swap 分区? k8s中容器之间、pod之间…...
【前端素材】推荐优质后台管理系统DAdmin平台模板(附源码)
一、需求分析 1、系统定义 后台管理系统是一种用于管理网站、应用程序或系统的管理界面,通常由管理员和工作人员使用。它提供了访问和控制网站或应用程序后台功能的工具和界面,使其能够管理用户、内容、数据和其他各种功能。 2、功能需求 后台管理系…...
Redis高级特性详解:事务处理、发布订阅、持久化和集群
Redis(Remote Dictionary Server)是一个开源的基于内存的数据结构存储系统,被广泛应用于缓存、队列、计数器等场景中。除了基本的键值存储功能外,Redis还提供了许多高级特性,包括事务处理、发布订阅、持久化和集群。在…...
nwjs做自动化测试
分别是2个常用的自动化测试化框架 GitHub - nwutils/nw-selenium-javascript-example: An example of end-to-end testing with Selenium for NW.js apps via JavaScript GitHub - nwutils/nw-puppeteer-example: An example of using NW.js via Puppeteer. 看习惯使用哪个&…...
【前端素材】推荐优质在线特殊品牌商城电商网页eStore平台模板(附源码)
一、需求分析 1、系统定义 在线特殊品牌商城是指一个通过互联网提供特定品牌或特殊类型商品购买服务的电子商务平台。这类商城专注于某个特定品牌、设计风格或商品类型,为顾客提供独特、专业的购物体验。 2、功能需求 在线特殊品牌商城是指一个通过互联网提供特…...
Redis之一: 简介及环境安装搭建
什么是NoSQL? NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。 NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据…...
关于电脑一天24小时多少度电电脑的一天用电量计算
随着这几年物价的上涨,一些地区的电价越来越高,而我们经常需要使用电脑,那么一台电脑一天24小时用多少度电呢? 如何计算电脑一天的用电量? 让我们跟随小编来了解更多吧。 1、功耗、主机箱功耗 现在的计算机中…...
Unity3D 物理引擎的基本配置详解
前言 在Unity3D中,物理引擎主要由两部分组成:碰撞检测和物理模拟。在本文中,我们将详细介绍Unity3D物理引擎的基本配置,并给出相应的技术详解和代码实现。 对惹,这里有一个游戏开发交流小组,希望大家可以…...
CSS:弹性盒子Flexible Box布局
CSS:Flexible Box弹性盒子布局 一、flex布局原理 flex是flexible Box的缩写,意为 ”弹性布局“,用来为盒状模型提供最大的灵活性,任何一个容器都可以指定为flex布局。 当我们的父盒子设置为flex布局之后,子元素的 float 、clear 和 vert…...
java常用环境docker安装
配置目录 rocketmqredismysql不配置binlog配置binlog Nacoszookeeper 本文为精简安装,部分不带容器卷映射,仅供以学习使用。 rocketmq nameservice sudo docker run -d \ --privilegedtrue \ --name rmqnamesrv \ -p 9876:9876 \ -e "MAX_HEAP_SI…...
Code-Audit(代码审计)习题记录6-7
介绍: 自己懒得搭建靶场了,靶场地址是 GitHub - CHYbeta/Code-Audit-Challenges: Code-Audit-Challenges为了方便在公网练习,可以随地访问,本文所有的题目均来源于网站HSCSEC-Code Audit 6、习题6 题目内容如下: 源代…...
go 的使用总结
go的内存逃逸? go语言在编辑阶段通过逃逸分析把分配在栈上变量 分配到堆上去。 栈内存: 一段连续的内存,便于高效运行指令过程中的临时变量存储。 堆内存: 主要由垃圾回收器 回收没有被引用的指针。 逃逸分析:栈内…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
