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*// Z& C5 u7 v4 `% `! ~
#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 }; 定时器最基本的使用方法可以使用下面这两个个内核提供的宏: //初始化定时器6 L+ s: x6 @4 w8 x
#define init_timer(timer)\
) i! T. p. j! q1 C) N( ?; { C) jinit_timer_key((timer), NULL, NULL): p1 d$ R' X& f' l
//注册一个定时器
/ n& L2 |1 P6 |' S3 \#define setup_timer(timer, fn, data)\
% s- F" _/ s; csetup_timer_key((timer), NULL, NULL, (fn), (data)) 还有以下两个函数: 添加一个定时器
3 _& H2 E: S/ X$ p) Cvoid add_timer(struct timer_list *timer) 删除一个定时器 int del_timer(struct timer_list *timer) 那么写一个定时器的具体步骤是什么?* ?* H$ E' G2 w0 |
1、初始化内核定时器
$ y$ Q: R; x, _. H* t0 N2、设置定时器执行函数的参数(可有可无)' _/ c- Z9 E- T6 g* d( x0 ]+ @ A
3、设置定时时间/ c7 K: t% q5 w
4、设置定时器函数
( X8 W; T. T: Q9 Z5、启动定时器 接下来,我们结合一个简单的驱动来了解这个过程,这个驱动非常简单,就是开机后,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() { n# ]' ^, R' x# l, O4 ]
|