Linux内核定时器timer_list怎么用,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
一、简单介绍一下定时器timer_list:
1、所在头文件:linux/timer.h
2、结构体:
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};
3、主要成员介绍:
list 实现的时候使用的,和定时器功能无关;
expires 是定时器定时的滴答数(当前的滴答数为jiffies);
void (*function)(unsigned long) 定时器超时处理函数;
data 传递到超时处理函数的参数,主要在多个定时器同时使用时,区别是哪个timer超时。
4、提供的API接口:
a、init_timer(struct timer_list*):定时器初始化函数;
b、add_timer(struct timer_list*):往系统添加定时器;
c、mod_timer(struct timer_list *, unsigned long jiffier_timerout):修改定时器的超时时间为jiffies_timerout;
d、timer_pending(struct timer_list *):定时器状态查询,如果在系统的定时器列表中则返回1,否则返回0;
e、del_timer(struct timer_list*):删除定时器。
5、使用方法:
a、创建定时器时需要先定义struct timer_list my_timer;
b、在file_operation指定的open函数中初始化定时器init_timer(&my_timer);
c、在超时处理函数结尾重新加载定时器时间mod_timer(&my_timer,HZ);
d、如果自己编写的驱动中有中断,需要在中断入口处del_timer(&my_timer);并且在入口处重新重新加载定时器时间mod_timer(&my_timer,HZ)。
二、实例演示:
1、驱动程序代码:
#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/delay.h> /*delay*/#include <linux/cdev.h>#include <linux/device.h>#include <linux/slab.h> /*kmalloc*/#include <linux/vmalloc.h> /*vmalloc*/#include <linux/types.h> /*ssize_t*/#include <linux/fs.h> /*file_operaiotns*/#include <linux/gpio_keys.h>#include <linux/gpio.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/uaccess.h>/************硬件相关*************/#include <mach/iomux-mx6dl.h> /*普通IO*/#define LED IMX_GPIO_NR(1,15) /*SD2_DAT0*/ /*分配内存空间大小*/#define WRITE_MALLOC_SIZE 4096/**主设备号和次设备号**/#define DEVICE_MAJOR 102#define DEVICE_MINOR 0/*缓存区指针,指向内存区*/static char *led_spvm;/*在/sys目录创造一个类*/static struct class *led_class;
/*在这个类下,创造一个设备节点*/static struct cdev *led_class_dev;/*定义定时器结构体*/static struct timer_list timer;
typedef unsigned short int unit; /*2个字节,16bit*//*超时函数声明*/void mytimeout(void);
/*定时器初始化函数*/void mytimer_init(void)
{
init_timer(&timer); /*初始化定时器*/
timer.expires = jiffies + HZ; /*设置超时时间为1S*/ timer.function = mytimeout; /*设置超时之后中断服务子程序入口*/add_timer(&timer); /*启动定时器*/}/*open函数的实现*/static int led_open(struct inode *inode, struct file *file)
{/*定时器初始化*/mytimer_init();return 0;
}/*release函数的实现*/static int led_close(struct inode *inode, struct file *file)
{ /*释放占用的资源*/gpio_free(LED);/*删除定时器*/del_timer(&timer);/*打印提示退出信息*/printk(KERN_ALERT"LED is closed!\n");return 0;
}/*具体的文件操作集合*/static const struct file_operations led_fops =
{/*这是拥有者*/.owner = THIS_MODULE,
.open = led_open,
.release = led_close,
};/*超时中断服务子函数*/void mytimeout(void)
{ /*LED闪烁*/__gpio_set_value(LED,1);
mdelay(1000);
__gpio_set_value(LED,0);/*重新设置定时时间为1s*/mod_timer(&timer,jiffies + HZ);
}/*驱动的初始化函数*/static int led_init(void)
{/*设备初始化*/int devno,error;/*设备号的申请,创建*/devno = MKDEV(DEVICE_MAJOR,DEVICE_MINOR);/*分配设备结构体的地址空间*/led_spvm = (char *)vmalloc(WRITE_MALLOC_SIZE);
led_class_dev = cdev_alloc();/*字符设备初始化,绑定相关操作到设备*/cdev_init(led_class_dev,&led_fops);/*设备的拥有者*/led_class_dev->owner = THIS_MODULE;/*添加设备到内核*/cdev_add(led_class_dev,devno,1);/*静态申请设备号*/register_chrdev(DEVICE_MAJOR,"led",&led_fops); /*创建设备类,用于自动创建设备文件*/led_class = class_create(THIS_MODULE, "led"); /*依据以前创建的设备类,创建设备*/device_create(led_class,NULL,MKDEV(DEVICE_MAJOR,DEVICE_MINOR),NULL,"led"); /*申请gpio*/error = gpio_request(LED,"gpio");if (error < 0)
{
printk(KERN_ALERT"failed to request GPIO LED\n");goto fail1;
}/*设置IO方向为输出*/error = gpio_direction_output(LED,0);if (error < 0)
{
printk(KERN_ALERT"failed to configure direction for LED\n");goto fail2;
}return 0;
fail1:return error;
fail2:
gpio_free(LED);
}/*退出函数*/static void led_exit(void)
{/*定时器卸载*/
del_timer(&timer); /*设备卸载*/unregister_chrdev(DEVICE_MAJOR,"led");
device_destroy(led_class,MKDEV(DEVICE_MAJOR,DEVICE_MINOR));
class_destroy(led_class);
}/*LICENSE信息*/MODULE_LICENSE("GPL");/*卸载和加载*/module_init(led_init);
module_exit(led_exit);
2、测试程序代码:
#include <sys/types.h>#include <sys/stat.h>#include <stdio.h>#include <unistd.h>#include <fcntl.h>int main(int argc,char **argv)
{ int fd;/*对应加载进去的设备名:dev/led*/fd = open("/dev/led",O_RDWR);/*如果打开设备出错,打印信息*/if (fd < 0)
{printf("can`t open fd_write!\n");
}while(1)
{
sleep(1000);
}/*退出时候,关闭设备*/close(fd);
}
看完上述内容,你们掌握Linux内核定时器timer_list怎么用的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/4890645/blog/4807077