当前位置: 代码网 > 服务器>服务器>Linux > 驱动开发(五):Linux内核定时器

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

2024年08月03日 Linux 我要评论
定时的本质是计时,计时的本质是计数。LInux内核定时器是一种基于未来时间点的计时方式,以当前时刻来启动的时间点,以未来的某一时刻为终止点。因此,我们要实现定时需要两个值,一个是当前时刻值(起始时间),一个是目标时间值(触发中断时间)
 驱动开发相关文章:

驱动开发(一):驱动代码的基本框架

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

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

驱动开发(六):应用层通过文件系统与内核层交互

目录

定时器介绍

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

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

定时器的使用 

1.声明一个定时器 

2.初始化定时器

 3.启动定时器

   3.1添加定时器

   3.2使用定时器

4.删除定时器

参考代码


定时器介绍

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

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

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

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

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

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

 在内核顶层目录下使用 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_stats
	int start_pid;
	void *start_site;
	char start_comm[16];
#endif
#ifdef config_lockdep
	struct 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");

现象: 

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com