EDA365欢迎您!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在Linux内核中,有这样的一个定时器,叫做内核定时器,内核定时器用于控制某个函数,也就是定时器将要处理的函数在未来的某个特定的时间内执行。内核定时器注册的处理函数只执行一次,即不是循环执行的。 如果对延迟的精度要求不高的话,最简单的实现方法如下---忙等待: Unsigned long j = jiffies + jit_delay * HZ; While(jiffies < j) { …… } 下面来说下具体的参数代表的含义: jiffies:全局变量,用来记录自系统启动以来产生的节拍总数。启动时内核将该变量初始化为0; 此后每次时钟中断处理程序增加该变量的值。每一秒钟中断次数HZ,jiffies一秒内增加HZ。系统运行时间 = jiffie/HZ. jiffies用途:计算流逝时间和时间管理 jiffies内部表示: extern u64 jiffies_64; extern unsigned long volatilejiffies; //位长更系统有关32/64----> | | 32位:497天后溢出 64位:…… 在定时器中有这样一个概念,度量时间差: 时钟中断由系统的定时硬件以周期性的时间间隔产生,这个间隔说白了其实就是频率由内核根据HZ来确定,嵌入式物联网等企鹅意义气呜呜吧久零就易,HZ是一个与体系结构无关的常数,可以配置为(50-1200),在X86平台,它的值被默认为1000 ; 定时器在内核中相关的头文件以及数据结构如下: #include <linux/timer.h> /*timer*/
& x3 P* Y/ Q1 [+ N( k+ X- c8 b#include <asm/uaccess.h> /*jiffies*/ struct timer_list { /* * All fields that change during normal runtime grouped to the * same cacheline */ //定时器可以作为链表的一个节点 struct list_head entry; //定时值基于jiffies unsigned long expires; //定时器内部值 struct tvec_base *base; //定时器处理函数 void (*function)(unsigned long); //定时器处理函数参数 unsigned long data; int slack; #ifdef CONFIG_TIMER_STATS int start_pid; void *start_site; char start_comm[16]; #endif #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif }; 定时器最基本的使用方法可以使用下面这两个个内核提供的宏: //初始化定时器
+ P2 W* w* w5 w: b#define init_timer(timer)\
. i* k7 @1 R( Z2 P3 N L/ Z1 Minit_timer_key((timer), NULL, NULL)5 m# P5 h5 v. J2 i8 C
//注册一个定时器
$ Z; P- o( a4 K. E3 C, r#define setup_timer(timer, fn, data)\% m' p5 X" O. r, n9 h$ c7 j
setup_timer_key((timer), NULL, NULL, (fn), (data)) 还有以下两个函数: 添加一个定时器
6 F, J7 k: w. x# V. ]/ A7 W. A" l, j; Qvoid add_timer(struct timer_list *timer) 删除一个定时器 int del_timer(struct timer_list *timer) 那么写一个定时器的具体步骤是什么?8 \' X, R/ D: m9 G" {9 l; N
1、初始化内核定时器9 P) r8 G) p8 g4 w
2、设置定时器执行函数的参数(可有可无)* m0 m6 E0 m& C
3、设置定时时间
8 e( [$ _) y8 B, n! z: y4、设置定时器函数
* Z: n. `; P( p4 h5、启动定时器 接下来,我们结合一个简单的驱动来了解这个过程,这个驱动非常简单,就是开机后,5s钟后,开发板上的蜂鸣器就会每隔1s钟交替响。 先来看看开发板的蜂鸣器的原理图: (1)蜂鸣器接口位于电路板的底板,看电路图可知道是高电平有效。 file:///C:\Users\郭晓娟\AppData\Local\Temp\ksohtml\wpsB266.tmp.jpg (2)相对应的找到核心板的接口。由此可知,我们的蜂鸣器是GPD0_0file:///C:\Users\郭晓娟\AppData\Local\Temp\ksohtml\wpsB286.tmp.png 接下来找数据手册,找到对应的寄存器,然后配置它就可以了。 2、查数据手册,找到相关的寄存器,并配置file:///C:\Users\郭晓娟\AppData\Local\Temp\ksohtml\wpsB297.tmp.png (1)找到GPD0CON,地址是0x114000A0,我们需要配置GPD0CON(0)为输出状态。也就是写0x1这个值到这个寄存器。 file:///C:\Users\郭晓娟\AppData\Local\Temp\ksohtml\wpsB2A8.tmp.png(2)找到GPD0DAT这个寄存器,用于配置蜂鸣器的高低电平,物理地址是0x114000A4,刚好与上一个差4个字节的偏移 我们只要对这个寄存器写1和写0,那么蜂鸣器就可以叫起来了,哈哈。是不是很简单?file:///C:\Users\郭晓娟\AppData\Local\Temp\ksohtml\wpsB2A9.tmp.png file:///C:\Users\郭晓娟\AppData\Local\Temp\ksohtml\wpsB2C9.tmp.png整个简单的驱动代码如下: #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/fb.h> #include <linux/backlight.h> #include <linux/err.h> #include <linux/pwm.h> #include <linux/slab.h> #include <linux/miscdevice.h> #include <linux/delay.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/timer.h> /*timer*/ #include <asm/uaccess.h> /*jiffies*/ #include <linux/delay.h> //设备名称 #define DEVICE_NAME "Bell" //设备GPIO引脚 #define BUZZER_GPIO EXYNOS4_GPD0(0) //定义一个定时器链表 struct timer_list timer; static void Bell_init() { - \5 y8 l1 e9 p
|