• 第6课.定时器


    1.简介

    内核通过定时器中断来跟踪时间流。
    定时器中断的中断间隔由内核根据HZ的值设定,HZ是一个与体系结构有关的常数默认HZ值范围为50~1200,而对软件仿真器的HZ值是24.大多数平台每秒有100或1000次时钟中断。
    每次当时钟中断发生时,内核内部计数器的值就增加一。这个计数器的值在系统引导时,被初始化为0,因此,它的值就是自上次操作系统引导以来的时钟滴答数。这个计数器是一个64位的变量(即使在32位架构上也是64位),称为"jiffies_64",但是,驱动程序开发者通常访问的是jiffies变量,它是unsigned long型的变量,要么和"jiffies_64"相同,要么仅仅是jiffes_64的低32位。通常首先使用jiffies,因为对它的访问很快,从而对64位jiffes_64值的访问并不需要在所有架构上都是原子的

    2.使用jiffes计数器

    该计数器和读取计数器的工具函数包含在<linux/jiffies.h>中,但是通常只需要包含<linux/sched.h>文件,后者会自动放入jiffies.h。还需要说明的是,jiffies和jiffies_64均应该被看成只读变量。包含param.h时,HZ宏始终被扩展为100。

    3.常用函数

    // timer_list的数据结构
    struct timer_list timer;	    
    
    // 初始化timer_list结构体
    void init_timer(struct timer_list * timer) 
    
    // 注册定时器结构,以在当前CPU上运行
    void add_timer(struct timer_list *timer)
    
    // 修改一个已经调度的定时器结构的到期时间。它也可以替代add_timer函数使用
    int mod_timer(struct timer_list *timer, unsigned long expires)
    

    4.代码解析

    Makefile

    KERN_DIR = /work/system/linux-2.6.22.6
    
    all:
    	make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order
    
    obj-m	+= buttons.o
    

    buttons.c

    static struct timer_list buttons_timer;
    
    static irqreturn_t buttons_irq(int irq, void *dev_id)
    {
    	/* 10ms后启动定时器 */
    	irq_pd = (struct pin_desc *)dev_id;
    	mod_timer(&buttons_timer, jiffies+HZ/100);
    	return IRQ_RETVAL(IRQ_HANDLED);
    }
    
    static void buttons_timer_function(unsigned long data)
    {
    	struct pin_desc * pindesc = irq_pd;
    	unsigned int pinval;
    
    	if (!pindesc)
    		return;
    	
    	pinval = s3c2410_gpio_getpin(pindesc->pin);
    
    	if (pinval)
    	{
    		/* 松开 */
    		key_val = 0x80 | pindesc->key_val;
    	}
    	else
    	{
    		/* 按下 */
    		key_val = pindesc->key_val;
    	}
    
        ev_press = 1;                  /* 表示中断发生了 */
        wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
    	
    	kill_fasync (&button_async, SIGIO, POLL_IN);
    }
    
    static int sixth_drv_init(void)
    {
    	init_timer(&buttons_timer);
    	buttons_timer.function = buttons_timer_function;
    	//buttons_timer.expires  = 0;
    	add_timer(&buttons_timer); 
    
    	major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);
    
    	sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");
    
    	sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
    
    //	gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    //	gpfdat = gpfcon + 1;
    
    	return 0;
    }
    
    解析:    HZ:表示1s
        HZ / 1000 = 1 / 100 = 10ms
    

    buttons_test.c

    int fd;
    
    void my_signal_fun(int signum)
    {
    	unsigned char key_val;
    	read(fd, &key_val, 1);
    	printf("key_val: 0x%x
    ", key_val);
    }
    
    int main(int argc, char **argv)
    {
    	unsigned char key_val;
    	int ret;
    	int Oflags;
    
    	//signal(SIGIO, my_signal_fun);
    	
    	fd = open("/dev/buttons", O_RDWR);
    	if (fd < 0)
    	{
    		printf("can't open!
    ");
    		return -1;
    	}
    
    	//fcntl(fd, F_SETOWN, getpid());
    	
    	//Oflags = fcntl(fd, F_GETFL); 
    	
    	//fcntl(fd, F_SETFL, Oflags | FASYNC);
    
    
    	while (1)
    	{
    		ret = read(fd, &key_val, 1);
    		printf("key_val: 0x%x, ret = %d
    ", key_val, ret);
    		//sleep(5);
    	}
    	
    	return 0;
    }
  • 相关阅读:
    1月10日 TextView
    1月9日 布局2
    30 Adapter适配器
    29 个人通讯录列表(一)
    28 ListView控件
    27 登录模板
    26 Activity的启动模式
    25 Activity的生命周期
    24 得到Activity返回的数据
    23 Activity的传值2(bundle)
  • 原文地址:https://www.cnblogs.com/huangdengtao/p/12504793.html
Copyright © 2020-2023  润新知