Linux系统驱动(十三)Linux内核定时器
文章目录
- 一、内核定时器原理
- 二、定时器API
- 三、使用定时器让LED灯闪烁
- 四、使用定时器对按键进行消抖
一、内核定时器原理
内核当前时间通过jiffies获取,它是内核时钟节拍数,在linux内核启动的时候,jiffies开始(按照一定频率)增加。在驱动中可以直接使用jiffies获取当前时间。
定时器每增加1走的时间由频率决定,定时器的频率可以通过make menuconfig进行选配,选配后的结果在.config文件中保存,选项是CONFIG_HZ。
linux-5.10.61内核CONFIG_HZ=100,定时器每增加1走10ms。
ubuntu的内核CONFIG_HZ=250,定时器每增加1走4ms。
二、定时器API
1.分配对象struct timer_list {struct hlist_node entry; //构成链表成员unsigned long expires; //定时器到期时间void (*function)(struct timer_list *);//定时器处理函数(定时时间到执行的函数)u32 flags; //填写为0};struct timer_list mytimer;
2.对象初始化mytimer.expires = jiffies+HZ; //定时1s钟 timer_setup(&mytimer, 定时器处理函数, 0);
3.启动定时器void add_timer(struct timer_list *timer)//功能:启动定时器,这个定时器只会执行一次(add_timer只能调用一次,多次调用内核会崩溃)int mod_timer(struct timer_list *timer, unsigned long expires)//功能:再次启动定时器
4.删除定时器int del_timer(struct timer_list *timer)
三、使用定时器让LED灯闪烁
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h> //设备树文件相关头文件
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include "mynode.h"const char *led[3]={"led1","led2","led3"};
int core_gpiono[3];
int expend_gpiono[3];
struct cdev *led_cdev;
struct class *led_class;
struct device *led_device;
int major = 0; //主设备号
int minor = 0;
dev_t led_dev_num;struct timer_list mytimer;//定时器int my_led_open(struct inode *inode, struct file *file){return 0;
}
int my_led_close(struct inode *inode, struct file *file){return 0;
}
long myled_ioctl(struct file *file, unsigned int cmd, unsigned long arg){return 0;
}const struct file_operations ledfops={.open=my_led_open,.release=my_led_close,.unlocked_ioctl=myled_ioctl,
};void timer_handler(struct timer_list* timer){int i;for(i=0;i<3;i++){gpio_set_value(expend_gpiono[i],!gpio_get_value(expend_gpiono[i]));}mod_timer(&mytimer,jiffies+HZ);
}static int __init mynode_init(void){struct device_node *core_node,*expend_node;int i,ret;//分配对象led_cdev = cdev_alloc();if(NULL == led_cdev){ //成功返回结构体指针,失败返回NULLpr_err("cdv_err error");return -ENOMEM;}//初始化对象:部分成员初始化cdev_init(led_cdev,&ledfops);//申请设备号:如果major为0,则动态申请,否则就静态指定if(major > 0){register_chrdev_region(MKDEV(major,minor),1,"mynode");}else if(major == 0){alloc_chrdev_region(&led_dev_num,0,1,"mynode"); major=MAJOR(led_dev_num);minor=MINOR(led_dev_num);}//注册cdev_add(led_cdev,MKDEV(major,minor),1); //自动创建设备节点led_class=class_create(THIS_MODULE,"mynode");led_device = device_create(led_class,NULL,MKDEV(major,minor),NULL,"mynode");/***gpio***///1. 获取节点//core节点core_node = of_find_node_by_path("/myleds/core_leds");if(NULL == core_node){pr_err("of_find_node_by_path error");return -EINVAL;}//expend节点expend_node = of_find_node_by_path("/myleds/expend_leds");if(NULL == expend_node){pr_err("of_find_node_by_path error");return -EINVAL;}//2.获取gpio号for(i=0;i<3;i++){//corecore_gpiono[i] = of_get_named_gpio(core_node,led[i],0);if(core_gpiono[i] < 0){pr_err("of_get_named_gpio error");return core_gpiono[i];}//expendexpend_gpiono[i] = of_get_named_gpio(expend_node,led[i],0);if(expend_gpiono[i] < 0){pr_err("of_get_named_gpio error");return expend_gpiono[i];}}//3. 申请gpiofor(i=0;i<3;i++){ret=gpio_request(core_gpiono[i],NULL);if(ret){pr_err("gpio_request error");for(i--;i>0;i--){gpio_free(core_gpiono[i]);}return ret;}}for(i=0;i<3;i++){ret=gpio_request(expend_gpiono[i],NULL);if(ret){pr_err("gpio_request error");for(i--;i>0;i--){gpio_free(expend_gpiono[i]);}for(i=0;i<3;i++){gpio_free(core_gpiono[i]);}return ret;}}//4.设置方向为输出for(i=0;i<3;i++){ret = gpio_direction_output(core_gpiono[i], 0);if (ret) {pr_err("gpio_direction_output error\n");goto err;}ret = gpio_direction_output(expend_gpiono[i], 0);if (ret) {pr_err("gpio_direction_output error\n");goto err;}}/***定时器****///2.定时器对象初始化mytimer.expires = jiffies+HZ; //定时1s钟 timer_setup(&mytimer, timer_handler, 0); //3.启动定时器add_timer(&mytimer);return 0;
err:for(i=0;i<3;i++){gpio_free(core_gpiono[i]);gpio_free(expend_gpiono[i]);}return ret;
}
static void __exit mynode_exit(void){int i;//删除定时器del_timer(&mytimer);for(i=0;i<3;i++){gpio_free(core_gpiono[i]);gpio_free(expend_gpiono[i]);}device_destroy(led_class, MKDEV(major, minor));class_destroy(led_class);cdev_del(led_cdev);unregister_chrdev_region(MKDEV(major, minor), 1);kfree(led_cdev);
}module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");
四、使用定时器对按键进行消抖

#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h> //设备树文件相关头文件
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/of_gpio.h>
// mykeys{
// interrupt-parent = <&gpiof>;
// interrupt = <7 0>,<8 0>,<9 0>;
// };struct device_node *key_node;
unsigned int key_gpiono[3];struct timer_list mytimer;//定时器
//7 8 9------2 3 1
unsigned int irqno[3]={0};void timer_handler(struct timer_list* timer){int i;for(i=0;i<3;i++){if(!gpio_get_value(key_gpiono[i])){switch(i){case 0:printk("key1 down ......");break;case 1:printk("key2 down ......");break;case 2:printk("key3 down ......");break;}}}
}irqreturn_t irq_handler(int irq, void *dev){mod_timer(&mytimer,jiffies+1);return IRQ_HANDLED;
}static int __init mynode_init(void){int i;/***GPIO***///1. 获取节点key_node = of_find_node_by_path("/mykeys");if(NULL == key_node){pr_err("of_find_node_by_path error");return -EINVAL;}printk("of_find_node_by_path success\n");//2.获取gpio号for(i=0;i<3;i++){//corekey_gpiono[i] = of_get_named_gpio(key_node,"keys",i);if(key_gpiono[i] < 0){pr_err("of_get_named_gpio error");return key_gpiono[i];}}printk("of_get_named_gpio success\n");//3. 申请gpio,是为了防止竞态/***中断***///1. 获取节点key_node = of_find_node_by_name(NULL,"mykeys");if(NULL == key_node){pr_err("of_find_node_by_name error");return -EINVAL;}//2.获取中断号for(i=0;i<3;i++){irqno[i] = irq_of_parse_and_map(key_node,i);if (irqno[i] == 0) {pr_err("irq_of_parse_and_map error\n");return -EAGAIN;}}//3.注册中断号for(i=0;i<3;i++){request_irq(irqno[i],irq_handler,IRQF_TRIGGER_FALLING,"my_IRQ_test",(void *)irqno[i]);}/***定时器****///2.定时器对象初始化mytimer.expires = jiffies+1; //定时10ms timer_setup(&mytimer, timer_handler, 0); //3.启动定时器add_timer(&mytimer);return 0;
}
static void __exit mynode_exit(void){int i=0;//注销中断号for(i=0;i<3;i++){free_irq(irqno[i],(void *)irqno[i]);}
}module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");
相关文章:
Linux系统驱动(十三)Linux内核定时器
文章目录 一、内核定时器原理二、定时器API三、使用定时器让LED灯闪烁四、使用定时器对按键进行消抖 一、内核定时器原理 内核当前时间通过jiffies获取,它是内核时钟节拍数,在linux内核启动的时候,jiffies开始(按照一定频率&…...
Visual Studio 调试时加载符号慢
什么是调试符号 编译程序时生成的一组特殊字符,并包含有关变量和函数在生成的二进制文件中的位置以及其他服务信息的信息。 该数据集可用于逐步调试程序或检查第三方代码。 调试符号可以添加到可执行文件或库中,但是大多数现代编译器将它们存储为单独的…...
Spring Cloud Config:动态配置的魔法师
Spring Cloud Config:动态配置的魔法师 在微服务架构的浩瀚星海中,配置管理如同一颗璀璨的星辰,而Spring Cloud Config则是那颗能够实现配置信息集中管理和动态刷新的魔法星。本文将深入探索Spring Cloud Config的奥秘,揭示如何通…...
Webpack入门基础知识及案例
webpack相信大家都已经不陌生了,应用程序的静态模块打包工具。前面我们总结了vue,react入门基础知识,也分别做了vue3的实战小案例,react的实战案例,那么我们如何使用webpack对项目进行模块化打包呢? 话不多…...
对中国人工智能与国外人工智能的思考
作为一名语文老师,我在教育的领域中见证着时代的变迁,也关注着科技的发展,尤其是人工智能这一前沿领域。当我们将目光投向中国人工智能与国外人工智能的发展时,心中不禁涌起诸多思考。 中国的人工智能近年来犹如一颗璀璨的新星&am…...
【debian系统arm架构安装docker】且换源后依旧不行就离线导入镜像
安装docker 在Debian系统上安装Docker并使用阿里云的镜像源可以通过以下步骤完成 1.更新软件包索引 前置如果需要更换源的请移步 : 初始化配置(自动连wifi,自动开启SSH)换清华源,远程桌面连接 sudo apt-get update2.安装必要的软件包以允许apt通过HTTPS使用仓库 sudo apt-get …...
Readwise 官方 Obsidian 插件使用
Readwise 官方 Obsidian 插件简介 Obsidian 中的 Readwise 注释示例 阅读已经发布了官方插件来导入你的 Readwise 数据Obsidian 。如果你还没有使用过 Readwise,那么值得一看。Readwise 是我最喜欢的 应用之一。我每天都在用它。因此,将这些数据自动导…...
A. A+B Again?
time limit per test 1 second memory limit per test 256 megabytes Given a two-digit positive integer nn, find the sum of its digits. Input The first line contains an integer tt (1≤t≤901≤t≤90) — the number of test cases. The only line of each tes…...
pr样机模板视频素材|城市户外高速路广告牌视频样机
https://prmuban.com/40369.html pr样机素材,全高清实景城市户外高速路广告牌视频样机模板,适合宣传视频制作。 主要特点: Adobe Premiere Pro 2024 全高清分辨率(19201080) 易于使用 快速渲染 无需插件 预览中使用的…...
谷歌大中华区总裁:所有企业都在问这个问题
中国开发者对于出海的热情,令Google大中华区总裁陈俊廷感慨。2024 Google I/O Connect(2024Google开发者大会)期间,他在接受第一财经记者独家采访时提到一个细节:早上7:30,他来到会场时,人们已经…...
GPT-4o:AI视觉识别的革命性飞跃
在AI的宏伟叙事中,图像识别技术始终扮演着关键角色。随着技术的不断演进,AI的视界已超越了简单的图像内容识别,它现在能够将视觉信息转化为引人入胜的文字描述。OpenAI最新力作——GPT-4o模型,以其卓越的多模态理解能力࿰…...
将电脑打造成私人网盘,支持外网访问之详细操作教程
你想过把自己电脑打造成随时随地访问的网盘吗?就是那种拥有一个属于自己的影音库,不用担心被和谐,随时可以登录访问电脑上的各种文件,相比传统网盘省心又安全。 使用Everything和节点小宝将电脑搭建成私人网盘,可以实现…...
spring同一个接口如何分页实现主表或主+联表group by查询
1 需求背景 我们的上游系统想要知道主表的记录关联子表所有记录中是否有一条满足特定的条件,如果有满足的就返回主表中的id。比如品牌brand主表中id为10的记录,在子表brand_rel中有id为1,2,3,4的这四个记录࿰…...
SpringDataJpa源码分析
我们在定义Repository的时候通常定义的时一个接口,而并没有去实现这个接口,那么Jpa是如何让开发者无需自己实现接口就可以使用Repository去操作数据库? 动态代理!!! Repository原理 试想一下JPA是如何做的…...
卷积神经网络 - 卷积神经网络与深度学习的历史篇
序言 卷积神经网络( Convolutional Neural Networks, CNN \text{Convolutional Neural Networks, CNN} Convolutional Neural Networks, CNN)与深度学习作为人工智能领域的两大重要分支,其发展历程充满了探索与突破。深度学习,作…...
初识 Floodfall 算法
文章目录 **一、Floodfall 算法的概述****二、深度优先搜索(DFS)和广度优先搜索(BFS)在 Floodfall 算法中的应用****三、算法的基本原理****四、应用场景** 一、Floodfall 算法的概述 Floodfall 算法通常用于解决与区域填充、图的…...
[Linux] LVM挂载的硬盘重启就掉的问题解决
问题:系统重启后挂在逻辑卷的盘会掉(必现) 环境:SUSE Linux 11 SP4 原因:boot.lvm是关闭的 解决:boot.lvm设置开启 参考资料: linux下lvm状态Not avaliable问题排查及处理(常见Suse操作系统…...
YOLOv8改进 | 主干网络 | 用EfficientNet卷积替换backbone【教程+代码 】
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有80+篇内容,内含各种Head检测头、损失函数Loss、…...
数据库规范化设计 5大基本原则
规范化设计原则是数据库设计的基本原则,有助于减少数据冗余,提高数据一致性和完整性,简化数据管理,增强数据安全性,对整个开发项目至关重要。而缺乏规范化设计会导致数据冗余,增加存储成本,引发…...
【nginx】解决k8s中部署nginx转发不会自动更新域名解析启动失败的问题
文章目录 1. 问题2.解决办法3.扩展说明3.1 DNS解析阶段划分3.2 问题说明3.2.1 先看/etc/resolv.conf说明3.2.2 针对第一个问题3.2.3 针对第二个问题 【后端】NginxluaOpenResty高性能实践 参考: https://blog.csdn.net/u010837612/article/details/123275026 1. 问…...
Redis分布式锁进阶第二十篇
一、本篇前置衔接 第二十篇我们完成了全系列终局复盘,整理了故障排查SOP与企业级落地铁律。常规单资源锁、热点分片锁、隔离锁全部讲透,但真实复杂业务永远不是单一资源:下单要扣库存、扣优惠券、扣积分、冻结余额,多资源并行争抢…...
双系统Ubuntu磁盘告急?别重装!用GParted无损扩容保姆级教程(附U盘启动盘制作)
双系统Ubuntu磁盘告急?别重装!用GParted无损扩容保姆级教程(附U盘启动盘制作)当你在Windows和Ubuntu双系统环境下工作时,是否遇到过这样的窘境:当初安装时给Ubuntu分配的空间捉襟见肘,而Windows…...
光轮智能 谢晨 访谈总结机器人仿真数据产业
光轮智能 谢晨 访谈总结机器人仿真关于创始人关于数据数据金字塔数据痛点仿真数据的重要性仿真数据的质量b站链接地址公司官网关于创始人 清华物理;哥伦比亚金融;英伟达智驾仿真;小鹏智驾仿真;现为光轮智能CEO 关于数据 数据的…...
Unity动态自然系统:Forest Environment-Dynamic Nature深度解析
1. 这不是“贴图堆砌”,而是自然系统级建模:Forest Environment-Dynamic Nature 的真实定位你有没有试过在Unity里拖进几棵树、铺点草、加个天空盒,然后发现场景像一张静止的风景明信片——风不动、叶不摇、雨不落、雾不散?我做过…...
差分隐私GDP机制紧密度量化:从隐私剖面到∆度量的实践指南
1. 差分隐私GDP机制:从理论到实践,如何量化隐私保护紧密度在差分隐私(Differential Privacy, DP)的实际部署中,尤其是在机器学习的隐私保护训练(如DP-SGD)场景里,我们常常面临一个核…...
PCL 法向量夹角剔除错误匹配点对【2026最新版】
目录 一、 算法简介 1、主要函数 2、参考文献 二、 代码实现 三、 结果展示 四、 参考链接 博客长期更新,本文最新更新时间为:2026年5月24日。代码在PCL1.15.1中测试通过 一、 算法简介 在三维点云配准中,对应点(correspondence)的准确性直接决定了配准算法的精度和鲁棒性…...
企业内统一API网关与Taotoken聚合平台对接方案
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 企业内统一API网关与Taotoken聚合平台对接方案 在推进AI应用落地的过程中,许多中大型企业面临一个共同挑战:…...
Jetson Orin上TVA模型DLA精准卸载配置
重磅预告:本专栏将独家连载系列丛书《智能体视觉技术与应用》部分精华内容,该书是世界首套系统阐述“因式智能体”视觉理论与实践的专著,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“…...
基于Arduino UNO的真随机数生成与数据持久化在Tambola游戏机中的应用
1. 项目概述:用Arduino UNO打造一台全自动Tambola游戏机如果你玩过或者听说过Tambola(在印度非常流行的游戏,在欧美也叫Bingo或Housie),就知道它的核心玩法是主持人从一个装有数字球的容器中随机抽取号码,玩…...
终极指南:三步搞定Windows系统安卓APK文件安装,告别模拟器时代
终极指南:三步搞定Windows系统安卓APK文件安装,告别模拟器时代 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 还在为电脑无法直接运行手机应用…...
