linux内核驱动之定时器

一、定时器的一些基本概念

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");

运行结果:

相关推荐

  1. Linux内核驱动开发-006内核定时器

    2024-03-17 17:28:03       14 阅读
  2. Linux嵌入式驱动开发-内核定时器

    2024-03-17 17:28:03       16 阅读
  3. Linux 设备驱动管理内核对象(Kernel Object)机制

    2024-03-17 17:28:03       15 阅读
  4. Linux驱动层】iTOP-RK3568学习路(六):定时器

    2024-03-17 17:28:03       14 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-17 17:28:03       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-17 17:28:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-17 17:28:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-17 17:28:03       20 阅读

热门阅读

  1. while 循环语句

    2024-03-17 17:28:03       19 阅读
  2. Elasticsearch(14) match_phrase_prefix的使用

    2024-03-17 17:28:03       18 阅读
  3. 策略模式业务实战

    2024-03-17 17:28:03       24 阅读
  4. MongoDB聚合运算符:$first

    2024-03-17 17:28:03       20 阅读
  5. 11. C++空基类优化

    2024-03-17 17:28:03       17 阅读
  6. 微信小程序睡眠X秒【while循环模式】

    2024-03-17 17:28:03       19 阅读
  7. 安装与配置FTP服务器(超详细)

    2024-03-17 17:28:03       20 阅读
  8. 奇怪需求之奇怪设计

    2024-03-17 17:28:03       17 阅读
  9. 人见人爱的链表

    2024-03-17 17:28:03       17 阅读
  10. Mac中文输入法区分回车和提交

    2024-03-17 17:28:03       19 阅读
  11. 数据结构和算法:链表构造相关代码理解

    2024-03-17 17:28:03       21 阅读