Linux驱动开发之内核定时器【完整教程】

!!!!完整代码在文章最后面!!!!
!!!!完整代码在文章最后面!!!!
!!!!完整代码在文章最后面!!!!

内核定时器基础知识

1.系统节拍率
  Linux系统节拍率默认为100Hz,是最小的,系统节拍率可以在make menucofing中设置,其中可以设置为100、200、250、300、500、1000Hz的节拍率,节拍率高低各有优缺点:
①高节拍率会提高系统时间精度,采用1000Hz的话,时间精度便是1ms,对于时间要求严格的函数来说,能够以更高的精度运行
②高节拍率会导致中断的产生更加频繁,加剧系统的负担。
  Linux内核使用全局变量jiffies来记录系统从启动以来的系统节拍数,一开始默认是0,jiffies定义在内核源码include/linux/jiffies.h文件中可以找到。32位的jiffies需要注意溢出的风险,而64位的则不需要,因为32位的只需要49.7天会溢出,而64位的jiffies需要5.8亿年。

2.内核定时器
  Linux内核定时器使用起来很简单,只需要提供超出时间和定时处理函数即可,当超出时间后,定时处理函数便会执行,并且需要在定时处理函数中重新开启定时器。Linux内核用结构体描述内核定时器,timer_list定义在/include/linux/timer.h。expires成员变量表示超时时间,单位是节拍数

struct timer_list{
   
	struct list_head entry;
	unsigned long expires;        //定时器超时时间,单位是节拍数
	struct tvec_base *base;

	void (*function)(unsigned long);   //定时处理函数
	unsigned long data;                //要传递给function函数的参数
	int slack;
};

  

驱动程序编写

1.最基本的设备驱动框架,接下来的步骤都是根据这个框架来完善的

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define TIMER_CNT 1
#define TIMER_NAME "timer1"

/*timer设备结构体*/
struct timer_dev{
   
    dev_t devid;
    int major; //主设备号
    int minor; //次设备号
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node *nd;
};
struct timer_dev timerdev;/*timer*/

static int timer_open(struct inode *inode, struct file *filp)
{
   
    filp->private_data = &timerdev;
    return 0;
}
static int timer_release(struct inode *inode, struct file *filp)
{
   
    return 0;
}
static ssize_t timer_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
   
    int ret;
        
    return 0;
}
/*cdev操作集合*/
static const struct file_operations timer_fops = {
   
    .owner   = THIS_MODULE,
    .write   = timer_write,
    .open    = timer_open,
    .release = timer_release,
};

/*驱动入口函数*/
static int __init timer_init(void)
{
   
    int ret = 0;

    /*1注册字符设备驱动*/
    timerdev.major = 0;
    if(timerdev.major){
    //给定主设备号
        timerdev.devid = MKDEV(timerdev.major, 0);
        register_chrdev_region(timerdev.devid, TIMER_CNT, TIMER_NAME);
    }else{
     //没有给定设备号
        alloc_chrdev_region(&timerdev.devid, 0, TIMER_CNT, TIMER_NAME);
        timerdev.major = MAJOR(timerdev.devid);
        timerdev.minor = MINOR(timerdev.devid);
    }
    if(ret <0){
   
        goto fail_devid;
    }
    printk("timer major = %d, timer = %d \r\n",timerdev.major,timerdev.minor)

你可能感兴趣的:(Linux,驱动开发,驱动开发,linux,c#,运维,centos)