05.Linux内核定时器
定时器的API¶
setup_timer(timer, fn, data);
设置定时器,主要是初始化 timer_list 结构体,设置其中的函数、参数。
void add_timer(struct timer_list *timer)
向内核添加定时器。timer->expires 表示超时时间。
当 超 时 时 间 到 达 , 内 核 就 会 调 用 这 个 函 数 :timer->function(timer->data)。
int mod_timer(struct timer_list *timer, unsigned long expires)
修改定时器的超时时间。
del_timer(struct timer_list *timer)
删除定时器
驱动编程¶
在初始化的时候
struct key_dev{
struct class *class;
struct device *device;
struct device_node *nd;
struct gpio_desc *gpiod;
struct timer_list timer;
int gpio;
int irq;
int major;
int minor;
};
static int gpio_key_probe(struct platform_device *pdev)
{
/*
初始化按键
*/
setup_timer(&key.timer, key_timer_expire, &key);
key.timer.expires = ~0;
add_timer(&key.timer);
/*
注册字符设备
*/
return 0;
}
每次按键中断的时候修改定时时间
static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
struct key_dev *gpio_key = dev_id;
mod_timer(&gpio_key->timer, jiffies + HZ/5);
return IRQ_HANDLED;
}
中断时间到了就到中断服务函数执行相关程序
static void key_timer_expire(unsigned long data)
{
/* data ==> gpio */
struct key_dev *gpio_key = (struct key_dev *)data;
int val;
val = gpiod_get_value(gpio_key->gpiod);
printk("key %d %d\n", gpio_key->gpio, val);
g_key = (gpio_key->gpio << 8) | val;
wake_up_interruptible(&gpio_key_wait);
kill_fasync(&button_fasync, SIGIO, POLL_IN);
}
新内核定时器的使用有不同,from_timer的功能是根据key_dev结构体中timer变量的位置推算出结构体的地址。
//setup_timer修改
timer_setup(&key.timer, key_timer_expire, 0);
//中断服务函数修改,获得数据的方式修改了
static void key_timer_expire(struct timer_list *t)
{
/* data ==> gpio */
struct key_dev *gpio_key = from_timer(key_dev, t, timer);
/*其他处理*/
}
应用编程¶
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>
static int fd;
/*
* ./button_test /dev/100ask_button0
*
*/
int main(int argc, char **argv)
{
int val;
struct pollfd fds[1];
int timeout_ms = 5000;
int ret;
int flags;
int i;
/* 1. 判断参数 */
if (argc != 2)
{
printf("Usage: %s <dev>\n", argv[0]);
return -1;
}
/* 2. 打开文件 */
fd = open(argv[1], O_RDWR | O_NONBLOCK);
if (fd == -1)
{
printf("can not open file %s\n", argv[1]);
return -1;
}
for (i = 0; i < 10; i++)
{
if (read(fd, &val, 4) == 4)
printf("get button: 0x%x\n", val);
else
printf("get button: -1\n");
}
flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
while (1)
{
if (read(fd, &val, 4) == 4)
printf("get button: 0x%x\n", val);
else
printf("while get button: -1\n");
}
close(fd);
return 0;
}
正点原子¶
定时器简单API
struct timer_list timer; /* 定义定时器 */
/* 定时器回调函数 */
void function(unsigned long arg)
{
/*
* 定时器处理代码
*/
/* 如果需要定时器周期性运行的话就使用 mod_timer
* 函数重新设置超时值并且启动定时器。
*/
mod_timer(&dev->timertest, jiffies + msecs_to_jiffies(2000));
}
/* 初始化函数 */
void init(void)
{
init_timer(&timer);/* 初始化定时器 */
timer.function = function;/* 设置定时处理函数 */
timer.expires=jffies + msecs_to_jiffies(2000);/* 超时时间 2 秒 */
timer.data = (unsigned long)&dev; /* 将设备结构体作为参数 */
add_timer(&timer);/* 启动定时器 */
}
/* 退出函数 */
void exit(void)
{
del_timer(&timer); /* 删除定时器 */
/* 或者使用 */
del_timer_sync(&timer);
}
定时器处理,他的例程在做处理的时候是将函数放在的unlocked_ioctl中。
struct timer_list timer;/* 定义一个定时器*/
static long timer_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct timer_dev *dev = (struct timer_dev *)filp->private_data;
int timerperiod;
unsigned long flags;
switch (cmd) {
case CLOSE_CMD: /* 关闭定时器 */
del_timer_sync(&dev->timer);
break;
case OPEN_CMD: /* 打开定时器 */
spin_lock_irqsave(&dev->lock, flags);
timerperiod = dev->timeperiod;
spin_unlock_irqrestore(&dev->lock, flags);
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(timerperiod));
break;
case SETPERIOD_CMD: /* 设置定时器周期 */
spin_lock_irqsave(&dev->lock, flags);
dev->timeperiod = arg;
spin_unlock_irqrestore(&dev->lock, flags);
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(arg));
break;
default:
break;
}
return 0;
}