驱动开发(五):Linux内核定时器

 驱动开发系列文章:
                驱动开发(一):驱动代码的基本框架    
                驱动开发(二):创建字符设备驱动
                驱动开发(三):内核层控制硬件层 

                驱动开发(四):Linux内核中断

                驱动开发(五):Linux内核定时器

目录

定时器介绍

定时器的当前时间如何获取?

定时器加1代表走了多长时间?

定时器的使用 

1.声明一个定时器 

2.初始化定时器

 3.启动定时器

   3.1添加定时器

   3.2使用定时器

4.删除定时器

参考代码


定时器介绍

在大部分操作系统中,系统时钟是由计算机硬件提供的。它通常以固定的频率发送时钟信号给计算机的中央处理器(CPU)。这个时钟信号会被操作系统内核接收并用于计算时间。操作系统通过不断监视系统时钟的变化来进行时间的跟踪,从而实现定时功能。

Linux内核中的定时器是一种机制,用于在一定的时间间隔或特定的时间点执行某个任务或触发某个事件。定时器在内核中广泛使用,用于实现各种功能,如任务调度、延迟处理、超时处理等。

定时的本质是计时,计时的本质是计数。LInux内核定时器是一种基于未来时间点的计时方式,以当前时刻来启动的时间点,以未来的某一时刻为终止点。

因此,我们要实现定时需要两个值,一个是当前时刻值(起始时间),一个是目标时间值(触发中断时间)

定时器的当前时间如何获取?

jiffies:内核当前时钟节拍数

jiffies是在板子上电这一刻开始计数,只要板子不断电,这个值一直在增加(64位)。在驱动代码中直接使用即可。

定时器加1代表走了多长时间?

Linux内核会使用CONFIG_HZ来设置自己的系统时钟。

在内核顶层目录下有.config

Kconfig(组成菜单) ---->menuconfig(配置) ------>.config(最终) 可以直接改.config

CONFIG_HZ=1000

周期 = 1/CONFIG_HZ

所以每加一个数是加1ms;

 在内核顶层目录下使用 vi .config 

定时器的使用 

 内核提供了一个封装好的结构体 struct timer_list 用来表示定时器。

struct timer_list 结构体里的内容:

struct timer_list {/** All fields that change during normal runtime grouped to the* same cacheline*/struct list_head entry;  unsigned long expires;    //定时到的时间struct tvec_base *base;void (*function)(unsigned long);  //定时器的处理函数unsigned long data;       //向定时器处理函数中填写的值int slack;#ifdef CONFIG_TIMER_STATSint start_pid;void *start_site;char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEPstruct lockdep_map lockdep_map;
#endif
};

1.声明一个定时器 

可以使用内核给你提供的这个接口直接声明自己的定时器。声明定时器的数量没有限制,想开几个开几个。

struct timer_list mytimer;    //声明一个结构体变量

2.初始化定时器

声明完之后还需要对结构体的基本内容进行填充

mytimer.expires = jiffies + 1000;  //1s
mytimer.function = timer_function;  //名字叫timer_function的中断处理函数
mytimer.data = 0;    void timer_function(unsigned long data) //定时器的处理函数
{}

 填完基本的参数之后,剩下的可以交给内核自动填充

init_timer(&mytimer);  //内核帮你填充你未填充的对象	

 3.启动定时器

   3.1添加定时器

用于向Linux内核注册定时器。

同一个定时器只能被添加一次,在你添加定时器的时候定时器会先启动一次

void add_timer(struct timer_list *timer);
   3.2使用定时器

除了第一次开启定时器使用add_timer,其他时间再次使用定时器要使用mod_timer。

int mod_timer(struct timer_list *timer, unsigned long expires)
//再次启动定时器,参数unsigned long expires为定时时间

4.删除定时器

int del_timer(struct timer_list *timer)    //删除定时器

不管定时器有没有被激活,都可以使用此函数删除。

参考代码

 用定时器实现按键消抖

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/timer.h>#define GPIONO(m, n) m * 32 + n
#define GPIO_B8 (GPIONO(1, 8))
#define GPIO_B16 (GPIONO(1, 16))
int gpiono[] = {GPIO_B8, GPIO_B16};
char *name[] = {"gpio_it_8", "gpio_it_16"};
int ret;
int i;
struct timer_list mytimer;
irqreturn_t handler(int irqno, void *dev)
{mod_timer(&mytimer,jiffies + 10);return IRQ_HANDLED;
}
void timer_function(unsigned long data) //定时器的处理函数
{int B8 = gpio_get_value(GPIO_B8);int B16 = gpio_get_value(GPIO_B16);if (B8 == 0){printk(KERN_ERR "------------\n");}if (B16 == 0){printk(KERN_ERR "++++++++++++\n");}
}static int __init hello_init(void)
{mytimer.expires = jiffies + 10;mytimer.function = timer_function;mytimer.data = 0;init_timer(&mytimer);  //内核帮你填充你未填充的对象	add_timer(&mytimer);    //开启一次定时器for (i = 0; i < sizeof(gpiono) / sizeof(int); i++){ret = request_irq(gpio_to_irq(gpiono[i]), handler, IRQF_TRIGGER_FALLING, name[i], NULL);if (ret != 0){printk(KERN_ERR "%s request irq err\n", name[i]);return ret;}}return 0;
}
static void __exit hello_exit(void)
{for (i = 0; i < sizeof(gpiono) / sizeof(int); i++){free_irq(gpio_to_irq(gpiono[i]), NULL);}del_timer(&mytimer);
}module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

现象: 

 

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

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

相关文章

移动端超超超详细知识点总结(Part4)

rem基础 1. rem单位 rem (root em)是一个相对单位&#xff0c;类似于em&#xff0c;em是父元素字体大小。不同的是rem的基准是相对于html元素的字体大小。比如&#xff0c;根元素&#xff08;html&#xff09;设置font-size12px; 非根元素设置width:2rem;则换成px表示就是24p…

数据防泄漏的六个步骤|数据防泄漏软件有哪些

在当前复杂多变的网络安全环境下&#xff0c;数据防泄漏软件成为了企业信息安全架构中不可或缺的一环。下面以安企神软件为例&#xff0c;告诉你怎么防止数据泄露&#xff0c;以及好用的防泄露软件。 1. 安企神软件 安企神软件是当前市场上备受推崇的企业级数据防泄漏解决方案…

【ARM-Linux篇】智能家居语音模块配置

1. pin脚配置&#xff1a; 2. 命令词自定义基本信息&#xff1a; 3. 命令词自定控制详情: • 测试&#xff1a;串口模块可先通过串口助手验证每个指令的准确性&#xff0c; 然后运行wiringOP中的serialTest程序(需把/dev/ttyS2改成/dev/ttyS5) 然后语音接收到指令后(比如喊你好…

10大wordpress外贸主题

手动工具wordpress外贸模板 适合生产套筒扳、管钳、工具箱、斧子、锤子、防爆工具、螺丝刀、扳手等手动工具的厂家。 https://www.jianzhanpress.com/?p4806 Invisible Trade WP外贸网站模板 WordPress Invisible Trade外贸网站模板&#xff0c;做进出口贸易公司官网的word…

开源高效API管理工具:RAP

RAP&#xff1a;简化API开发&#xff0c;提升团队协作效率- 精选真开源&#xff0c;释放新价值。 概览 RAP&#xff08;RESTful API Project&#xff09;是一个开源的API管理工具&#xff0c;由阿里巴巴团队开发并维护。它旨在帮助前后端开发人员通过一个统一的平台来设计、开…

软件方案评审与模块优化:从FOC模块出发的电控平台建设

一、背景 洞悉模块发展趋势&#xff0c;定制行业应用特点&#xff0c;明确优化方向与阶段性目标 随着科技进步的飞速发展&#xff0c;模块化设计已成为众多行业产品开发的核心理念。无论是软件系统、硬件组件&#xff0c;还是复杂系统中的功能模块&#xff0c;都需要对其发展…

如何提高软件质量

你写的程序是否有这些问题&#xff1a;命名不规范、函数设计不合理、分层不清晰、没有模块化概念、代码结构混乱、高度耦合等等。只是为了完成功能&#xff0c;从来没有考虑过代码质量问题、代码设计问题。 这样的代码维护起来非常费劲&#xff0c;添加或者修改一个功能&#…

Vue部分文件说明

1.eslintignore文件 Eslint会忽略的文件 # Eslint 会忽略的文件.DS_Store node_modules dist dist-ssr *.local .npmrc 2.gitignore # Git 会忽略的文件.DS_Store node_modules dist dist-ssr .eslintcache# Local env files *.local# Logs logs *.log npm-debug.log* yarn-de…

不可不知的Java SE技巧:如何使用for each循环遍历数组

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

HTML+CSS 旋转呼吸加载器

效果演示 实现了一个旋转加载动画效果&#xff0c;包括一个圆形的加载框和两个不同颜色的圆形旋转动画。加载框和动画都使用了CSS的动画属性&#xff0c;实现了旋转和缩放的效果。整个加载动画的样式比较简单&#xff0c;使用了黑色和黄色的背景色&#xff0c;以及白色的文本颜…

基于SVD的点云配准(下)

点云配准及特征提取详细解读 本篇博客将介绍一个用于点云配准的 C++ 代码示例,该示例使用 PCL(Point Cloud Library)库来处理和配准两个点云数据集。我们将逐步解析代码的关键部分,并解释每个步骤的作用。 代码说明 代码的整体结构及其主要功能: int main(int argc, ch…

【C++】【期末考】【基本概念和语法】概括总结——期末速成

目录 1. C简介 C的历史与发展 C的特点与优势 2. 基本语法 注释 数据类型与变量 常量 运算符 输入与输出 3. 控制结构 条件语句 循环语句 4. 函数 函数定义与声明 参数传递 返回值 函数重载 5. 数组与字符串 一维数组 多维数组 字符串处理 6. 指针 指针的…

本地部署 Stable Diffusion3

6月13日&#xff0c;Stability AI 正式开源20亿参数版本的Stable Diffusion 3 Medium。本文将在本地部署 SD3&#xff0c;GPU配置如下 GPU 2080TI / 22G 安装依赖 修改 WORKSPACE 位置信息&#xff0c;安装ComfyUI # #title Environment Setupfrom pathlib import PathOPTIO…

SoftReference 到底在什么时候被回收 ? 如何量化内存不足 ?

本文基于 OpenJDK17 进行讨论&#xff0c;垃圾回收器为 ZGC。 提示&#xff1a; 为了方便大家索引&#xff0c;特将在上篇文章 《以 ZGC 为例&#xff0c;谈一谈 JVM 是如何实现 Reference 语义的》 中讨论的众多主题独立出来。 大家在网上或者在其他讲解 JVM 的书籍中多多少少…

关于QTcreator,19年大学时写的文章了,之前写在印象笔记现在拉过来,往事如烟呐

1.初来乍到&#xff0c;先按照书本写一个基础列程理解一下原理。 这里创建工程的时候选择Qdialog基类&#xff0c;dialog.h头文件&#xff0c;并且勾选了创建界面 &#xff08;勾选之后可以通过手动添加组块并且可以自生成他们的函数定义&#xff0c;如果没有勾选&#xff0c;…

聊天页面样式

聊天页面样式 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><link rel"styleshee…

C++程序员笔试训练

面试题1&#xff1a;使用库函数将数字转换位字符串 考点&#xff1a;c语言库函数中数字转换位字符串的使用 char *gcvt(double number, int ndigit, char *buf);参数说明&#xff1a; number&#xff1a;待转换的double类型数值。 ndigit&#xff1a;保留的小数位数。 buf&am…

数智教育创新如何向未来?腾讯云与你探索革新之路

引言 随着科技革命的快速发展&#xff0c;掀起教育领域的变革&#xff0c;新理念、新技术、新模式、新应用正不断涌现&#xff0c;正塑造着教育的未来形态。未来科技还将如何赋能教育创新&#xff1f; 5月31日&#xff0c;由腾讯云TVP 与西安电子科技大学联合举办的「数智教育的…

LC1020:飞地的数量

题目 给你一个大小为 m x n 的二进制矩阵 grid &#xff0c;其中 0 表示一个海洋单元格、1 表示一个陆地单元格。 一次 移动 是指从一个陆地单元格走到另一个相邻&#xff08;上、下、左、右&#xff09;的陆地单元格或跨过 grid 的边界。 返回网格中 无法 在任意次数的移动…

C++访问Private,Protecd的一些方法总结

前言 在编写C程序中 我们偶尔会碰到这样的三种特殊修改变量值的需求&#xff1a; [1]在不修改类原本的实现下&#xff0c;访问修改类的Private变量 [2]在不修改类原本的实现下&#xff0c;修改类的Protected变量 Private变量访问 public类模版函数特化 这种办法利用了类模…