嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十四)查询方式的按键驱动程序_编写框架

简介: 嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十四)查询方式的按键驱动程序_编写框架

1.查询方式的按键驱动程序_编写框架


1.1 LED驱动回顾


对于LED,APP调用open函数导致驱动程序的led_open函数被调用。在里面,把GPIO配置为输出引脚。安装驱动程序后并不意味着会使用对应的硬件,而APP要使用对应的硬件,必须先调用open函数。所以建议在驱动程序的open函数中去设置引脚。

APP继续调用write函数传入数值,在驱动程序的led_write函数根据该数值去设置GPIO的数据寄存器,从而控制GPIO的输出电平。

怎么操作寄存器?从芯片手册得到对应寄存器的物理地址,在驱动程序中使用ioremap函数映射得到虚拟地址。驱动程序中使用虚拟地址去访问寄存器。

1670920381319.jpg

1.2 按键驱动编写思路


GPIO按键的原理图一般有如下2种:

1670920392445.jpg

按键没被按下时,上图中左边的GPIO电平为高,右边的GPIO电平为低。 按键被按下后,上图中左边的GPIO电平为低,右边的GPIO电平为高。


编写按键驱动程序最简单的方法如下图所示:

1670920402317.jpg

回顾一下编写驱动程序的套路:

1670920412038.jpg

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


1.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结构体即可。

1670920430453.jpg

使用GIT下载所有源码后,本节源码位于如下目录:

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


1.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


1.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, "100ask_button", &button_fops);
84
85     button_class = class_create(THIS_MODULE, "100ask_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, "100ask_button%d", i);
63     }
64 }
65


1.4 测试


这只是一个示例程序,还没有真正操作硬件。测试程序操作驱动程序时,只会导致驱动程序中打印信息。

首先设置交叉工具链,修改驱动Makefile中内核的源码路径,编译驱动和测试程序。

启动开发板后,通过NFS访问编译好驱动程序、测试程序,就可以在开发板上如下操作了:

# insmod button_drv.ko   // 装载驱动程序
[  435.276713] button_drv: loading out-of-tree module taints kernel.
# insmod board_xxx.ko
# ls /dev/100ask_button* -l     // 查看设备节点
crw-------    1 root     root      236,   0 Jan 18 08:57 /dev/100ask_button0
crw-------    1 root     root      236,   1 Jan 18 08:57 /dev/100ask_button1
# ./button_test /dev/100ask_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    // 得到数据


1.5 课后怎业


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

相关文章
|
6月前
|
Ubuntu Linux 开发者
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
341 15
|
7月前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
263 13
|
11月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
496 3
|
12月前
|
Ubuntu 算法 Linux
嵌入式Linux的学习误区
**嵌入式Linux学习误区摘要** 1. **过度聚焦桌面Linux** - 许多学习者误将大量时间用于精通桌面Linux系统(如RedHat、Fedora、Ubuntu),认为这是嵌入式Linux开发的基石。 - 实际上,桌面Linux仅作为开发工具和环境,目标不应是成为Linux服务器专家,而应专注于嵌入式开发工具和流程。 2. **盲目阅读Linux内核源码** - 初学者在不了解Linux基本知识时试图直接研读内核源码,这往往导致困惑和挫败感。 - 在具备一定嵌入式Linux开发经验后再有针对性地阅读源码,才能有效提升技能。
162 4
|
11月前
|
传感器 人工智能 网络协议
:嵌入式 Linux 及其用途
【8月更文挑战第24天】
412 0
|
24天前
|
开发者
鸿蒙开发:资讯项目实战之项目初始化搭建
目前来说,我们的资讯项目只是往前迈了很小的一步,仅仅实现了项目创建,步虽小,但概念性的知识很多,这也是这个项目的初衷,让大家不仅仅可以掌握日常的技术开发,也能让大家理解实际的项目开发知识。
鸿蒙开发:资讯项目实战之项目初始化搭建
|
18天前
|
缓存 JavaScript IDE
鸿蒙开发:基于最新API,如何实现组件化运行
手动只是让大家了解切换的原理,在实际开发中,可不推荐手动,下篇文章,我们将通过脚本或者插件,快速实现组件化模块之间的切换,实现独立运行,敬请期待!
鸿蒙开发:基于最新API,如何实现组件化运行
|
24天前
|
SQL 弹性计算 数据库
鸿蒙5开发宝藏案例分享---优化应用时延问题
鸿蒙性能优化指南来了!从UI渲染到数据库操作,6大实战案例助你提升应用流畅度。布局层级优化、数据加载并发、数据库查询提速、相机资源延迟释放、手势识别灵敏调整及转场动画精调,全面覆盖性能痛点。附赠性能自检清单,帮助开发者高效定位问题,让应用运行如飞!来自华为官方文档的精华内容,建议收藏并反复研读,共同探讨更多优化技巧。
|
24天前
|
缓存
鸿蒙5开发宝藏案例分享---Swiper组件性能优化实战
本文分享了鸿蒙系统中Swiper组件的性能优化技巧,包括:1) 使用`LazyForEach`替代`ForEach`实现懒加载,显著降低内存占用;2) 通过`cachedCount`精准控制缓存数量,平衡流畅度与内存消耗;3) 利用`onAnimationStart`在抛滑时提前加载资源,提升构建效率;4) 添加`@Reusable`装饰器复用组件实例,减少创建开销。实际应用后,图库页帧率从45fps提升至58fps,效果显著。适合处理复杂列表或轮播场景,欢迎交流经验!
|
24天前
|
缓存 JavaScript 前端开发
鸿蒙5开发宝藏案例分享---Web开发优化案例分享
本文深入解读鸿蒙官方文档中的 `ArkWeb` 性能优化技巧,从预启动进程到预渲染,涵盖预下载、预连接、预取POST等八大优化策略。通过代码示例详解如何提升Web页面加载速度,助你打造流畅的HarmonyOS应用体验。内容实用,按需选用,让H5页面快到飞起!