一、定时器的一些基本概念
1.1 定时器一般分为两大类:
软件定时器:由操作系统模拟的定时,没有真实存在的时钟源和计数器, 一般对时钟源和计数器硬件有一定的依赖,跨平台性较好。
硬件定时器:由真正存在的时钟源和计数器组成,跟硬件相关,跨平台的性能不好。
1.2 定时器一般由什么组成
一般的定时器都有两部分组成:
计数器和时钟源;
计数器:单纯的计数 如:RTC向上的计数器
时钟源:给计数提供一个节拍,说白了就是决定我们的计数器多久计数一次。比如说时钟源 100HZ
就表示我们的计数器一秒钟计数100次。
二、linux内核定时器
内核的定时器,指的就是Linux下的软件的定时,所有的软件定时器对硬件的定时器是有一定的依赖的,软件定时器也有硬件定时器的特性,软件定时器也有时钟源和计数器。
如果说我们使用linux3.5的内核里,时钟源默认的是 100HZ 每计数一次是10ms,在.config配置内核的编译配置的时候,改成了 200HZ --那么就是每5ms计数一次。
在linux内核里,计数器开始计数是从系统上电就开始的,并且只要我的系统不关闭,计数器就会一直计数,计数器从开机到现在所计的数在linux内核里有一个变量记录,这个变量的值是一直变化的,就类似与日历时间,这个变量就叫做jiffies,它的值是每隔5ms自加一次,假如我现在要定时5s去执行某一个动作,让计数器去计时5s,定时器计时五秒钟后,计数器应该计数的值:jiffies+5*HZ。
三、linux内核定时器相关的API
函数的功能:初始化一个内核的定时器
函数的头文件:<linux/timer.h>
函数的原型:void init_timer(struct timer_list *timer)
函数的参数:struct timer_list *timer:内核定时器的核心的结构体
函数的返回值: 无
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
struct timer_list {
unsigned long expires:计数器要计的数值
void (*function)(unsigned long):计数器计数完成之后,要调用的回调函数
unsigned long data:传给回调函数的参数 一般不填
};
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:向内核注册一个定时器 并运行
函数的头文件:<linux/timer.h>
函数的原型: void add_timer(struct timer_list *timer)
函数的参数:struct timer_list *timer:内核定时器的核心的结构体
函数的返回值:无
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:重新激活内核定时器
函数的头文件:<linux/timer.h>
函数的原型:int mod_timer(struct timer_list *timer, unsigned long expires)
函数的参数:
struct timer_list *timer:内核定时器的核心结构体
unsigned long expires:新的计数器要计的数
函数的返回值:当前边的定时器时间还未到 返回1
否则 成功返回 0 失败返回 -1
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的功能:删除一个内核定时器
函数的头文件:<linux/timer.h>
函数的原型:int del_timer(struct timer_list *timer)
函数的参数: struct timer_list *timer:内核定时器的核心的结构体
函数的返回值:
成功返回 0
失败返回 -1
计数的时间假如为秒的话
计数的次数 直接就是jiffies+秒数*HZ
当计数的时间为微秒的时候
unsigned long usecs_to_jiffies(const unsigned int u)//指定时间单位us
到计数的时间为毫秒的时候
unsigned long msecs_to_jiffies(const unsigned int m)//指定时间单位ms
四、以下代码是练习代码和运行结果,仅供参考
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/gpio.h>
#include<linux/irq.h>
#include<linux/interrupt.h>
#include<linux/miscdevice.h>
#include<linux/fs.h>
#include<asm/uaccess.h>
#include<linux/sched.h>
#include<linux/wait.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/timer.h>
int my_irq;
int value;
int count=0;
struct timer_list mytime;
dev_t mykey1;
struct cdev mycdev;
struct file_operations myfops;
struct class * mykey1_class=NULL;
struct device * mydevicekey1=NULL;
int light=1;
static DECLARE_WAIT_QUEUE_HEAD(myque);
//定时器回调函数
void my_fun(unsigned long data)
{
int ret1;
ret1=gpio_get_value(EXYNOS4_GPX3(2));
if(ret1 == 0)
{
count=1;
wake_up_interruptible(&myque);
//翻转LED1
light =!light;
gpio_set_value(EXYNOS4X12_GPM4(0),light);
printk("翻转LED1\n");
}
//printk("我被调用了\n");
}
//中断函数
irqreturn_t fun1(int num, void *arg)
{
//printk("num:%d\n",num);
mod_timer(&mytime, jiffies+msecs_to_jiffies(20));
return 0;
}
int myopen (struct inode *inode, struct file *file)
{
int fan;
//1.申请中断号(key1)
my_irq = gpio_to_irq(EXYNOS4_GPX3(2));
if(my_irq < 0)
{
printk("申请中断失败\n");
return -1;
}
printk("申请的中断号为:%d\n",my_irq);
//2.使能中断
enable_irq(my_irq);
//3.向内核注册中断
fan=request_irq(my_irq,fun1,IRQF_TRIGGER_FALLING,"mykey",NULL);
printk("按键打开\n");
return 0;
}
int myclose(struct inode *inode, struct file *file)
{
//1.注销中断号
free_irq(my_irq, NULL);
//2.使能中断
disable_irq(my_irq);
gpio_set_value(EXYNOS4X12_GPM4(0),1);
printk("led1已关闭\n");
//printk("按键关闭\n");
return 0;
}
ssize_t myread(struct file *file, char __user *buf, size_t size, loff_t *oft)
{
int ret;
//printk("开始读取\n");
//到这陷入阻塞,放弃cpu
count=0;
wait_event_interruptible(myque,count);
value=gpio_get_value(EXYNOS4_GPX3(2));
ret=copy_to_user(buf,&value,1);
return 0;
}
static int __init mykeys_init(void)
{
//定时器
mytime.expires=jiffies+msecs_to_jiffies(20); //20ms
mytime.function=my_fun;
init_timer(&mytime); //初始化定时器
add_timer(&mytime); //向内核注册一个定时器 并运行
//linux2.6 设备注册
int ret;
//1:申请1个设备号,key1用
ret=alloc_chrdev_region(&mykey1, 0, 1, "key1");
if(ret < 0)
{
printk("申请设备号失败\n");
return -1;
}
printk("mykey1:%d\n",mykey1);
printk("key1主设备号:%d\n",MAJOR(mykey1));
printk("key1次设备号:%d\n",MINOR(mykey1));
//2:初始化linux2.6的核心结构体
myfops.owner=THIS_MODULE;
myfops.open=myopen;
myfops.release=myclose;
myfops.read=myread;
cdev_init(&mycdev,&myfops);
//3:向内核注册linux2.6的核心结构体
cdev_add(&mycdev, mykey1, 1);
//4:创建自动生成设备文件所需要的类结构体
mykey1_class=class_create(THIS_MODULE, "key1");
if(mykey1_class == NULL)
{
printk("创建类结构体失败\n");
return -1;
}
//5:生成设备文件
mydevicekey1=device_create(mykey1_class, NULL, mykey1, NULL, "key1");
if(mydevicekey1 ==NULL)
{
printk("生成设备文件失败\n");
}
return 0;
}
static void __exit mykeys_exit(void)
{
//1:销毁设备文件
device_destroy(mykey1_class, mykey1);
//2:销毁类结构体
class_destroy(mykey1_class);
//3:从内核取消注册linux2.6的核心结构体
cdev_del(&mycdev);
//释放设备号
unregister_chrdev_region(mykey1,1);
}
module_init(mykeys_init);
module_exit(mykeys_exit);
MODULE_LICENSE("GPL");
运行结果: