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 条评论
登录 后参与评论

相关文章

来自专栏抠抠空间

Django单元测试简单示例

对一个功能的验证往往是需要很多多测试用例,可以把测试用例集合在一起执行,这就产生了测试套件TestSuite 的概念,它是用来组装单个测试用例,规定用例的执行的...

654
来自专栏cloudskyme

虚拟化平台cloudstack(1)——介绍

什么是cloudstack CloudStack是一个开源的具有高可用性及扩展性的云计算平台。目前Cloudstack支持管理大部分主流的hypervisors...

3967
来自专栏上善若水

L012Linux和androidNDK之执行报错CANNOT LINK EXECUTABLE: cannot locate symbol "signal" referenced by

1723
来自专栏微信终端开发团队的专栏

Android 内存申请分析

做内存方面优化的工作过程,除了关注内存的申请量以及 GC 的情况之外,我们经常需要想方法找出是那些对象占用了大量内存,以及他们是如何导致 GC 的,这意味着我们...

2680
来自专栏Java技术分享圈

FastDFS的配置、部署与API使用解读(1)Get Started with FastDFS

转载请注明来自:诗商·柳惊鸿CSDN博客,原文链接:FastDFS的配置、部署与API使用解读(1)入门使用教程

753
来自专栏北京马哥教育

OpenStack与K8s结合的几种方案之比较

OpenStack与K8S结合主要有两种方案。一是K8S部署在OpenStack平台之上,二是K8S和OpenStack组件集成。

1696
来自专栏后端云

cyborg agent

Cyborg的需要一下功能:包括在计算机节点上管理代理,定位加速器,监控加速器状态和协调加速器驱动程序。

925
来自专栏云计算D1net

不只是编排引擎,OpenStack Heat之应用部署实践

作为OpenStack中的编排引擎,Heat能够出色的完成编排任务,井井有条地管理编排出来的资源。但同时,Heat也是一个出色的应用部署引擎,它提供了一套内置的...

3645
来自专栏梦里茶室

【Chromium中文文档】沙箱FAQ

什么是沙箱? 沙箱是一个允许沙箱进程创建的C++库,沙箱进程是一种运行在非常限制性的环境中的进程。沙箱进程可以唯一自由使用的资源是CPU周期和内存。例如,沙箱进...

19210
来自专栏Python自动化测试

Python接口测试之unittest(五)

Test-driven development(TDD)开发模式在今天已经不是什么新奇的事了,它的开发思维是在开发一个产品功能的时候,先编写好该功能...

693

扫码关注云+社区