linux定时器使用指南及实例

本文简述如何使用linux里的定时器,包括周期性中断,停止和启动的控制。

日常常用的几个定时器相关linux API函数:

  1. init_timer(); 初始化定时器
  2. add_timer(); 启动定制器
  3. del_timer();停止定时器
  4. mod_timer(); 重新修改定时器当前计数时间

这些API位于:kernel\timer.c中,该源文件里还包括了常用的msleep(),schedule_timeout()等常用的延时调度函数。

下面以一个实例驱动介绍linux里的timer的使用(基于3.10.0-123内核)。


案例如下:

  1. 创建一定时器,完成每3s一次周期性中断并打印。
  2. 通过字符设备接口与用户层交互,写0则关闭(停止)定时器,写1则开启(启动)定时器
    (即:当echo 1 >/dev/demo_deva启动定时器,当echo 0 >/dev/demo_deva 停止定时器)。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/device.h> 
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include "timer_drv.h"

/*
功能:
	定时器3秒定时中断一次打印。
	当echo 1 >/dev/demo_deva开启定时器,当echo 0 >/dev/demo_deva 关闭定时器
*/

#define DRV_VERSION  "V1.0"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LUDY");
MODULE_DESCRIPTION("This is timer demo");
MODULE_VERSION(DRV_VERSION);

//static volatile int time_count = 0;
static void handel_irq_do_timer(unsigned long arg);
u8 delay = 3; //3s
/* 设备要使用的定时器 */
static struct timer_list my_timer;//也可以:TIMER_INITIALIZER(handel_irq_do_timer, 0, 0); 直接快速初始化结构体内容

/* 定时器中断处理函数 */
static void handel_irq_do_timer(unsigned long arg)
{
	// struct xxx_device *dev = (struct xxx_device *)(arg);
	/* 修改调度定时器,3s再执行 */
	mod_timer(&my_timer, jiffies + delay*HZ); //*HZ即转换成jiffies单位值
	printk("timer arrival\n");
}

/* 定时器初始化*/
void timer_init_run(void* pri_data)
{

	//device *dev =  (device*)pri_data;
    /* 初始化定时器 */
    init_timer(&my_timer);   
	/* 设备结构体指针作为定时器处理函数参数 */
    my_timer.function = &handel_irq_do_timer; //中断处理函数
	my_timer.expires =  delay*HZ;  //定时时间delay秒  
    //my_timer.data = (unsigned long)dev;
}

/*
写函数;
定时器启动和停止控制
*/
ssize_t  demodrv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	char rev_data;
      /*只接受一个字符的写入*/
	if(count >2)  //count包括了/0字符
		return -EFAULT;
	//copy_from_user(rev_data1, buf, count);
	if(get_user(rev_data, buf))
	{
		return -EFAULT;
	}
	printk("driver: device write:%c  count:%d\n" ,rev_data, count);

	switch(rev_data)
	{
		case '0':
		    /* 删除(停止)定时器 */
			del_timer(&my_timer);
			break;
		case '1':
			/* 添加(注册) 启动定时器 */
			add_timer(&my_timer);  //add添加后,定制器开始运行
			break;
		default:
			PRINT_ERR("write EINVAL:%c\n" ,rev_data);
			break;
	}
	return count;
}


ssize_t demodrv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	return 1;
}

static int demodrv_open(struct inode *inode, struct file *file)
{
	printk("driver: device open\n");
	return 0;
}


int demodrv_close(struct inode *inode, struct file *file)
{
	printk("driver: device close\n");
	return 0;
}


static struct file_operations demo_drv_fops = {
    .owner   =  THIS_MODULE, 
    .open    =  demodrv_open,     
	.read	 =	demodrv_read,
	.write	 =	demodrv_write,		
	.release =  demodrv_close,
};

int major;
static struct class *demo_drv_class;
static struct class_device	*demo_class_dev;

static int __init demo_drv_init(void)
{
	major = register_chrdev(0, "demo_drv", &demo_drv_fops);//注册字符驱动获取设备号
	demo_drv_class = class_create(THIS_MODULE, "demo_drv_class"); //sys/class下创建类
	demo_class_dev = device_create(demo_drv_class, NULL, MKDEV(major, 0), NULL, "demo_dev"); /*类下创建设备文件绑定到设备号 /dev/demo_dev */

	timer_init_run(demo_class_dev);
	return 0;
}


static void __exit demo_drv_exit(void)
{
	unregister_chrdev(major, "demodrv");
	device_unregister(demo_class_dev);
	class_destroy(demo_drv_class);
    /* 删除(停止)定时器 */
    del_timer(&my_timer);

	return 0;
}
module_init(demo_drv_init);
module_exit(demo_drv_exit);

如上源码可知,使用一个定时器通常需要如下步骤:

  1. 定义一个timer_list 结构体的定时器对象。并可以通过TIMER_INITIALIZER快速赋值对象里的成员(中断函数;定时时间等);
  2. init_timer 初始化该定制器(此时定时器还不能走);
  3. 可以自定义为定时器对象里的成员赋值(中断函数;定时时间;私有数据等);
  4. add_timer 启动该定时器,定时器开始倒计时;
  5. mod_timer 修改当前定时器的数值(复位定时器);
  6. 如果要停止(删除)一个定时器,执行del_timer,需要重新启动则继续执行add_timer。
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux系统提供了多种方法实现定时器,其中常用的有以下两种方式: 1. 使用系统调用函数 setitimer() setitimer() 函数可以设置定时器,它有三个参数:定时器类型、定时器的初始值和定时器的重载值。使用该函数需要引入头文件 <sys/time.h>。 示例代码: ``` #include <sys/time.h> #include <signal.h> #include <stdio.h> #include <unistd.h> void timer_handler(int signum) { printf("Timer expired.\n"); } int main() { struct sigaction sa; struct itimerval timer; /* 安装信号处理器 */ sa.sa_handler = timer_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM, &sa, NULL); /* 设置定时器 */ timer.it_value.tv_sec = 5; /* 初始值为5秒 */ timer.it_value.tv_usec = 0; timer.it_interval.tv_sec = 1; /* 重载值为1秒 */ timer.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &timer, NULL); /* 等待定时器触发 */ while (1) { sleep(1); } return 0; } ``` 2. 使用Linux内核提供的定时器接口 Linux内核提供了一组定时器接口,可以用于实现高精度、高可靠性的定时器。使用该定时器需要引入头文件 <linux/timer.h>。 示例代码: ``` #include <linux/timer.h> #include <linux/jiffies.h> #include <linux/module.h> static struct timer_list my_timer; void my_timer_callback(unsigned long data) { /* 定时器到期时执行的函数 */ printk("Timer expired.\n"); /* 重新设置定时器 */ mod_timer(&my_timer, jiffies + msecs_to_jiffies(5000)); } int init_module() { /* 初始化定时器 */ init_timer(&my_timer); my_timer.function = my_timer_callback; my_timer.expires = jiffies + msecs_to_jiffies(5000); /* 初始值为5秒 */ add_timer(&my_timer); return 0; } void cleanup_module() { /* 删除定时器 */ del_timer(&my_timer); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值