驱动开发相关文章:
驱动开发(六):应用层通过文件系统与内核层交互
目录
定时器介绍
定时的本质是计时,计时的本质是计数。linux内核定时器是一种基于未来时间点的计时方式,以当前时刻来启动的时间点,以未来的某一时刻为终止点。
因此,我们要实现定时需要两个值,一个是当前时刻值(起始时间),一个是目标时间值(触发中断时间)
定时器的当前时间如何获取?
jiffies是在板子上电这一刻开始计数,只要板子不断电,这个值一直在增加(64位)。在驱动代码中直接使用即可。
定时器加1代表走了多长时间?
linux内核会使用config_hz来设置自己的系统时钟。
在内核顶层目录下使用 vi .config
定时器的使用
内核提供了一个封装好的结构体 struct timer_list 用来表示定时器。
struct timer_list 结构体里的内容:
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
};
1.声明一个定时器
可以使用内核给你提供的这个接口直接声明自己的定时器。声明定时器的数量没有限制,想开几个开几个。
struct timer_list mytimer; //声明一个结构体变量
2.初始化定时器
声明完之后还需要对结构体的基本内容进行填充
mytimer.expires = jiffies + 1000; //1s
mytimer.function = timer_function; //名字叫timer_function的中断处理函数
mytimer.data = 0;
void timer_function(unsigned long data) //定时器的处理函数
{
}
填完基本的参数之后,剩下的可以交给内核自动填充
init_timer(&mytimer); //内核帮你填充你未填充的对象
3.启动定时器
3.1添加定时器
用于向linux内核注册定时器。
同一个定时器只能被添加一次,在你添加定时器的时候定时器会先启动一次
void add_timer(struct timer_list *timer);
3.2使用定时器
除了第一次开启定时器使用add_timer,其他时间再次使用定时器要使用mod_timer。
int mod_timer(struct timer_list *timer, unsigned long expires)
//再次启动定时器,参数unsigned long expires为定时时间
4.删除定时器
int del_timer(struct timer_list *timer) //删除定时器
不管定时器有没有被激活,都可以使用此函数删除。
参考代码
用定时器实现按键消抖
#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#define gpiono(m, n) m * 32 + n
#define gpio_b8 (gpiono(1, 8))
#define gpio_b16 (gpiono(1, 16))
int gpiono[] = {gpio_b8, gpio_b16};
char *name[] = {"gpio_it_8", "gpio_it_16"};
int ret;
int i;
struct timer_list mytimer;
irqreturn_t handler(int irqno, void *dev)
{
mod_timer(&mytimer,jiffies + 10);
return irq_handled;
}
void timer_function(unsigned long data) //定时器的处理函数
{
int b8 = gpio_get_value(gpio_b8);
int b16 = gpio_get_value(gpio_b16);
if (b8 == 0)
{
printk(kern_err "------------\n");
}
if (b16 == 0)
{
printk(kern_err "++++++++++++\n");
}
}
static int __init hello_init(void)
{
mytimer.expires = jiffies + 10;
mytimer.function = timer_function;
mytimer.data = 0;
init_timer(&mytimer); //内核帮你填充你未填充的对象
add_timer(&mytimer); //开启一次定时器
for (i = 0; i < sizeof(gpiono) / sizeof(int); i++)
{
ret = request_irq(gpio_to_irq(gpiono[i]), handler, irqf_trigger_falling, name[i], null);
if (ret != 0)
{
printk(kern_err "%s request irq err\n", name[i]);
return ret;
}
}
return 0;
}
static void __exit hello_exit(void)
{
for (i = 0; i < sizeof(gpiono) / sizeof(int); i++)
{
free_irq(gpio_to_irq(gpiono[i]), null);
}
del_timer(&mytimer);
}
module_init(hello_init);
module_exit(hello_exit);
module_license("gpl");
现象:
发表评论