Linux内核之定时器详解

简介:

    前面我们对按键驱动的开发已经基本完成了,但是当你对按键多次按下的时候,你会发现打印的返回值是不正确的,这是什么原因呢?学过51单片机的同学你们都应该知道按键容易产生抖动,俗称“消抖”,我以前的处理办法是设置一个延时10ms,现在我们的按键也是需要延时的,当过了10ms我们在去读这个按键值。


提示:红色部分是定时器代码。


我对定时器的理解如下:

static struct timer_list buttons_timer;//定义timer_list类型的结构体


# define HZ 100

mod_timer(&buttons_timer, jiffies+HZ/100);/定义初始化时间,10ms,jiffies表示当前时间,表示过了1S就出发这个定时函数  jiffies+HZ*10是10s  初始化后只能用一次,以后还得初始化,没有自动充装置。HZ表示100个jiffies,一个jiffies是10ms


static void buttons_timer_function(unsigned long data)    /* 时间到了就调用此函数 */
{
   if(data==14)
    printk("this is cnt=%04d\n",sec++);

}


  init_timer(&buttons_timer);//初始化这个链表
buttons_timer.data=14;//传递给buttons_timer_function的值
buttons_timer.function = buttons_timer_function;//定义超时函数
//buttons_timer.expires  = 0;//设置初始值mod_timer是重新=设置值
add_timer(&buttons_timer);//把定时器增加到内核

  del_timer(struct timer_list * timer)//删除定时器


驱动程序:#include <linux/module.h> /*模块有关的*/

#include <linux/kernel.h>/*内核有关的*/
#include <linux/fs.h>/*文件系统有关的*/
#include <linux/init.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>/*linux中断*/
#include <linux/poll.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>  //copy_to_user
#include <mach/regs-gpio.h>/*寄存器设置S3C2410_GPF0等的定义*/
#include <mach/hardware.h>//s3c2410_gpio_getpin等的定义
#include <mach/irqs.h> //IRQ_EINT0等的定义
#include <asm/system.h>
#include <asm/signal.h>
#include <linux/fcntl.h>
/*
*  休眠用的队列的一个宏
*/
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
//static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量并初始化为1
static DECLARE_MUTEX(button_lock);   //定义互斥锁
#define DEVICE_NAME  "timer"

static struct class *timer_class;
static struct fasync_struct *button_async;
static struct timer_list buttons_timer;

static struct pin_desc *irq_pd;
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val;
struct pin_desc{
unsigned int pin;
unsigned int key_val;
};
//static unsigned char keyval;
/* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */
static volatile int ev_press = 0;
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
struct pin_desc pins_desc[4] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPF3, 0x03},
{S3C2410_GPF4, 0x04},
};
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
irq_pd = (struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies+HZ/100);
return IRQ_HANDLED;
}

static int fifth_drv_open(struct inode *inode, struct file *file)
{
  #if 0
if (!atomic_dec_and_test(&canopen))
{
  atomic_inc(&canopen);
  return -EBUSY;
}
#endif
if (file->f_flags & O_NONBLOCK)//非阻塞
{
if (down_trylock(&button_lock))
return -EBUSY;
}
else //阻塞
{
/* 获取信号量 */
down(&button_lock);
}

request_irq(IRQ_EINT0,buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "S2", &pins_desc[0]);
request_irq(IRQ_EINT2,buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "S3", &pins_desc[1]);
request_irq(IRQ_EINT3,buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "S4", &pins_desc[2]);
request_irq(IRQ_EINT4,buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "S5", &pins_desc[3]);
return 0;
}

ssize_t fifth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
if(size!=1)
return EINVAL;
/* 如果有按键动作, 返回键值 */
if (file->f_flags & O_NONBLOCK)//非阻塞
{
if (!ev_press)
return -EAGAIN;
}
else //阻塞
{
/* 如果没有按键动作, 休眠 */
wait_event_interruptible(button_waitq, ev_press);

}
copy_to_user(buf, &key_val, 1);
ev_press=0;
return 0;
}

int fifth_drv_close(struct inode *inode, struct file *file)
{
//atomic_inc(&canopen);
up(&button_lock);
free_irq(IRQ_EINT0, &pins_desc[0]);
free_irq(IRQ_EINT2, &pins_desc[1]);
free_irq(IRQ_EINT3, &pins_desc[2]);
free_irq(IRQ_EINT4, &pins_desc[3]);
return 0;
}

static int fifth_drv_fasync (int fd, struct file *filp, int on)
{
printk("driver: fifth_drv_fasync\n");
return fasync_helper (fd, filp, on, &button_async);
}

static struct file_operations fifth_drv_fops = {
.owner = THIS_MODULE,/* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open =fifth_drv_open,
.read =fifth_drv_read,    
.release = fifth_drv_close,
.fasync  = fifth_drv_fasync,
};

static void buttons_timer_function(unsigned long data)  /* 定时器调用函数 */
{
struct pin_desc * pindesc = irq_pd;
unsigned int pinval;

if (!pindesc)
return;
pinval = s3c2410_gpio_getpin(pindesc->pin);
if (pinval)
{
/* 松开 */
key_val = 0x80 | pindesc->key_val;
}
else
{
/* 按下 */
key_val = pindesc->key_val;
}

ev_press = 1;   /* 表示中断发生了 */
wake_up_interruptible(&button_waitq);/* 唤醒休眠的进程 */

//kill_fasync (&button_async, SIGIO, POLL_IN);
}


int major;
static int fifth_drv_init(void)
{
 init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;   /* 定时器的一些初始化操作 */
//buttons_timer.expires  = 0;
add_timer(&buttons_timer);

major = register_chrdev(0, DEVICE_NAME, &fifth_drv_fops);
timer_class= class_create(THIS_MODULE, DEVICE_NAME);
device_create(timer_class, NULL, MKDEV(major, 0), NULL, "timer");
return 0;
}

static void fifth_drv_exit(void)
{
unregister_chrdev(major, "signal");
device_destroy(timer_class,MKDEV(major, 0));
class_destroy(timer_class);
}

module_init(fifth_drv_init);
module_exit(fifth_drv_exit);
MODULE_LICENSE("GPL");

测试程序不变,只是把open里面变成/dev/timer


目录
相关文章
|
13天前
|
算法 Linux 调度
深入理解Linux内核调度器:从基础到优化####
本文旨在通过剖析Linux操作系统的心脏——内核调度器,为读者揭开其高效管理CPU资源的神秘面纱。不同于传统的摘要概述,本文将直接以一段精简代码片段作为引子,展示一个简化版的任务调度逻辑,随后逐步深入,详细探讨Linux内核调度器的工作原理、关键数据结构、调度算法演变以及性能调优策略,旨在为开发者与系统管理员提供一份实用的技术指南。 ####
51 4
|
17天前
|
缓存 算法 Linux
深入理解Linux内核调度器:公平性与性能的平衡####
真知灼见 本文将带你深入了解Linux操作系统的核心组件之一——完全公平调度器(CFS),通过剖析其设计原理、工作机制以及在实际系统中的应用效果,揭示它是如何在众多进程间实现资源分配的公平性与高效性的。不同于传统的摘要概述,本文旨在通过直观且富有洞察力的视角,让读者仿佛亲身体验到CFS在复杂系统环境中游刃有余地进行任务调度的过程。 ####
38 6
|
3天前
|
缓存 网络协议 Linux
深入探索Linux操作系统的内核优化策略####
本文旨在探讨Linux操作系统内核的优化方法,通过分析当前主流的几种内核优化技术,结合具体案例,阐述如何有效提升系统性能与稳定性。文章首先概述了Linux内核的基本结构,随后详细解析了内核优化的必要性及常用手段,包括编译优化、内核参数调整、内存管理优化等,最后通过实例展示了这些优化技巧在实际场景中的应用效果,为读者提供了一套实用的Linux内核优化指南。 ####
11 1
|
8天前
|
算法 Linux 开发者
Linux内核中的锁机制:保障并发控制的艺术####
本文深入探讨了Linux操作系统内核中实现的多种锁机制,包括自旋锁、互斥锁、读写锁等,旨在揭示这些同步原语如何高效地解决资源竞争问题,保证系统的稳定性和性能。通过分析不同锁机制的工作原理及应用场景,本文为开发者提供了在高并发环境下进行有效并发控制的实用指南。 ####
|
16天前
|
缓存 资源调度 安全
深入探索Linux操作系统的心脏——内核配置与优化####
本文作为一篇技术性深度解析文章,旨在引领读者踏上一场揭秘Linux内核配置与优化的奇妙之旅。不同于传统的摘要概述,本文将以实战为导向,直接跳入核心内容,探讨如何通过精细调整内核参数来提升系统性能、增强安全性及实现资源高效利用。从基础概念到高级技巧,逐步揭示那些隐藏在命令行背后的强大功能,为系统管理员和高级用户打开一扇通往极致性能与定制化体验的大门。 --- ###
45 9
|
15天前
|
缓存 负载均衡 Linux
深入理解Linux内核调度器
本文探讨了Linux操作系统核心组件之一——内核调度器的工作原理和设计哲学。不同于常规的技术文章,本摘要旨在提供一种全新的视角来审视Linux内核的调度机制,通过分析其对系统性能的影响以及在多核处理器环境下的表现,揭示调度器如何平衡公平性和效率。文章进一步讨论了完全公平调度器(CFS)的设计细节,包括它如何处理不同优先级的任务、如何进行负载均衡以及它是如何适应现代多核架构的挑战。此外,本文还简要概述了Linux调度器的未来发展方向,包括对实时任务支持的改进和对异构计算环境的适应性。
37 6
|
16天前
|
缓存 Linux 开发者
Linux内核中的并发控制机制:深入理解与应用####
【10月更文挑战第21天】 本文旨在为读者提供一个全面的指南,探讨Linux操作系统中用于实现多线程和进程间同步的关键技术——并发控制机制。通过剖析互斥锁、自旋锁、读写锁等核心概念及其在实际场景中的应用,本文将帮助开发者更好地理解和运用这些工具来构建高效且稳定的应用程序。 ####
35 5
|
16天前
|
算法 Unix Linux
深入理解Linux内核调度器:原理与优化
本文探讨了Linux操作系统的心脏——内核调度器(Scheduler)的工作原理,以及如何通过参数调整和代码优化来提高系统性能。不同于常规摘要仅概述内容,本摘要旨在激发读者对Linux内核调度机制深层次运作的兴趣,并简要介绍文章将覆盖的关键话题,如调度算法、实时性增强及节能策略等。
|
17天前
|
存储 监控 安全
Linux内核调优的艺术:从基础到高级###
本文深入探讨了Linux操作系统的心脏——内核的调优方法。文章首先概述了Linux内核的基本结构与工作原理,随后详细阐述了内核调优的重要性及基本原则。通过具体的参数调整示例(如sysctl、/proc/sys目录中的设置),文章展示了如何根据实际应用场景优化系统性能,包括提升CPU利用率、内存管理效率以及I/O性能等关键方面。最后,介绍了一些高级工具和技术,如perf、eBPF和SystemTap,用于更深层次的性能分析和问题定位。本文旨在为系统管理员和高级用户提供实用的内核调优策略,以最大化Linux系统的效率和稳定性。 ###
|
16天前
|
Java Linux Android开发
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。