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
};
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);
}
最終實現LED燈的閃爍,親測可行!