Linux内核定时器timer_list
Linux内核版本:linux-3.0.35
开发板:i.MX6S MY-IMX6-EK200
拟定任务:LED闪烁
声明:嵌入式新手,如有错误还望指正,谢谢!
一、简单介绍一下定时器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_STATS int start_pid; void *start_site; char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map;
#endif
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
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);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
最终实现LED灯的闪烁,亲测可行!
文章来源: jackcui.blog.csdn.net,作者:Jack-Cui,版权归原作者所有,如需转载,请联系作者。
原文链接:jackcui.blog.csdn.net/article/details/50915449
- 点赞
- 收藏
- 关注作者
评论(0)