定时器功能:仅定时
判断计数周期eg:
T=1/f=1s/200ms=5ms
定时:当前时间+未来时间段
定时器核心结构体:
unsigned long msecs_to_jiffies(const unsigned int m)
//将毫秒值转为节拍数
void add_timer(struct timer_list *timer)
//向内核添加定时器,仅生效一次
mod_timer(timer, expires) is equivalent to:
del_timer(timer); timer->expires = expires; add_timer(timer);
poll
利用等待队列 实现阻塞,此时阻塞在内核层
借助 poll 可以阻塞在应用层
应用层:多路 IO 复用 select poll epoll
select 最多轮询 1024 个描述符 支持跨平台
poll 没有个数的限制
epoll 没有个数的限制 内核回调机制 仅用于 linux
1)应用层:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
形参:nfds: struct pollfd 个数
timeout: 0 --- 非阻塞 >0 规定时间内轮询 单位:毫秒 -1 阻塞
2)内核层 poll
static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
函数功能:将文件描述符添加到内核轮询表中,放入等待队列
参数 filp 和 p 就是 poll 函数形参
poll 返回值给应用层 revents
例题,利用poll定时轮询查询按键中断
cdev.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/irq.h>
#define BASEMINOR 12
#define MINORCOUNT 4
#define MAJORNAME "MYKEY"
#define CLASSNAME "KEYtest"
#define DEVNAME "KEY_%d"
struct cdev cdev;
dev_t dev;
int ret = 0;
struct class *class;
struct timer_list time;
struct INFOR{
unsigned gpio;
unsigned int irq;
char *name;
int num;
struct timer_list time;
};
struct INFOR infor[]={
{EXYNOS4_GPX3(2),0,"key_1",1},
{EXYNOS4_GPX3(3),0,"key_2",2},
{EXYNOS4_GPX3(4),0,"key_3",3},
{EXYNOS4_GPX3(5),0,"key_4",4}
};
int condition = 0;
int key[4];
DECLARE_WAIT_QUEUE_HEAD(wq);
irqreturn_t key_irq_handler(int irqnum, void *arg)
{
int num = (int)arg-1;
mod_timer(&infor[num].time,jiffies+msecs_to_jiffies(40));
return IRQ_HANDLED;
}
void key_time_out(unsigned long arg)
{
condition |= 1<<arg;
wake_up_interruptible(&wq);
}
int key_open (struct inode *node, struct file *f)
{
int index = node->i_rdev - dev;
f->private_data = (void *)(infor[index].num);
gpio_request(infor[index].gpio,infor[index].name);
gpio_direction_input(infor[index].gpio);
infor[index].irq = gpio_to_irq(infor[index].gpio);
request_irq(infor[index].irq,key_irq_handler,IRQ_TYPE_EDGE_BOTH,infor[index].name,(void*)infor[index].num);
infor[index].time.expires = jiffies + msecs_to_jiffies(40);
infor[index].time.function = key_time_out;
infor[index].time.data = infor[index].num;
init_timer(&infor[index].time);
return 0;
}
int key_close (struct inode *node, struct file *f)
{
int index = node->i_rdev - dev;
free_irq(infor[index].irq,(void*)infor[index].num);
gpio_free(infor[index].gpio);
return 0;
}
ssize_t key_read (struct file *f, char __user *buf, size_t s, loff_t *l)
{
int key_num = (int)f->private_data;
int value[2]={key_num};
// wait_event_interruptible(wq, condition);
condition &= ~(1<<key_num);
value[1] = gpio_get_value(infor[key_num-1].gpio);
copy_to_user(buf, value, sizeof(value));
return 0;
}
unsigned int key_poll(struct file *f, struct poll_table_struct *table)
{
int num = (int)f->private_data;
poll_wait(f, &wq,table);
if(condition & (1<<((int)f->private_data)))
return POLLIN;
else
return 0;
}
struct file_operations ops={
.owner = THIS_MODULE,
.open = key_open,
.release = key_close,
.read = key_read,
.poll = key_poll
};
static int __init key_enter(void)
{
int i;
struct device *deviceRet = NULL;
cdev_init(&cdev,&ops);
ret = alloc_chrdev_region(&dev,BASEMINOR,MINORCOUNT,MAJORNAME);
if(ret < 0)
{
printk("申请设备号失败\n");
goto end;
}
ret = cdev_add(&cdev,dev,MINORCOUNT);
if(ret < 0)
{
printk("cdev_add failed\n");
goto ADDERR;
}
class = class_create(THIS_MODULE,CLASSNAME);
if(IS_ERR(class))
{
printk("class create failed\n");
ret = PTR_ERR(class);
goto CLASSERR;
}
for(i=0;i<MINORCOUNT;i++)
{
deviceRet = device_create(class,NULL,dev+i,NULL,DEVNAME,i);
if(IS_ERR(deviceRet))
{
printk("device create failed\n");
ret = PTR_ERR(deviceRet);
goto DEVERR;
}
}
return 0;
DEVERR:
for(i--;i>=0;i--)
device_destroy(class,dev+i);
class_destroy(class);
CLASSERR:
cdev_del(&cdev);
ADDERR:
unregister_chrdev_region(dev,MINORCOUNT);
end:
return ret;
}
static void __exit key_quit(void)
{
int i;
if(ret != 0)
return;
for(i=MINORCOUNT;i>=0;i--)
device_destroy(class,dev+i);
class_destroy(class);
cdev_del(&cdev);
unregister_chrdev_region(dev,MINORCOUNT);
}
module_init(key_enter);
module_exit(key_quit);
MODULE_LICENSE("GPL");
Makefile
obj-m +=cdev.o
KDIR = /home/fuck/桌面/linux-3.5
all:
make -C ${KDIR} M=${PWD} modules
arm-linux-gcc app.c -o app
clean:
make -C ${KDIR} M=${PWD} modules clean
rm app
app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <stdlib.h>
#include <signal.h>
struct pollfd fds[4];
void fun(int num)
{
int i;
for(i=0;i<4;i++)
{
close(fds[i].fd);
}
exit(0);
}
int main()
{
int i,ret,data[2];
char file[30];
signal(2,fun);
for(i=0;i<4;i++)//依次打开相应的文件设备
{
sprintf(file,"/dev/KEY_%d",i);
fds[i].fd = open(file,O_RDWR);
fds[i].events = POLLIN;
}
while(1)
{
ret = poll(fds,4,6000);
if(ret == 0)
{
printf("6s内按键没有变化\n");
}
else if(ret > 0)
{
for(i=0;i<4;i++)
{
if(fds[i].revents == POLLIN)
{
read(fds[i].fd,data,sizeof(data));
if(data[1]==0)
printf("*********%d 按键 按下*********\n",data[0]);
else if(data[1] == 1)
printf("@@@@@@@@@%d 按键 松开@@@@@@@@@\n",data[0]);
}
}
}
}
}