嵌入式Linux应用开发-第十四章查询方式的按键驱动程序

嵌入式Linux应用开发-第十四章查询方式的按键驱动程序

  • 第十四章 查询方式的按键驱动程序_编写框架
    • 14.1 LED驱动回顾
    • 14.2 按键驱动编写思路
    • 14.3 编程:先写框架
      • 14.3.1 把按键的操作抽象出一个button_operations结构体
      • 14.3.2 驱动程序的上层:file_operations结构体
    • 14.4 测试
    • 14.5 课后怎业

第十四章 查询方式的按键驱动程序_编写框架

在这里插入图片描述

14.1 LED驱动回顾

对于 LED,APP调用 open函数导致驱动程序的 led_open函数被调用。在里面,把 GPIO配置为输出引脚。安装驱动程序后并不意味着会使用对应的硬件,而 APP要使用对应的硬件,必须先调用 open函数。所以建议在驱动程序的 open函数中去设置引脚。
APP继续调用 write函数传入数值,在驱动程序的 led_write函数根据该数值去设置 GPIO的数据寄存器,从而控制 GPIO的输出电平。
怎么操作寄存器?从芯片手册得到对应寄存器的物理地址,在驱动程序中使用 ioremap函数映射得到虚拟地址。驱动程序中使用虚拟地址去访问寄存器。
在这里插入图片描述

14.2 按键驱动编写思路

GPIO按键的原理图一般有如下 2种:
在这里插入图片描述

按键没被按下时,上图中左边的 GPIO电平为高,右边的 GPIO电平为低。 按键被按下后,上图中左边的 GPIO电平为低,右边的 GPIO电平为高。
编写按键驱动程序最简单的方法如下图所示:
在这里插入图片描述

回顾一下编写驱动程序的套路:
在这里插入图片描述

对于使用查询方式的按键驱动程序,我们只需要实现 button_open、button_read。

14.3 编程:先写框架

我们的目的写出一个容易扩展到各种芯片、各种板子的按键驱动程序,所以驱动程序分为上下两层: ① button_drv.c分配/设置/注册 file_operations结构体
起承上启下的作用,向上提供 button_open,button_read供 APP调用。
而这 2个函数又会调用底层硬件提供的 p_button_opr中的 init、read函数操作硬件。
② board_xxx.c分配/设置/注册 button_operations结构体
这个结构体是我们自己抽象出来的,里面定义单板 xxx的按键操作函数。
这样的结构易于扩展,对于不同的单板,只需要替换 board_xxx.c提供自己的 button_operations结构体即可。
在这里插入图片描述
使用 GIT下载所有源码后,本节源码位于如下目录:

01_all_series_quickstart\ 
05_嵌入式 Linux驱动开发基础知识\source\ 
04_button_drv\01_button_drv_template 

14.3.1 把按键的操作抽象出一个button_operations结构体

首先看看 button_drv.h,它定义了一个 button_operations结构体,把按键的操作抽象为这个结构体:

04 struct button_operations { 
05     int count; 
06     void (*init) (int which); 
07     int (*read) (int which); 
08 }; 
09 
10 void register_button_operations(struct button_operations *opr); 
11 void unregister_button_operations(void); 
12 

再看看 board_xxx.c,它实现了一个 button_operations结构体,代码如下。
第 45行调用 register_button_operations函数,把这个结构体注册到上层驱动中。 37 static struct

button_operations my_buttons_ops ={ 
38     .count = 2, 
39     .init  = board_xxx_button_init_gpio, 
40     .read  = board_xxx_button_read_gpio, 
41 }; 
42 
43 int board_xxx_button_init(void) 
44 { 
45     register_button_operations(&my_buttons_ops); 
46     return 0; 
47 } 
48 

14.3.2 驱动程序的上层:file_operations结构体

上层是 button_drv.c,它的核心是 file_operations结构体,首先看看入口函数,代码如下。
第 83行向内核注册一个 file_operations结构体。
第 85行创建一个 class,但是该 class下还没有 device,在后面获得底层硬件的信息时再在 class下创建 device:这只是用来创建设备节点,它不是驱动程序的核心。

81 int button_init(void) 
82 { 
83     major = register_chrdev(0, "xxxxxx_button", &button_fops); 
84 
85     button_class = class_create(THIS_MODULE, "xxxxxx_button"); 
86     if (IS_ERR(button_class)) 
87         return -1; 
88 
89     return 0; 
90 } 
91 

再来看看 button_drv.c中 file_operations结构体的成员函数,代码如下。
第 34、44行都用到一个 button_operations指针,它是从何而来?

28 static struct button_operations *p_button_opr; 
29 static struct class *button_class; 
30 
31 static int button_open (struct inode *inode, struct file *file) 
32 { 
33     int minor = iminor(inode); 
34     p_button_opr->init(minor); 
35     return 0; 
36 } 
37 
38 static ssize_t button_read (struct file *file, char __user *buf, size_t size, loff_t *off) 
39 { 
40     unsigned int minor = iminor(file_inode(file)); 
41     char level; 
42     int err; 
43 
44     level = p_button_opr->read(minor); 
45     err = copy_to_user(buf, &level, 1); 
46     return 1; 
47 } 
48 
49 
50 static struct file_operations button_fops = { 51     .open = button_open, 
52     .read = button_read, 
53 }; 

上面第 34、44行都用到一个 button_operations指针,来自于底层硬件相关的代码。
底层代码调用 register_button_operations函数,向上提供这个结构体指针。
register_button_operations函数代码如下,它还根据底层提供的 button_operations调用
device_create,这是创建设备节点(第 62行)。

55 void register_button_operations(struct button_operations *opr) 
56 { 
57     int i; 
58 
59     p_button_opr = opr; 
60     for (i = 0; i < opr->count; i++) 
61     { 
62         device_create(button_class, NULL, MKDEV(major, i), NULL, "xxxxxx_button%d", i); 
63     } 
64 } 
65 

14.4 测试

这只是一个示例程序,还没有真正操作硬件。测试程序操作驱动程序时,只会导致驱动程序中打印信息。
首先设置交叉工具链,修改驱动 Makefile中内核的源码路径,编译驱动和测试程序。
启动开发板后,通过 NFS访问编译好驱动程序、测试程序,就可以在开发板上如下操作了:

# insmod button_drv.ko   // 装载驱动程序 
[  435.276713] button_drv: loading out-of-tree module taints kernel. 
# insmod board_xxx.ko 
# ls /dev/xxxxxx_button* -l     // 查看设备节点 
crw-------    1 root     root      236,   0 Jan 18 08:57 /dev/xxxxxx_button0 
crw-------    1 root     root      236,   1 Jan 18 08:57 /dev/xxxxxx_button1 
# ./button_test /dev/xxxxxx_button0    // 读按键 
[  450.886180] /home/book/source/04_button_drv/01_button_drv_template/board_xxx.c board_xxx_button_init_gpio 28, init gpio for button 0 [ 
450.910915] 
/home/book/source/04_button_drv/01_button_drv_template/board_xxx.c 
board_xxx_button_read_gpio 33, read gpio for button 0 
get button : 1    // 得到数据 

14.5 课后怎业

合并 LED、BUTTON框架驱动程序:01_led_drv_template、01_button_drv_template,合并为:
gpio_drv_template

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

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

相关文章

竞赛选题 大数据商城人流数据分析与可视化 - python 大数据分析

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的基站数据分析与可视化 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度…

优化 Node.js 性能:检测内存泄漏和高 CPU 使用率

优化 Node.js 性能&#xff1a;检测内存泄漏和高 CPU 使用率 Node.js 是一种流行的 JavaScript 运行时&#xff0c;以其速度、性能和可扩展性而闻名。然而&#xff0c;即使是优化和编写得非常好的 Node.js 应用程序也可能会遇到性能问题&#xff0c;例如内存泄漏和 CPU 使用率…

yolov8 opencv模型部署(C++版)

yolov8 opencv模型部署&#xff08;C 版&#xff09; 使用opencv推理yolov8模型&#xff0c;仅依赖opencv&#xff0c;无需其他库&#xff0c;以yolov8s为例子&#xff0c;注意&#xff1a; 使用opencv4.8.0 &#xff01;使用opencv4.8.0 &#xff01;使用opencv4.8.0 &#…

Python函数语法与面向对象回顾(精华)

目录 函数 语法定义 返回值 位置参数 关键字传递 默认参数 函数参数中 / 作用 lambda表达式 递归函数 面向对象 初识对象 继承 构造函数 ​编辑 多态 "私有属性" 动态 类方法和静态方法 函数 语法定义 pyhon的函数定义语法是 def 函数名(参数…

基于SpringBoot的师生共评的作业管理系统设计与实现

目录 前言 一、技术栈 二、系统功能介绍 课程管理 作业管理 作业互评 小组管理 作业管理 作业评分 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息互联网信息的飞速发展&#xff0c;无纸化作业变成了一种趋势&#xff0c;针对这个问题开发一个…

蓝桥等考Python组别十级003

第一部分&#xff1a;选择题 1、Python L10 &#xff08;15分&#xff09; 已知s Pencil&#xff0c;下列说法正确的是&#xff08; &#xff09;。 s[0]对应的字符是Ps[1]对应的字符是ns[-1]对应的字符是is[3]对应的字符是e 正确答案&#xff1a;A 2、Python L10 &am…

【GDB】 command 命令

GDB command 命令 语法 command 命令是一个很好用的调试命令&#xff0c;它配合断点使用&#xff0c;可以在指定的断点执行预先设置的命令 其语法为&#xff1a;command bread_id&#xff0c;这样会提示你输入你要执行的命令&#xff0c;以 end 结束。这个 bread_id 就是用 …

【Axure】Axure的常用功能

选择 分为相交选中和包含选中 相交选中&#xff1a;部分选中即是选中包含选中&#xff1a;全选才是选中 缩放 按住元件四角&#xff0c;等比例缩放 置顶和置底 所谓置于顶层就是不被后来的元件覆盖住&#xff0c;置于底层的意思则相反 组合、对齐、分布 组合&#xff1…

Java安全之servlet内存马分析

目录 前言 什么是中间键 了解jsp的本质 理解servlet运行机制 servlet的生命周期 Tomcat总体架构 查看Context 的源码 servlet内存马实现 参考 前言 php和jsp一句话马我想大家都知道&#xff0c;早先就听小伙伴说过一句话木马已经过时了&#xff0c;现在是内存马的天下…

Spring MVC 十:异常处理

异常是每一个应用必须要处理的问题。 Spring MVC项目&#xff0c;如果不做任何的异常处理的话&#xff0c;发生异常后&#xff0c;异常堆栈信息会直接抛出到页面。 比如&#xff0c;我们在Controller写一个异常&#xff1a; GetMapping(value"/hello",produces{&qu…

搭建前端框架

在终端进入web目录&#xff0c;然后创建vuecrud工程 创建工程并引入ElementUI和axios手把手教学>传送门:VueCLI脚手架搭建

2023.09.30使用golang1.18编译Hel10-Web/Databasetools的windows版

#Go 1.21新增的 log/slog 完美解决了以上问题&#xff0c;并且带来了很多其他很实用的特性。 本次编译不使用log/slog 包 su - echo $GOPATH ;echo $GOROOT; cd /tmp; busybox wget --no-check-certificate https://go.dev/dl/go1.18.linux-amd64.tar.gz;\ which tar&&am…

驱动插入中断门示例代码

驱动插入中断描述符示例代码 最近做实验&#xff0c;每次在应用层代码写测试代码的时候都要手动挂一个中断描述符&#xff0c;很不方便所以就想着写个驱动挂一个中断门比较省事 驱动测试效果如下&#xff1a; 下面的代码是个架子&#xff0c;用的时候找个驱动历程传递你要插…

搭建智能桥梁,Amazon CodeWhisperer助您轻松编程

零&#xff1a;前言 随着时间的推移&#xff0c;人工智能技术以惊人的速度向前发展&#xff0c;正掀起着全新的编程范式革命。不仅仅局限于代码生成&#xff0c;智能编程助手等创新应用也进一步提升了开发效率和代码质量&#xff0c;极大地推动着软件开发领域的快速繁荣。 当前…

小白继续深入学习C++

第1节 指针的基本概念 1、变量的地址&#xff1a; 变量是内存地址的简称&#xff0c;在C中&#xff0c;每定义一个变量&#xff0c;系统就会给变量分配一块内存&#xff0c;内存是有地址的。 C用运算符&获取变量在内存中的起始地址。 语法&#xff1a; &变…

如果在 Mac 上的 Safari 浏览器中无法打开网站

使用网络管理员提供的信息更改代理设置。个人建议DNS解析&#xff0c;设置多个例如114.114.114.114 8.8.8.8 8.8.4.4 如果打不开网站&#xff0c;请尝试这些建议。 在 Mac 上的 Safari 浏览器 App 中&#xff0c;检查页面无法打开时出现的信息。 这可能会建议解决问题的…

Chrome(谷歌浏览器)如何关闭搜索栏历史记录

目录 问题描述解决方法插件解决&#xff08;亲测有效&#xff09;自带设置解决步骤首先打开 地址 输入&#xff1a;chrome://flags关闭浏览器&#xff0c;重新打开Chrome 发现 已经正常 问题描述 Chrome是大家熟知的浏览器&#xff0c;但是搜索栏的历史记录如何自己一条条的删…

第80步 时间序列建模实战:GRNN回归建模

基于WIN10的64位系统演示 一、写在前面 这一期&#xff0c;我们使用Matlab进行GRNN模型的构建。 使用的数据如下&#xff1a; 采用《PLoS One》2015年一篇题目为《Comparison of Two Hybrid Models for Forecasting the Incidence of Hemorrhagic Fever with Renal Syndrom…

(高阶) Redis 7 第16讲 预热/雪崩/击穿/穿透 缓存篇

面试题 什么是缓存预热/雪崩/击穿/穿透如何做缓存预热如何避免或减少缓存雪崩穿透和击穿的区别?穿透和击穿的解决方案出现缓存不一致时,有哪些修补方案缓存预热 理论 将需要的数据提前加载到缓存中,不需要用户使用的过程中进行数据回写。(比如秒杀活动数据等) 方案 1.…

软件设计师_操作系统基本原理_学习笔记

文章目录 2.1 操作系统概述2.2 进程2.2.1 进程状态转换图2.2.2 前趋图2.2.3 进程的同步与互斥2.2.4 PV操作2.2.5 死锁 2.3 存储管理2.3.1 分区存储管理 2.1 操作系统概述 2.2 进程 2.2.1 进程状态转换图 2.2.2 前趋图 哪些任务可以并行&#xff0c;哪些任务有先后关系&#xf…