本文简述如何使用linux里的定时器,包括周期性中断,停止和启动的控制。

日常常用的几个定时器相关linux API函数:

  1. init_timer(); 初始化定时器
  2. add_timer(); 启动定制器
  3. del_timer();停止定时器
  4. mod_timer(); 重新修改定时器当前计数时间

这些API位于:kernel\timer.c中,该源文件里还包括了常用的msleep(),schedule_timeout()等常用的延时调度函数。

下面以一个实例驱动介绍linux里的timer的使用(基于3.10.0-123内核)。


案例如下:

  1. 创建一定时器,完成每3s一次周期性中断并打印。
  2. 通过字符设备接口与用户层交互,写0则关闭(停止)定时器,写1则开启(启动)定时器
    (即:当echo 1 >/dev/demo_deva启动定时器,当echo 0 >/dev/demo_deva 停止定时器)。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include "timer_drv.h"/*
功能:定时器3秒定时中断一次打印。当echo 1 >/dev/demo_deva开启定时器,当echo 0 >/dev/demo_deva 关闭定时器
*/#define DRV_VERSION  "V1.0"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LUDY");
MODULE_DESCRIPTION("This is timer demo");
MODULE_VERSION(DRV_VERSION);//static volatile int time_count = 0;
static void handel_irq_do_timer(unsigned long arg);
u8 delay = 3; //3s
/* 设备要使用的定时器 */
static struct timer_list my_timer;//也可以:TIMER_INITIALIZER(handel_irq_do_timer, 0, 0); 直接快速初始化结构体内容/* 定时器中断处理函数 */
static void handel_irq_do_timer(unsigned long arg)
{// struct xxx_device *dev = (struct xxx_device *)(arg);/* 修改调度定时器,3s再执行 */mod_timer(&my_timer, jiffies + delay*HZ); //*HZ即转换成jiffies单位值printk("timer arrival\n");
}/* 定时器初始化*/
void timer_init_run(void* pri_data)
{//device *dev =  (device*)pri_data;/* 初始化定时器 */init_timer(&my_timer);   /* 设备结构体指针作为定时器处理函数参数 */my_timer.function = &handel_irq_do_timer; //中断处理函数my_timer.expires =  delay*HZ;  //定时时间delay秒  //my_timer.data = (unsigned long)dev;
}/*
写函数;
定时器启动和停止控制
*/
ssize_t  demodrv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{char rev_data;/*只接受一个字符的写入*/if(count >2)  //count包括了/0字符return -EFAULT;//copy_from_user(rev_data1, buf, count);if(get_user(rev_data, buf)){return -EFAULT;}printk("driver: device write:%c  count:%d\n" ,rev_data, count);switch(rev_data){case '0':/* 删除(停止)定时器 */del_timer(&my_timer);break;case '1':/* 添加(注册) 启动定时器 */add_timer(&my_timer);  //add添加后,定制器开始运行break;default:PRINT_ERR("write EINVAL:%c\n" ,rev_data);break;}return count;
}ssize_t demodrv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{return 1;
}static int demodrv_open(struct inode *inode, struct file *file)
{printk("driver: device open\n");return 0;
}int demodrv_close(struct inode *inode, struct file *file)
{printk("driver: device close\n");return 0;
}static struct file_operations demo_drv_fops = {.owner   =  THIS_MODULE, .open    =  demodrv_open,     .read  = demodrv_read,.write  = demodrv_write,      .release =  demodrv_close,
};int major;
static struct class *demo_drv_class;
static struct class_device  *demo_class_dev;static int __init demo_drv_init(void)
{major = register_chrdev(0, "demo_drv", &demo_drv_fops);//注册字符驱动获取设备号demo_drv_class = class_create(THIS_MODULE, "demo_drv_class"); //sys/class下创建类demo_class_dev = device_create(demo_drv_class, NULL, MKDEV(major, 0), NULL, "demo_dev"); /*类下创建设备文件绑定到设备号 /dev/demo_dev */timer_init_run(demo_class_dev);return 0;
}static void __exit demo_drv_exit(void)
{unregister_chrdev(major, "demodrv");device_unregister(demo_class_dev);class_destroy(demo_drv_class);/* 删除(停止)定时器 */del_timer(&my_timer);return 0;
}
module_init(demo_drv_init);
module_exit(demo_drv_exit);

如上源码可知,使用一个定时器通常需要如下步骤:

  1. 定义一个timer_list 结构体的定时器对象。并可以通过TIMER_INITIALIZER快速赋值对象里的成员(中断函数;定时时间等);
  2. init_timer 初始化该定制器(此时定时器还不能走);
  3. 可以自定义为定时器对象里的成员赋值(中断函数;定时时间;私有数据等);
  4. add_timer 启动该定时器,定时器开始倒计时;
  5. mod_timer 修改当前定时器的数值(复位定时器);
  6. 如果要停止(删除)一个定时器,执行del_timer,需要重新启动则继续执行add_timer。

linux定时器使用指南及实例相关推荐

  1. linux定时器(crontab)实例

    linux实验示例----实现每2分钟将"/etc"下面的文件打包存储到"/usr/lobal"目录下 ·Step1:编辑当前用户的crontab并保存 终端输 ...

  2. linux调度全景指南

    | 导语 本文主要是讲Linux的调度系统, 由于全部内容太多,分三部分来讲,调度可以说是操作系统的灵魂,为了让CPU资源利用最大化,Linux设计了一套非常精细的调度系统,对大多数场景都进行了很多优 ...

  3. Linux定时器接口

    Linux定时器接口主要分为三类: 一. sleep(), unsleep, alarm(),引用了SIGALARM信号,在多线程中使用信号又是相当麻烦的. 二. nanosleep(), clock ...

  4. 数据简化社区Google和Linux代码风格指南(附PDF公号发“代码风格”下载)

    数据简化社区Google和Linux代码风格指南(附PDF公号发"代码风格"下载) 秦陇纪2019代码类 数据简化DataSimp 昨天 数据简化DataSimp导读:数据简化社区 ...

  5. Linux 内核编程指南

    Linux 内核编程指南   PeterJay Salzman MichaelBurian OriPomerantz Copyright© 2001 Peter Jay Salzman 2007−05 ...

  6. Linux TWI开发指南

    文章目录 Linux TWI开发指南 1 前言 1.1 文档简介 1.2 目标读者 1.3 适用范围 2 模块介绍 2.1 模块功能介绍 2.2 相关术语介绍 2.2.1 硬件术语 2.2.2 软件术 ...

  7. linux内核调试指南

    Hunnad的专栏 * 条新通知 * 登录 * 注册 * 欢迎 * 退出 * 我的博客 * 配置 * 写文章 * 文章管理 * 博客首页 * * * * 空间 * 博客 * 好友 * 相册 * 留言 ...

  8. linux内核调试指南 1

    大海里的鱼有很多,而我们需要的是鱼钩一只 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 ...

  9. linux 内核调试指南

    大海里的鱼有很多,而我们需要的是鱼钩一只 本文档由大家一起自由编写,修改和扩充,sniper负责维护.引用外来的文章要注明作者和来处.本文档所有命令都是在ubuntu/debian下的操作.选取的内核 ...

  10. Linux Kernel - Debug Guide (Linux内核调试指南 )

    linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 ...

最新文章

  1. MBTiles离线包生成和使用
  2. 软件开发是一门手艺活
  3. 混合开发的坑(7) ---输入文本时,键盘遮挡
  4. debian linux 内核 3.14-1 显示器 很暗,Ubuntu 与 Linux Mint 用户安装 Kernel 3.14.1 内核
  5. 【数据结构与算法】之深入解析“石子游戏”的求解思路与算法示例
  6. html整个项目怎么导出来,怎样将jquery导入web项目中?
  7. LINUX下system和execl有什么差异?
  8. java编程入门到精通课后答案,附源代码
  9. linux qq 提示错误,deepin-wine QQ崩溃,QQ遇到错误的暂时解决方法
  10. 神器!程序员必备的Linux命令行大全(PDF下载)
  11. C语言找出1000之内的完数
  12. C# 复数类 Complex
  13. XSS注入之xss-labs
  14. 测试用例-------纸杯
  15. Android多语言设置
  16. 指尖江湖李忘生鸿蒙初开,剑网3指尖江湖李忘生怎么样_李忘生装备搭配、技能特性、解锁方法介绍_游戏吧...
  17. 2006-03-18工作记录
  18. mingw编译linux源码,minGW编译cgminer源码
  19. samba端口号修改_修改samba端口
  20. ssas 数据源mysql_支持的数据源类型(SSAS 多维)

热门文章

  1. 微信小程序实现组件之间的传值
  2. 【教程】python递归三部曲(基于turtle实现可视化)-一、谢尔宾斯基三角形
  3. 奖补多的2022年合肥高新区高成长企业申报时间入选范围及申报条件材料
  4. C语言scanf函数详细解释
  5. ADS实验报告三:匹配电路的设计与仿真
  6. 爬虫之字体反爬(仅供学习参考)
  7. C语言学习杂记1|学习软件选择
  8. TurboMail邮件系统配置之预防邮件炸弹
  9. 计算机发展史 文档,计算机发展史课件
  10. 微软雅黑字体的设计理念