lv14 内核定时器 11

这篇具有很好参考价值的文章主要介绍了lv14 内核定时器 11。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、时钟中断

硬件有一个时钟装置,该装置每隔一定时间发出一个时钟中断(称为一次时钟嘀嗒-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
    ​
    //返回值为布尔类型。例如 time_after(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;      //传给回调函数的实参,常转换为地址来使用
};

其中list_head是链表,内核中通过链表管理很多个定时器,每个定时器都有一个超时值。硬件时钟每经过一个时间,都会进行一个计数,同时触发一个软中断,在软中断服务程序中(异常上下文,不能调用任何可能引起阻塞的函数),会进来查看定时器是否超时了,通过现在的tick值与超时tick值进行比较,如果超时了会触发回调函数,其中data用来给回调函数传实参。

(2)初始化定时器

init_timer(struct timer_list *)

(3)增加定时器 ------ 定时器开始计时

void add_timer(struct timer_list *timer);

加入到链表,定时器才开始工作

(4)删除定时器 -------定时器停止工作

int del_timer(struct timer_list * timer);

(5)修改定时器

一般如果想实现每隔x秒钟设置一个闹钟,需要把这个函数放在回调函数的最后。

 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(....);//如需要定时器继续隔指定时间再次调用本函数
}

四、课堂练习—秒设备

目标:在应用程序测试读取字符设备时打印秒计数值

second.c,中断定时器不能被多个应用打开,所以使用原子来防止被重复打开

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>


int major = 11;
int minor = 0;
int mysecond_num  = 1;

struct mysecond_dev
{
	struct cdev mydev;

	atomic_t openflag;//1 can open, 0 can not open

	struct timer_list timer;
	int second;
	
};

struct mysecond_dev gmydev;

void timer_func(unsigned long arg)
{
	struct mysecond_dev * pmydev = (struct mysecond_dev *)arg;
	pmydev->second++;
	mod_timer(&pmydev->timer, jiffies + 1 * HZ);

}

int mysecond_open(struct inode *pnode,struct file *pfile)
{
	struct mysecond_dev *pmydev = NULL;

	pfile->private_data =(void *) (container_of(pnode->i_cdev,struct mysecond_dev,mydev));
	
	pmydev = (struct mysecond_dev *)pfile->private_data;

	//运算后结果为0则返回真,否则返回假表示设备已经被打开
	if(atomic_dec_and_test(&pmydev->openflag))
	{
		pmydev->timer.expires = jiffies + 1 * HZ;
		pmydev->timer.function = timer_func;
		pmydev->timer.data = (unsigned long)pmydev;
		add_timer(&pmydev->timer);

		return 0;
	}
	else
	{
		atomic_inc(&pmydev->openflag);
		printk("The device is opened already\n");
		return -1;
	}
}

int mysecond_close(struct inode *pnode,struct file *pfile)
{
	struct mysecond_dev *pmydev = (struct mysecond_dev *)pfile->private_data;

	del_timer(&pmydev->timer);
	atomic_set(&pmydev->openflag,1);

	return 0;
}

int mysecond_read(struct file *pfile,char __user *puser, size_t size, loff_t *p_pos)
{
	struct mysecond_dev *pmydev = (struct mysecond_dev *)pfile->private_data;
	int ret = 0;

	if(size < sizeof(int))
	{
		printk("the expect read size is invalid\n");
		return -1;
	}
	if(size >= sizeof(int))
	{
		size= sizeof(int);
	}

	ret = copy_to_user(puser, &pmydev->second, size);
	if(ret)
	{
		printk("copy to user failed\n");
		return -1;
	}

	return 0;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = mysecond_open,
	.release = mysecond_close,
	.read = mysecond_read,
};

int __init mysecond_init(void)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);

	/*申请设备号*/
	ret = register_chrdev_region(devno,mysecond_num,"mysecond");
	if(ret)
	{
		ret = alloc_chrdev_region(&devno,minor,mysecond_num,"mysecond");
		if(ret)
		{
			printk("get devno failed\n");
			return -1;
		}
		major = MAJOR(devno);//容易遗漏,注意
	}

	/*给struct cdev对象指定操作函数集*/	
	cdev_init(&gmydev.mydev,&myops);

	/*将struct cdev对象添加到内核对应的数据结构里*/
	gmydev.mydev.owner = THIS_MODULE;
	cdev_add(&gmydev.mydev,devno,mysecond_num);

	//初始化置位1
	atomic_set(&gmydev.openflag,1);

	//初始化定时器
	init_timer(&gmydev.timer);

;	return 0;
}

void __exit mysecond_exit(void)
{
	dev_t devno = MKDEV(major,minor);

	cdev_del(&gmydev.mydev);

	unregister_chrdev_region(devno,mysecond_num);
}


MODULE_LICENSE("GPL");

module_init(mysecond_init);
module_exit(mysecond_exit);

Makefile

ifeq ($(KERNELRELEASE),)

ifeq ($(ARCH),arm)
KERNELDIR ?= /home/linux/Linux_4412/kernel/linux-3.14
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)


modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_install

clean:
	rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versions

else

CONFIG_MODULE_SIG=n
obj-m += mychar.o
obj-m += mychar_poll.o
obj-m += openonce_atomic.o
obj-m += openonce_spinlock.o
obj-m += mychar_sema.o
obj-m += mychar_mutex.o
obj-m += second.o

endif

testsecond_app.c

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char * argv[])
{
	int fd = -1;
	int sec;

	if(argc < 2)
	{
		printf("The argument is too few\n");
		return -1;
	}

    //打开字符驱动时,即会启动定时器
	fd = open(argv[1],O_RDONLY);
	if(fd < 0)
	{
		printf("open %s failed \n", argv[1]);
		return 2;
	}

    //延迟
	sleep(3);

	read(fd, &sec, sizeof(sec));
	printf("The second is %d\n",sec);

	close(fd);
	fd = -1;
	return 0;
	
}

编译测试效果

lv14 内核定时器 11,嵌入式开发,linux,arm开发文章来源地址https://www.toymoban.com/news/detail-813495.html

到了这里,关于lv14 内核定时器 11的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【嵌入式】HC32F定时器PWM捕获+APC芯片实现模拟AD采样

    目录 一 项目背景 二 原理说明 三 设计实现——定时器初始化 四 设计实现——PWM捕获 五 梳理总结         目前使用了TI的ADC采样芯片 ADS1018实现模拟量4-20mA/0-20mA的采样 ,原理是 将外部输入的模拟量信号4-20mA,经由并联的两个100Ω电阻,转换为0.2-1V的电压信号传递到模数转

    2023年04月24日
    浏览(47)
  • 【蓝桥杯嵌入式】定时器实现按键单击,双击,消抖以及长按的代码实现

    🎊【蓝桥杯嵌入式】专题正在持续更新中,原理图解析✨,各模块分析✨以及历年真题讲解✨都在这儿哦,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -  蓝桥杯嵌入式_勾栏听曲_0的博客 🍻欢迎大家  🏹  点赞👍  评论📨  收藏⭐️ 📌个人主

    2024年01月17日
    浏览(45)
  • 嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第二天-ARM中断、定时器、看门狗(物联技术666)

    链接:https://pan.baidu.com/s/1E4x2TX_9SYhxM9sWfnehMg?pwd=1688 提取码:1688 上午:中断           吕峰老师 下午:定时器 教学内容: 一、中断 ARM 中断分为二级,分为一级中断和二级中断,二级中断为子中断,对于 ARM 来说有 50 个中断源, 其中有 32+ ( EINT23-4 ) 23-4+1-2=50 子中断源

    2024年02月19日
    浏览(57)
  • 【小黑嵌入式系统第十五课】μC/OS-III程序设计基础(四)——消息队列(工作方式&数据通信&生产者消费者模型)、动态内存管理、定时器管理

    上一课: 【小黑嵌入式系统第十四课】μC/OS-III程序设计基础(三)——信号量(任务同步资源同步)、事件标记组(与或多个任务) 下一课: 【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣

    2024年01月17日
    浏览(47)
  • Linux 内核定时器

    一、相关知识点 (一)知识点 1、内核定时器分类     1)标准定时器或系统定时器     2)高精度定时器(HRT)         头文件:#include linux/hrtimer.h 2、检查系统是否可用HRT     1)查看内核配置文件              2)查看机器         cat proc/timer_list  | grep \\\"resolution\\\" 

    2024年02月11日
    浏览(39)
  • 09_Linux内核定时器

    目录 Linux时间管理和内核定时器简介 内核定时器简介 Linux内核短延时函数 定时器驱动程序编写 编写测试APP 运行测试          学习过UCOS或FreeRTOS的同学应该知道, UCOS或FreeRTOS是需要一个硬件定时器提供系统时钟, 一般使用Systick作为系统时钟源。同理 , Linux要运行 , 也是需

    2024年02月13日
    浏览(39)
  • 【STM32】STM32学习笔记-定时器定时中断 定时器外部时钟(14)

    1.1 TIM_InternalClockConfig 1.2 TIM_TimeBaseInit 1.3 TIM_TimeBaseInitTypeDef 1.4 TIM_ClearFlag 1.5 TIM_ITConfig 1.6 TIM_Cmd 1.7 中断服务函数 参考程序 1.8 TIM_ETRClockMode2Config timer.h timer.c main.c timer.h timer.c main.c 09-定时器定时中断.rar 10-定时器外部时钟.rar 参考: 【STM32】江科大STM32学习笔记汇总

    2024年02月03日
    浏览(51)
  • Linux内核 -高精度定时器

    高精度定时器使用示例

    2024年01月19日
    浏览(50)
  • 14、计时器、定时器设计与应用

    掌握同步四位二进制计数器 74LS161 的工作原理和设计方法 掌握时钟/定时器的工作原理与设计方法 任务 1:采用行为描述设计同步四位二进制计数器 74LS161 任务 2:基于 74LS161 设计时钟应用 1.创建工程并创建 Verilog 文件 建立 HDL 类型的工程 My74LS161,创建 Verilog 文件 My74LS161,

    2024年02月03日
    浏览(52)
  • Linux 内核定时器(高级字符设备五)

      在 Linux 内核中很多函数是基于定时器进行驱动的,但是内核定时器的精度并不高,所以不能作为高精度定时器使用。并且内核定时器的运行没有周期性,到达计时终点后会自动关闭。如果要实现周期性定时,就要在定时处理函数中重新开启定时器。   Linux 内核中使用

    2024年02月08日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包