第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\n", 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!\n");
		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\n", key_val, ret);
		//sleep(5);
	}
	
	return 0;
}
posted @ 2020-03-16 16:37  人民广场的二道贩子  阅读(171)  评论(0编辑  收藏  举报