系统时钟中断:选取一个硬件定时器,对该硬件定时器作出相应的初始化,使得该定时器产生周期性的系统时钟中断
setup_irq(info->irqno, &timer_event_irqaction);
timer_event_handler:会调用tick_periodic
更新墙上时间
计算当前线程的时间片是否耗尽
如果耗尽重新执行任务调度
jiffies++;
…
HZ:它是一个宏
它对规定了每秒钟产生的系统时钟中断次数
当前所使用的系统 HZ=1000
tick:系统滴答
时钟节拍
tick=1/HZ;两次系统时钟中断的时间间隔
jiffies,一个unsigned int 类型全局变量
记录自开机以产生系统时钟中断的次数
例如:HZ=1000
在时间点A去读取jiffies,发现其值为10000,问开机多长时间了?10s
jiffies会溢出吗? 会
1.内核中的延时函数
睡眠延时:
schedule_timeout(signed long timeout)
msleep
忙等待延时:内核中长时间延时建议使用睡眠延时
udelay(n),微秒延时
mdelay,毫秒延时
Linux系统非实时操作系统,以上给的延时函数都不够准确,mdelay要比msleep准确度要高些
问题:睡眠延时函数如何做到的减少功耗
2.内核定时器
是在系统时钟中断基础上发展起来了,软件意义上的定时器
核心数据结构
struct timer_list
{
/*定时器时间到*/
unsigned long expires;
/*定时时间到后要执行的动作*/
void (*function)(unsigned long);
/*当系统调用function时传递个funciton的参数值*/
unsigned long data;
。。。
}
定时器的使用
1)定义一个定时器变量
struct tiemr_list btn_timer;
2) 初始化定时器
init_timer(&btn_timer);
btn_timer.expires =
btn_timer.function =
btn_timer.data =
3) 启动定时器
void add_timer(struct timer_list *timer)/int mod_timer(struct timer_list *timer, unsigned long expires);
4)修改定时器超时时间
int mod_timer(struct timer_list *timer, unsigned long expires);
5)停止定时器
int del_timer(struct timer_list *timer);
练习:希望在安装内核模块时LED1开始闪烁 闪烁的时间间隔为1s,卸载模块时停止闪烁
案例代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <mach/platform.h>
MODULE_LICENSE("GPL");
/*定义定时器变量*/
struct timer_list led_timer;
void led_timer_func(unsigned long data)
{
gpio_set_value(PAD_GPIO_C+12,!!data);
led_timer.data = !data;
mod_timer(&led_timer,jiffies+1*HZ);
}
int __init led_drv_init(void)
{
/*申请管脚*/
gpio_request(PAD_GPIO_C+12,"lED1");
/*使用管脚*/
gpio_direction_output(PAD_GPIO_C+12,0);
/*初始化定时器*/
init_timer(&led_timer);
led_timer.function = led_timer_func;
led_timer.expires = jiffies + 1*HZ;
led_timer.data = 1;//定时时间到后,管脚要输出的电平值
/*启动定时器*/
add_timer(&led_timer);
return 0;
}
void __exit led_drv_exit(void)
{
del_timer(&led_timer);
gpio_free(PAD_GPIO_C+12);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
练习2: 能不能实现在用户空间调整LED1闪烁的时间间隔
1s
2s
3s
4s
...
模块参数
vmware + ubuntu系统中 kermit软件的使用
1)vmware 菜单: 虚拟机---》可移动设备---》串行端口2(可能不同)----》连接
2)vi /home/tarena/.kermrc
set line /dev/ttyUSB0 #改成这样报错 跳过这个步骤就没有问题了set line /dev/ttyS1
3)sudo kermit -c
4)退出kermit的方式
ctrl + \
q
扩展:dmesg 命令 重新输出缓冲区内容