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灯的闪烁,亲测可行!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Linuxer的专栏

宋宝华:LEP ( Linux 易用剖析器 ) 是什么,为什么以及怎么办 ( 1 )

LEP是 Linuxer 之 LEP 项目组(Barry Song,Mac Xu,陈松等以及陈莉君老师)正在致力于打造的一个开源项目,本文是 LEP 文档《 L...

52100
来自专栏邹立巍的专栏

Linux 的进程间通信:文件和文件锁

我们首先引入文件进行 IPC ,试图先使用文件进行通信引入一个竞争条件的概念,然后使用文件锁解决这个问题,从而先从文件的角度来管中窥豹的看一下后续相关 IPC ...

1.3K00
来自专栏郑剑的专栏

linux 内存管理初探

本文主要介绍 linux 内存组织结构和页面布局,内存碎片产生原因和优化算法,linux 内核几种内存管理的方法,内存使用场景以及内存使用的那些坑。

2.6K90
来自专栏云加头条

Linux Kernel 4.11 发布

4月30日,Linus Torvalds 在内核邮件列表上宣布释出 Linux Kernel 4.11。

25000
来自专栏莫韵的专栏

linux 根分区的空间去哪里了 ?记一次根分区满的服务故障排查记录

linux 根分区的空间去哪里了 ?记一次根分区满的服务故障排查记录。我的排查思路是先找占用没有占用,找占用的文件句柄。

1.5K00
来自专栏Linuxer的专栏

吴锦华 / 明鑫 : 用户态文件系统 ( FUSE ) 框架分析和实战

用户态文件系统(filesystem in userspace, 简称 FUSE),它能使用户在无需编辑和编译内核代码的情况下,创建用户自定义的文件系统。

1.6K10
来自专栏张戈的专栏

【ES私房菜】收集 Linux 系统日志

ES环境已经就绪,我们需要先调通一类简单日志作为数据上报全链路的试运行。恰好Linux系统日志就是这样一个角色,随处可见,风险可控。这里,我们选择了2种Linu...

1K10
来自专栏刘远飞的专栏

CentOS6.5系统yum安装LAMP环境

采用Linux下二进制模式来安装LAMP,适合初学者,测试使用。

87500
来自专栏潘嘉兴的专栏

手把手教你如何优化linux服务器

服务器的优化是我们最小化安装系统后应该做的事情,下面是一些常见的基本的优化服务器的方法。关闭不需要的服务。列出需要启动的的服务crond、network、ssh...

68700
来自专栏皮振伟的专栏

linux、pthread、qemu 的一次 pthread create 失败的分析

qemu 因为 pthread create 失败而发生了 crash 。这种类型的问题比较少见,这里记录一下问题的分析过程以及解决思路。

55300

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励