当前位置:网站首页>嵌入式系统驱动初级【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
结果:

边栏推荐
猜你喜欢

花了半个月,终于把一线大厂高频面试题做成合集了

跟我学 UML 系统建模

B站回应HR称核心用户是Loser;微博回应宕机原因;Go 1.19 正式发布|极客头条

面渣逆袭:MySQL六十六问,两万字+五十图详解

【JVM】JVM调优

Minecraft HMCL 第三方启动器使用教程

Real-Time Rendering 4th related resource arrangement (no credit required)

How to monitor code cyclomatic complexity by refactoring indicators

B 站又上热搜了, HR 称「核心用户都是 Loser」

把boot和APP一起烧录进MCU
随机推荐
实践:二进制数据处理与封装
Request method ‘POST‘ not supported。 Failed to load resource: net::ERR_FAILED
gcc7.5.0编译ceres-solver报错‘is_trivially_default_constructible’ is not a member of ‘std’
JVM Tuning-GC Fundamentals and Tuning Key Analysis
寻找消失的类名
什么是APS?APS+MES如何解决生产难题?
测试开发必备技能-Jmeter二次开发
Beginner crawler notes (collecting data)
吴恩达机器学习[9]-神经网络学习
云存储硬核技术内幕——(9) 相见时难别亦难
For循环控制
【二叉树】根据描述创建二叉树
在VMD上可视化hdf5格式的分子轨迹文件
Win10 无线网卡驱动感叹号,显示错误代码56
Crawler Xiaobai Notes (yesterday's supplement to pay attention to parsing data)
线上一次JVM FullGC搞得整晚都没睡,彻底崩溃
Minecraft 服务器安装Forge 并添加Mod
JVM调优-GC基本原理和调优关键分析
云存储硬核技术内幕——(12) 皮洛士惨胜罗马军团
测试零基础如何进入大厂?一场面试教会你(附面试题解析)