我是靠谱客的博主 甜甜电话,最近开发中收集的这篇文章主要介绍linux内核中使用定时器,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、使用Linux 内核定时器
Linux 内核定时器采用系统时钟来实现, Linux 内核定时器使用很简单,只需要提供超时时间(相当于定时值)和定时处理函数即可,当超时时间到了以后设置的定时处理函数就会执行,和我们使用硬件定时器的套路一样,只是使用内核定时器不需要做一大堆的寄存器初始化工作。在使用内核定时器的时候要注意一点,内核定时器并不是周期性运行的,超时以后就会自动关闭,因此如果想要实现周期性定时,那么就需要在定时处理函数中重新开启定时器。 Linux 内核使用 timer_list 结构体表示内核定时器, timer_list 定义在文件include/linux/timer.h 中。具体步骤:
1、在设备结构体定义一个timer_list结构体

/* ad7606设备结构体 */
struct ad7606_dev{
 dev_t devid;			/* 设备号 	 */
 struct cdev cdev;		/* cdev 	*/
 struct class *class;    /* 类 		*/
 struct device *device;	/* 设备 	 */
 int major;				/* 主设备号	  */
 int minor;				/* 次设备号   */
 /*添加定时器*/
 int timeperiod; 		/* 定时周期,单位为ms */
 struct timer_list timer;/* 定义一个定时器*/
 spinlock_t lock;		/* 定义自旋锁 */
};

在设备初始化时初始化定时器

	/* 初始化timer,设置定时器处理函数,还未设置周期,所有不会激活定时器 */
	init_timer(&ad7606.timer);
	ad7606.timer.function = timer_function;   //定时中断函数
	ad7606.timer.data = (unsigned long)&ad7606;
	return 0;

定时中断函数

void timer_function(unsigned long arg)
{
	struct ad7606_dev *dev = (struct ad7606_dev *)arg;
	int timerperiod;		//定时周期
	unsigned long flags;
	/*自己要实现的功能*/
	/*重启定时器*/
	spin_lock_irqsave(&dev->lock, flags);
	timerperiod = dev->timeperiod;
	spin_unlock_irqrestore(&dev->lock, flags);
	mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->timeperiod)); 
 }

在ioctl中即可控制定时器

static long timer_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	struct ad7606_dev *dev =  (struct ad7606_dev *)filp->private_data;
	int timerperiod;
	unsigned long flags;
	
	switch (cmd) {
		case CLOSE_CMD:		/* 关闭定时器 */
			del_timer_sync(&dev->timer);
			break;
		case OPEN_CMD:		/* 打开定时器 */
			spin_lock_irqsave(&dev->lock, flags);
			timerperiod = dev->timeperiod;
			spin_unlock_irqrestore(&dev->lock, flags);
			mod_timer(&dev->timer, jiffies + msecs_to_jiffies(timerperiod));
			break;
		case SETPERIOD_CMD: /* 设置定时器周期 */
			spin_lock_irqsave(&dev->lock, flags);
			dev->timeperiod = arg;
			spin_unlock_irqrestore(&dev->lock, flags);
			mod_timer(&dev->timer, jiffies + msecs_to_jiffies(arg));
			break;
		default:
			break;
	}
	return 0;
}

使用内核定时器的最大缺点是定时精度低,一般最小定时时间为一个系统节拍周期(通常为100HZ),随着内核升级,目前已经支持高精度内核定时器,由于本次实验的内核为3.0.15,虽然有高精度定时器,但仍有缺陷(参考其他博主的),接下来使用EPIT定时器
二、使用EPIT定时器
EPIT 的全称是: Enhanced Periodic Interrupt Timer,直译过来就是增强的周期中断定时器,它主要是完成周期性中断定时的。学过 STM32 的话应该知道, STM32 里面的定时器还有很多其它的功能,比如输入捕获、 PWM 输出等等。但是 I.MX6U 的 EPIT 定时器只是完成周期性中断定时的,仅此一项功能!至于输入捕获、 PWM 输出等这些功能, I.MX6U 由其它的外设来完成。EPIT 是一个 32 位定时器,在处理器几乎不用介入的情况下提供精准的定时中断,软件使能以后 EPIT 就会开始运行, EPIT 定时器有如下特点:
①、时钟源可选的 32 位向下计数器。
②、 12 位的分频值。
③、当计数值和比较值相等的时候产生中断。
EPIT定时器实现参考恩智浦的论坛
具体例子参考程序
使用EPIT要使能CCM在这里插入图片描述
EPIT中断号在mx6.h在这里插入图片描述
附:filp_open打开文件时的标志位
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_APPEND 追加
O_CREAT 创建
O_EXEC 如果使用了O_CREAT且文件存在,就会发生一个错误
O_NOBLOCK 以非阻塞方式打开一个文件
O_TRUNC 如果文件已经存在,则删除文件的内容
O_RDONLY O_WRONLY O_RDWR 只能使用其中一个。不能同时使用多个

最后

以上就是甜甜电话为你收集整理的linux内核中使用定时器的全部内容,希望文章能够帮你解决linux内核中使用定时器所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(74)

评论列表共有 0 条评论

立即
投稿
返回
顶部