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. 问…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
