【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第六十二章 定时器按键消抖实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT、4G模块、CAN、RS485等接口一应俱全。H264、VP8视频硬编码,H.264、H.265、VP8、VP9视频硬解码,并提供相关历程,支持8路PDM接口、5路SAI接口、2路Speaker。系统支持Android9.0(支持获取root限)Linux4.14.78+Qt5.10.1、Yocto、Ubuntu20、Debian9系统。适用于智能充电桩,物联网,工业控制,医疗,智能交通等,可用于任何通用工业和物联网应用、

【公众号】迅为电子

【粉丝群】258811263(加群获取驱动文档+例程)


六十二 定时器按键消抖实验

本章导读

在前面的实验中都用到了按键,用到按键就要处理因为机械结构带来的按键抖动问题,也就是按键消抖。如果直接用延时函数来实现消抖会浪费 CPU 性能,因为在延时函数里面 CPU 什么都做不了。如果按键使用中断的话更不能在中断里面使用延时函数,因为中断服务函数要快进快出!本章我们学习如何使用定时器来实现按键消抖,使用定时器既可以实现按键消抖,而且也不会浪费CPU 性能,这个也是 Linux 驱动里面按键消抖的做法。

62.1章节讲解了定时器按键消抖原理

62.2章节以实验的形式,实现定时器按键消抖。

本章内容对应视频讲解链接(在线观看):

按键消抖实验 → https://www.bilibili.com/video/BV1Vy4y1B7ta?p=41

程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\019-定时器按键消抖实验\”路径下。

62.1 定时器按键消抖简介

理想型的按键电压变化过程如图所示:

在上图中,按键没有按下的时候按键值为 1,当按键在 t1 时刻按键被按下以后按键值就变为 0,这是最理想的状态。但是实际的按键是机械结构,加上刚按下去的一瞬间人手可能也有抖动,实际的按键电压变化过程如下图所示: 

在上图中,t1 时刻按键被按下,但是由于抖动的原因,直到 t2 时刻才稳定下来,t1 到t2 这段时间就是抖动。一般这段时间就是十几 ms 左右,从上图中可以看出在抖动期间会有多次触发,如果不消除这段抖动的话软件就会误判,本来按键就按下了一次,结果软件读取IO 值发现电平多次跳变以为按下了多次。所以我们需要跳过这段抖动时间再去读取按键的 IO值,也就是至少要在 t2 时刻以后再去读 IO 值。因此,

我们可以借助定时器来实现消抖,按键采用中断驱动方式,当按键按下以后触发按键中断,在按键中断中开启一个定时器,定时周期为 10ms,当定时时间到了以后就会触发定时器中断,最后在定时器中断处理函数中读取按键的值,如果按键值还是按下状态那就表示这是一次有效的按键。定时器按键消抖如下图所示:

 

在上图中t1~t3 这一段时间就是按键抖动,是需要消除的。设置按键为下降沿触发,因此会在 t1、t2 和 t3 这三个时刻会触发按键中断,每次进入中断处理函数都会重新开启定时器中断,所以会在 t1、t2 和 t3 这三个时刻开器定时器中断。但是 t1~t2 和 t2~t3 这两个时间段是小于我们设置的定时器中断周期(也就是消抖时间,比如 10ms),所以虽然 t1 开启了定时器,但是定时器定时时间还没到呢 t2 时刻就重置了定时器,最终只有 t3 时刻开启的定时器能完整的完成整个定时周期并触发中断,我们就可以在中断处理函数里面做按键处理了,这就是定时器实现按键防抖的原理,Linux 里面的按键驱动用的就是这个原理!

62.2 定时器按键消抖实验

我们在Ubuntu的/home/topeet/imx8mm/19目录下新建driver.c文件,将Makefile,build.sh拷贝到同级目录下,完整代码如下所示:

/** @Author:topeet* @Description:定时器按键消抖*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/timer.h>//need by strerror()
//#include <string.h>// 声明时间处理函数
static void timer_function(unsigned long data);
// 该宏会静态创建一个名叫 timer_name 内核定时器,
// 并初始化其 function, expires, name 和 base 字段。
DEFINE_TIMER(test_timer, timer_function, 0, 0);
//定义结构体表示我们的节点
struct device_node *test_device_node;
struct property *test_node_property;
//要申请的中断号
int irq;
//GPIO 编号
int gpio_nu;
int a=0;
/*** @description:超时处理函数 * @param {*}* @return {*}*/
static void timer_function(unsigned long data)
{//如果超时则打印信息printk(" This is timer_function \n");a=0;//mod_timer(&test_timer,jiffies + 1*HZ);
}//中断处理函数
irqreturn_t test_key(int irq, void *args)
{if(a==0){a=1;printk("test_key\n");test_timer.expires = jiffies + msecs_to_jiffies(20);//定时器注册到内核里面add_timer(&test_timer);}return IRQ_HANDLED;
}
/*** @brief led_probe : 与设备信息层(设备树)匹配成功后自动执行此函数,* @param inode : 文件索引* @param file  : 文件* @return 成功返回 0           
*/
int led_probe(struct platform_device *pdev)
{int ret = 0;printk("led_probe\n");//of_find_node_by_path函数通过路径查找节点,/test_key是设备树下的节点路径test_device_node = of_find_node_by_path("/test");if (test_device_node == NULL){printk("of_find_node_by_path is error \n");return -1;}//of_get_named_gpio函数获取 GPIO 编号gpio_nu = of_get_named_gpio(test_device_node, "gpios", 0);if (gpio_nu < 0){printk("of_get_namd_gpio is error \n");return -1;}// 设置GPIO为输入模式gpio_direction_input(gpio_nu);// 获取中断号irq = irq_of_parse_and_map(test_device_node, 0);//gic_irq_domain_translate(test_device_node, 0);printk("irq is %d \n", irq);/*申请中断,irq:中断号名字  test_key:中断处理函数IRQF_TRIGGER_RISING:中断标志,意为上升沿触发"test_key":中断的名字*/ret = request_irq(irq, test_key, IRQ_TYPE_EDGE_BOTH, "test_key", NULL);if (ret < 0){printk("request_irq is error :%d\n",ret);return -1;}return 0;
}int led_remove(struct platform_device *pdev)
{printk("led_remove\n");return 0;
}
const struct platform_device_id led_idtable = {.name = "keys",
};
const struct of_device_id of_match_table_test[] = {{.compatible = "keys"},{},
};
struct platform_driver led_driver = {//3. 在led_driver结构体中完成了led_probe和led_remove.probe = led_probe,.remove = led_remove,.driver = {.owner = THIS_MODULE,.name = "led_test",.of_match_table = of_match_table_test},//4 .id_table的优先级要比driver.name的优先级要高,优先与.id_table进行匹配.id_table = &led_idtable};static int led_driver_init(void)
{//1.我们看驱动文件要从init函数开始看int ret = 0;//2. 在init函数里面注册了platform_driverret = platform_driver_register(&led_driver);if (ret < 0){printk("platform_driver_register error \n");}printk("platform_driver_register ok \n");return 0;
}static void led_driver_exit(void)
{del_timer(&test_timer);free_irq(irq, NULL);platform_driver_unregister(&led_driver);printk("gooodbye! \n");
}
module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");

我们将刚刚编写的驱动代码编译为驱动模块,如下图所示:

并且加载驱动模块,如下图所示,我们按下开发板上面的音量+按键,打印" This is timer_function \n",说明进入了超时服务函数。 

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

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

相关文章

shardingsphere的学习(一):shardingsphere的基本概念和水平分表例子

简介 关于shardingsphere的基本相关概念的学习和使用shardingjdbc进行水平分表的例子 shardingsphere 是一套开源的分布式关系型数据库中间件解决方案&#xff0c;由sharding-jdbc&#xff0c;sharding-proxy&#xff0c;sharding-sidecar三个项目组成。 定位为关系型数据库…

日期类的实现(C++实现)

完整呈现 Date.h #include <iostream> using namespace std; //日期类 class Date { public:int GetMonthDays(int year, int month) const;//构造函数Date(int year 0, int month 1, int day 1);//拷贝构造Date(const Date& d);//打印void Print();//析构函数~…

Redis与MySQL数据一致性问题的策略模式及解决方案

目录 一、策略模式 1、旁路缓存模式&#xff08;Cache Aside Pattern&#xff09; 2、读写穿透&#xff08;Read-Through/Write-Through&#xff09; 3、异步缓存写入&#xff08;Write Behind&#xff09; 二、一致性解决方案 1、缓存延迟双删 2、删除重试机制 3、读取…

【python】sklearn基础教程及示例

【python】sklearn基础教程及示例 Scikit-learn&#xff08;简称sklearn&#xff09;是一个非常流行的Python机器学习库&#xff0c;提供了许多常用的机器学习算法和工具。以下是一个基础教程的概述&#xff1a; 1. 安装scikit-learn 首先&#xff0c;确保你已经安装了Python和…

Unity 资源 之 Pop It 3D 解压玩具与双人AI游戏 Unity 资源包分享

精彩呈现&#xff1a;Pop It 3D 解压玩具与双人AI游戏 Unity 资源包分享 一、Pop It 3D 解压玩具的魅力二、双人游戏的互动乐趣三、Unity 游戏资源包的优势四、如何获取资源包 亲爱的游戏爱好者们&#xff0c;今天为大家带来一款令人兴奋的游戏资源——Pop It 3D 解压玩具双人带…

数字陷波器的设计和仿真(Matlab+C)

目录 一、数字陷波器的模型 二、Matlab仿真 1. 示例1 2. 示例2 三、C语言仿真 1. 由系统函数计算差分方程 2. 示例代码 一、数字陷波器的模型 二、Matlab仿真 1. 示例1 clear clc f0=100;%滤掉的100Hz fs=1000;%大于两倍的信号最高频率 r=0.9; w0=2*pi*f0/fs;%转换到…

[图解]《分析模式》漫谈19-Midjourney、Sora

1 00:00:02,360 --> 00:00:03,360 今天的漫谈 2 00:00:03,370 --> 00:00:04,560 我们来说一下 3 00:00:04,570 --> 00:00:08,720 人工智能&#xff0c;还是前言 4 00:00:08,890 --> 00:00:11,840 这里有一句话 Kent Beck 5 00:00:12,630 --> 00:00:13,750 W…

Spring Boot配置文件的语法规则

主要介绍两种配置文件的语法和格式&#xff0c;properties和yml 目录 1.配置文件的作用 2.创建配置文件 3.properties语法 4.yml语法 5.配置文件格式 1.配置文件的作用 对于配置文件&#xff0c;也有独立的文件夹去存放&#xff0c;主要用来存放一些需要经过变动的数据&a…

python绘制方波信号

python绘制方波信号 1、效果 2、导入库 pip install numpy pip install matplotlib3、实现代码 # -*- coding: utf-8 -*-""" @contact: 微信 1257309054 @file: test.py @time: 2024/7/28 14:48 @author: LDC """ import numpy as np import …

IOS-04 Swift 中数组、集合、字典、区间、元组和可选类型

在 Swift 编程语言中&#xff0c;数据结构和类型的合理运用对于高效编程至关重要。接下来&#xff0c;我们将深入探讨数组、集合、字典、区间、元组和可选类型的相关知识。 一、数组&#xff08;Array&#xff09; &#xff08;一&#xff09;元素定义 可以通过多种方式定义数…

Hello 算法:动画图解、一键运行的数据结构与算法教程

Hello 算法 《Hello 算法》是一份开源、免费的数据结构与算法入门教程&#xff0c;特别适合新手。全书采用动画图解&#xff0c;内容清晰易懂&#xff0c;学习曲线平滑&#xff0c;引导初学者探索数据结构与算法的知识地图。源代码可以一键运行&#xff0c;帮助读者通过练习提…

C#中的同步编程和异步编程

1. 简单描述一下同步编程和异步编程 同步编程&#xff1a;按照代码的顺序一行一行执行&#xff0c;如果某个操作需要等待&#xff08;比如读取文件、网络请求、数据库操作等&#xff09;&#xff0c;那么当前的线程就会停下来&#xff0c;一直到这个操作完成了之后&#xff0c…

git学习(一)

一、代码仓库的初始化 1、先在本地操作&#xff0c;不涉及到远程服务器&#xff0c;创建目录mkdir git demo 想要本地创建的目录成为一个远程仓库就需要初始化git init git init 后会发生什么&#xff1f; 2、watch -n 1 -d tind每隔1s打印当前文件目录并且刷新 左边命令 wa…

搞DDR,你是可以看看我的这篇笔记(三)

关于DDR PHY这个部分,是数模混合器件,工作涉及到了很多信号完整性,眼图,模拟等相关的东西我就没讲了。因为确实不太熟悉,只能站在架构、功能、使用上去聊聊。 上一篇我们看了这个图片,简化就是下面这个样子: 其实这个也不太合适~~~ 这样舒服多了,一般DDRC和DDRPHTY都会…

被工信部认可的开源软件治理解决方案

近日&#xff0c;工信部网络安全产业发展中心正式发布了“2023年信息技术应用创新解决方案”&#xff0c;开源网安凭借“基于SCA技术开源软件治理解决方案”顺利入选&#xff0c;成为经工信部认可的优秀解决方案&#xff0c;这是开源网安连续两届荣获此荣誉。 工业和信息化部网…

17.延迟队列

介绍 延迟队列&#xff0c;队列内部是有序的&#xff0c;延迟队列中的元素是希望在指定时间到了以后或之前取出和处理。 死信队列中&#xff0c;消息TTL过期的情况其实就是延迟队列。 使用场景 1.订单在十分钟内未支付则自动取消。 2.新创建的店铺&#xff0c;如果十天内没…

【Redis系列】RedisTemplate的使用与注意事项

目录 一.什么是RedisTemplate 二.如何使用RedisTemplate RedisTemplate的API 序列化 三.StringRedisTemplate 一.什么是RedisTemplate RedisTemplate 是一个工具类&#xff0c;由 Spring 官方提供的方便操作 Redis 数据库的一个工具类&#xff0c;来源于 org.springframe…

【LLM】-10-部署llama-3-chinese-8b-instruct-v3 大模型

目录 1、模型下载 2、下载项目代码 3、启动模型 4、模型调用 4.1、completion接口 4.2、聊天&#xff08;chat completion&#xff09; 4.3、多轮对话 4.4、文本嵌入向量 5、Java代码实现调用 由于在【LLM】-09-搭建问答系统-对输入Prompt检查-CSDN博客 关于提示词注入…

涉密移动载体智能柜管控系统DW-S404|国产自主可控

东识移动载体管控系统载体柜系统采用RFID识别技术&#xff0c;结合智能载体管理软件&#xff0c;实现了文件载体权限管理、定位管理、智能存取、智能盘点、在线监控等功能&#xff0c;同时对文件载体进行规范化、智能化、自动化管理。工作人员通过授权进行文件、载体、卷宗等存…

C# 简单的单元测试

文章目录 前言参考文档新建控制台项目新建测试项目添加引用添加测试方法测试结果(有错误)测试结果&#xff0c;通过正规的方法抛出异常 总结 前言 听说复杂的项目最好都要单元测试一下。我这里也试试单元测试这个功能。到时候调试起来也方便。 参考文档 C# 单元测试&#xf…