当前位置:网站首页>嵌入式系统驱动初级【6】——内核定时器
嵌入式系统驱动初级【6】——内核定时器
2022-08-04 16:17:00 【imysy_22_】
一、时钟中断
硬件有一个时钟装置,该装置每隔一定时间发出一个时钟中断(称为一次时钟嘀嗒-tick),对应的中断处理程序就将全局变量jiffies_64加1
jiffies_64 是一个全局64位整型, jiffies全局变量为其低32位的全局变量,程序中一般用jiffies
HZ:可配置的宏,表示1秒钟产生的时钟中断次数,一般设为100或200
二、延时机制
1. 短延迟:忙等待
1. void ndelay(unsigned long nsecs)
2. void udelay(unsigned long usecs)
3. void mdelay(unsigned long msecs)
2. 长延迟:忙等待
使用jiffies比较宏来实现
time_after(a,b) //a > b
time_before(a,b) //a < b
//延迟100个jiffies
unsigned long delay = jiffies + 100;
while(time_before(jiffies,delay))
{
;
}
//延迟2s
unsigned long delay = jiffies + 2*HZ;
while(time_before(jiffies,delay))
{
;
}3. 睡眠延迟----阻塞类
void msleep(unsigned int msecs);
unsigned long msleep_interruptible(unsigned int msecs);
延时机制的选择原则:
1. 异常上下文中只能采用忙等待类
2. 任务上下文短延迟采用忙等待类,长延迟采用阻塞类
三、定时器
(1)定义定时器结构体
struct timer_list
{
struct list_head entry;
unsigned long expires; // 期望的时间值 jiffies + x * HZ
void (*function)(unsigned long); // 时间到达后,执行的回调函数,软中断异常上下文
unsigned long data;
};(2)初始化定时器
init_timer(struct timer_list *)(3)增加定时器 ------ 定时器开始计时
void add_timer(struct timer_list *timer);(4)删除定时器 -------定时器停止工作
int del_timer(struct timer_list * timer);(5)修改定时器
int mod_timer(struct timer_list *timer, unsigned long expires);定义struct timer_list tl类型的变量
init_timer(...);//模块入口函数
//模块入口函数或open或希望定时器开始工作的地方
tl.expires = jiffies + n * HZ //n秒
tl.function = xxx_func;
tl.data = ...;
add_timer(....);
//不想让定时器继续工作时
del_timer(....);
void xxx_func(unsigned long arg)
{
......
mod_timer(....);//如需要定时器继续隔指定时间再次调用本函数
}四、课堂练习—秒设备
Timer.c:
利用原子变量只能由一个app使用该字符设备;
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/atomic.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#define BUF_LEN 100
struct mysecond_dev {
struct cdev mydev;
struct timer_list timer;
atomic_t open_flag;
int second;
};
int major = 11;
int minor = 0;
int num = 1;
struct mysecond_dev gmydev;
void Timer_function(unsigned long arg)
{
struct mysecond_dev *pgmydev = (struct mysecond_dev *) arg;
pgmydev->second ++;
mod_timer(&gmydev.timer, jiffies + 1*HZ);
}
int myopen (struct inode *pnode, struct file *pfile)
{
struct mysecond_dev *pgmydev = NULL;
pfile->private_data = (void *)container_of(pnode->i_cdev,struct mysecond_dev,mydev);
pgmydev = (struct mysecond_dev *)pfile->private_data;
if(atomic_dec_and_test(&pgmydev->open_flag))
{
pgmydev->timer.expires = jiffies + 1*HZ;
pgmydev->timer.function = Timer_function;
pgmydev->timer.data = (unsigned long)pgmydev;
add_timer(&pgmydev->timer);
return 0;
}
else
{
atomic_inc(&pgmydev->open_flag);
printk("The device is open already\n");
return -1;
}
return 0;
}
int myclose (struct inode *pnode, struct file *pfile)
{
struct mysecond_dev *pgmydev = (struct mysecond_dev *)pfile->private_data;
atomic_set(&gmydev.open_flag,1);
del_timer(&pgmydev->timer);
return 0;
}
ssize_t myread(struct file *filp, char __user *pbuf, size_t count, loff_t *ppos)
{
struct mysecond_dev *pgmydev = (struct mysecond_dev *)filp->private_data;
int ret = 0;
if(count < sizeof(int))
{
printk("the expect read count is invalid.\n");
return -1;
}
if(count >= sizeof(int))
{
count = sizeof(int);
}
ret = copy_to_user(pbuf,&pgmydev->second,count);
if(ret)
{
printk("myread copy_to_user failed.\n");
return -1;
}
return count;
}
struct file_operations myops = {
.owner = THIS_MODULE,
.open = myopen,
.read = myread,
.release = myclose,
};
int __init atomic_init(void)
{
int ret = 0;
dev_t devno = MKDEV(major,minor);
ret = register_chrdev_region(devno,num,"mysecond");
if(ret)
{
ret = alloc_chrdev_region(&devno,minor,num,"mysecond");
if(ret)
{
printk("devno failed.\n");
return -1;
}
major = MAJOR(devno);
minor = MINOR(devno);
}
/*给mydev指定操作函数集*/
cdev_init(&gmydev.mydev,&myops);
/*将mydev添加到内核对应的数据结构里*/
gmydev.mydev.owner = THIS_MODULE;
cdev_add(&gmydev.mydev,devno,num);
atomic_set(&gmydev.open_flag,1);
init_timer(&gmydev.timer);
return 0;
}
void __exit atomic_exit(void)
{
dev_t devno = MKDEV(major,minor);
cdev_del(&gmydev.mydev);
unregister_chrdev_region(devno, num);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("imysy_22");
MODULE_DESCRIPTION("This is a script explained by the author who's name is imysy_22.");
MODULE_ALIAS("HI");
module_init(atomic_init);
module_exit(atomic_exit);
app.c 利用内核定时器打印open到read函数之间一共过了多少秒
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
if(argc < 2)
{
printf("argc is too few.\n");
return -1;
}
int fd = -1;
int sec = 0;
fd = open(argv[1],O_RDONLY);
if(fd < 0)
{
printf("open failed.\n");
return -1;
}
sleep(3);
read(fd, &sec, sizeof(sec));
printf("second = %d\n",sec);
close(fd);
fd = -1;
return 0;
}Makefile增加一行:obj-m += Timer.o
结果:

边栏推荐
猜你喜欢

Many merchants mall system function and dismantling 24 - ping the strength distribution of members

攻防视角下,初创企业安全实战经验分享

如何防止重复下单?
JVM调优-GC基本原理和调优关键分析

游戏云服务器配置怎么选合理?

成功 解决 @keyup.enter=“search()“ 在el-input 组件中不生效的问题

【Jprofile 11.0 安装】

荐书 | 《大脑的奥秘:人人要懂的脑科学》:大脑里面有什么

Minecraft 我的世界 .minecraft下的各个文件夹的用处

面了三十个人,说说真实感受
随机推荐
云存储硬核技术内幕——(11) 女子会所的秘密
吴恩达机器学习[12]-机器学习系统设计
How to monitor code cyclomatic complexity by refactoring indicators
LeetCode·每日一题·1403.非递增顺序的最小子序列·贪心
Does DMS have an interface to get the list of databases under each instance?
【二叉树】根据描述创建二叉树
PAT 甲级 A1072 Gas Station
shell中当basename和dirname无法满足你的需求时你一定要想到的命令
【Es6中的promise】
项目里的各种配置,你都了解吗?
Tomato assistant downloading tomatoes
DMS 有接口获取每个实例下的数据库列表吗
seaborn
leetcode:743. 网络延迟时间【单源最短路 + dijkstra模板】
吴恩达机器学习[9]-神经网络学习
荐书 | 《大脑的奥秘:人人要懂的脑科学》:大脑里面有什么
NFT blind box mining system dapp development NFT chain game construction
什么是APS?APS+MES如何解决生产难题?
Redis持久化操作
An article to answer what is the product library of the DevOps platform