学做网站的软件/开网店怎么开 新手无货源
文章目录
- 前言
- 通用定时器
- 系统节拍
- 节拍数与时间转换
- 基本框架
- 定时器使用
- 代码展示
- 通用定时器特点
- 高精度定时器
前言
LInux内核定时器是一种基于未来时间点的计时方式,以当前时刻来启动的时间点,以未来的某一时刻为终止点。比如,现在是10点5分,我要定时5分钟,那么定时就是10点5分+5分钟=10点10分。这个和手机闹钟很相似。比如你要定一个第二天早晨8点的闹钟,就是当前时间定时到第二天早晨8点。
通用定时器
系统节拍
在了解定时器之前,先来了解一下内核系统节拍的设置。硬件定时器提供时钟源,时钟源的频率可以设置, 设置好以后 就周期性的产生定时中断,系统使用定时中断来计时。中断周期性产生的频率就是系统频率, 也叫做节拍率(tick rate)(有的资料也叫系统频率),比如 1000Hz,100Hz 等等说的就是系统节拍 率。系统节拍率是可以设置的,单位是 Hz,我们在编译 Linux 内核的时候可以通过图形化界面 设置系统节拍率,按照如下路径打开配置界面:
-> Kernel Features -> Timer frequency ( [=y])
默认情况下选择 100Hz。设置好以后打开 Linux 内核源码根目录下的.config 文件中CONFIG_HZ会等于设置好的值,Linux 内核会使用 CONFIG_HZ 来设置自己的系统时 钟。打开文件 include/asm-generic/param.h,有如下内容:
# undef HZ
# define HZ CONFIG_HZ
# define USER_HZ 100
# define CLOCKS_PER_SEC (USER_HZ)
这里需要注意的是,并不是节拍率越高越好,高节拍率会提高系统时间精度,但是高节拍率会导致中断的产生更加频繁,频繁的中断会加剧系统的负担。
Linux 内核使用全局变量 jiffies 来记录系统从启动以来的系统节拍数,系统启动的时候会 将 jiffies 初始化为 0,jiffies 定义在文件 include/linux/jiffies.h 中,如下图所示,jiffies_64 和 jiffies 其实是同一个东西,jiffies_64 用于 64 位系统,而 jiffies 用于 32 位系统。
节拍数与时间转换
为了方便开发,Linux 内核提供了几个 jiffies 和 ms、us、ns 之间的转换函数,如表所示:
有时候我们需要在内核中实现短延时,尤其是在 Linux 驱动中。Linux 内核提供了毫秒、微 秒和纳秒延时函数:
基本框架
Linux内核使用timer_list结构体表示内核定时器,timer_list定义在文件include/linux/timer.h中,定义如下:
struct timer_list {/** All fields that change during normal runtime grouped to the* same cacheline*/struct hlist_node entry; unsigned long expires; /*定时器超时时间,单位节拍数*/void (*function)(unsigned long);/*定时处理函数*/unsigned long data;/*要传递function函数的参数*/u32 flags;
#ifdef CONFIG_TIMER_STATSint start_pid;void *start_site;char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEPstruct lockdep_map lockdep_map;
#endif
};
在上面这个结构体中,有几个参数需要重点关注一下。一个是expires到期时间,单位是节拍数。等于定时的当前的始终节拍计数(存储在系统的全局变量和jiffies)+定时时长对应的时钟节拍数量。
那么如何把时间 转换成节拍数量呢?示例:假如从现在开始定时1秒,转换成节拍数量是多少呢? 内核中有一个宏HZ,表示一秒对应的时钟节拍数,那么我们就可以通过这个宏来把时间转换成节拍数。所以,定时1秒就是expires = jiffies + 1*HZ。前面已经说明了HZ是怎么设置的。
定时器使用
- 当我们定义了一个 timer_list 变量以后一定 要先用 init_timer 初始化一下
void init_timer(struct timer_list *timer)
- add_timer 函数用于向 Linux 内核注册定时器,使用 add_timer 函数向内核注册定时器以后, 定时器就会开始运行
void add_timer(struct timer_list *timer)
- del_timer 函数用于删除一个定时器,不管定时器有没有被激活,都可以使用此函数删除。
int del_timer(struct timer_list * timer)
- del_timer_sync 函数是 del_timer 函数的同步版,会等待其他处理器使用完定时器再删除,
int del_timer_sync(struct timer_list *timer)
- mod_timer 函数用于修改定时值,如果定时器还没有激活的话,mod_timer 函数会激活定时器!
int mod_timer(struct timer_list *timer, unsigned long expires)
其中timer:要修改超时时间(定时值)的定时器。 expires:修改后的超时时间。
代码展示
下面这个代码实现了内核定时器周期性的点亮和熄灭开发板上的 LED 灯,当CMD = 3 是LED 灯的闪烁周期可以由内核定时器来设置,这里用到了ioctrl的相关知识,linux内核给用户提供了两类系统调用函数:一类是数据操作函数,比如read、write…。 另外一类函数是非数据操作函数,比如ioctl…,用户程序可以用ioctl给底层设备发送指令。 如果不是很熟悉这一块内容的话可以参考我的下一篇帖子:嵌入式驱动开发详解5(ioctl的使用)
应用层代码如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include "string.h"
#include <stdlib.h>
#include <sys/ioctl.h>#define CLOSE_CMD _IO(0XEF, 0X1) /* 关闭定时器 */
#define OPEN_CMD _IO(0XEF, 0X2) /* 打开定时器 */
#define SETPERIOD_CMD _IO(0XEF, 0X3) /* 设置定时器周期命令 */int main(int argc,char *argv[])
{int fd,ret;char *filename;unsigned int cmd;unsigned int arg;unsigned char str[100];if(argc != 2){printf("Error Usage!!!\r\n");return -1;}filename = argv[1];fd = open(filename ,O_RDWR);if(fd < 0){printf("file %s open failed!\r\n",filename);return -1;}while(1){printf("Input CMD:");ret = scanf("%d",&cmd);if(ret != 1){ /* 参数输入错误 */fgets(str,100,stdin); /* 防止卡死 */}if(cmd == 1)cmd = CLOSE_CMD;else if(cmd == 2)cmd = OPEN_CMD;else if(cmd == 3){cmd = SETPERIOD_CMD;printf("Input Timer Period:");ret = scanf("%d",&arg);if(ret != 1){fgets(str,100,stdin); }}ioctl(fd,cmd,arg);}ret = close(fd);if(ret < 0){printf("file %s close failed! \r\n",filename);return -1;}return 0;
}
内核层代码如下:
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h> //copy
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h> //淇″彿閲� 浜掞拷锟戒綋
#include <linux/timer.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>#define TIMER_CNT 1
#define TIMER_NAME "timer"
#define CLOSE_CMD _IO(0XEF, 0X1) /* 鍏抽棴瀹氭椂鍣� */
#define OPEN_CMD _IO(0XEF, 0X2) /* 鎵撳紑瀹氭椂鍣� */
#define SETPERIOD_CMD _IO(0XEF, 0X3) /* 璁剧疆瀹氭椂鍣ㄥ懆鏈熷懡浠� */ //铏界劧姝ゅ娌℃湁鍐檃rg锛屼絾鏄渶鍚庡鏋滄湁arg鍙傛暟杩樻槸鍙互浼犺繘鏉�#define LED_ON 1
#define LED_OFF 0struct timer_dev{dev_t devid; int major;int minor;struct cdev cdev;struct class *class;struct device *device;struct device_node *nd;int led_gpio;int timeperiod; struct timer_list timer; spinlock_t lock;
};struct timer_dev timerdev;static int led_init(void)
{int ret;timerdev.nd = of_find_node_by_path("/gpioled");if(timerdev.nd == NULL){printk("timerdev node cant not find!!\r\n");ret = -1;goto fail_node;}else{printk("timerdev node found!!\r\n");}timerdev.led_gpio = of_get_named_gpio(timerdev.nd,"led-gpio",0);if(timerdev.led_gpio < 0){printk("cant not get led-gpio\r\n");ret = -1;goto fail_node;}printk("led-gpio-num=%d\r\n",timerdev.led_gpio);gpio_request(timerdev.led_gpio,"led");ret = gpio_direction_output(timerdev.led_gpio,1);if(ret < 0){printk("can`t set gpio!!!\r\n");}return 0;
fail_node:return ret;}static int timer_open(struct inode *inode, struct file *file)
{int ret = 0;file->private_data = &timerdev;timerdev.timeperiod = 1000;ret = led_init();if(ret < 0){return ret;}return 0;
}static long timer_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{unsigned long flags;int timerperiod;struct timer_dev *dev = filep->private_data;switch (cmd) {case CLOSE_CMD:del_timer_sync(&dev->timer);break;case OPEN_CMD:spin_lock_irqsave(&dev->lock, flags);timerperiod = dev->timeperiod;spin_unlock_irqrestore(&dev->lock, flags);mod_timer(&dev->timer,jiffies+msecs_to_jiffies(timerperiod));break;case SETPERIOD_CMD:spin_lock_irqsave(&dev->lock, flags);dev->timeperiod = arg;spin_unlock_irqrestore(&dev->lock, flags);mod_timer(&dev->timer,jiffies+msecs_to_jiffies(dev->timeperiod));break;default:break;}return 0;
}void timer_function(unsigned long arg)
{struct timer_dev *dev = (struct timer_dev *)arg; //姝ゅ闇€瑕佹敞鎰忎紶杩涙潵鐨勬槸鍦板潃static int sta =1;int timerperiod;unsigned long flags;sta = !sta;gpio_set_value(dev->led_gpio,sta);spin_lock_irqsave(&dev->lock, flags);timerperiod = dev->timeperiod;spin_unlock_irqrestore(&dev->lock, flags);mod_timer(&dev->timer,jiffies+msecs_to_jiffies(timerperiod));
}static const struct file_operations timer_fops = {.owner = THIS_MODULE,.open = timer_open,.unlocked_ioctl = timer_unlocked_ioctl,
};static int __init timer_init(void)
{int ret;/* 鍒濆鍖栧師瀛愬彉閲� */spin_lock_init(&timerdev.lock);if(timerdev.major){timerdev.devid = MKDEV(timerdev.major,timerdev.minor);ret = register_chrdev_region(timerdev.devid, TIMER_CNT, TIMER_NAME);}else{ret = alloc_chrdev_region(&timerdev.devid,0,TIMER_CNT,TIMER_NAME);timerdev.major = MAJOR(timerdev.devid);timerdev.minor = MINOR(timerdev.devid);printk("alloc_chrdev_region major=%d minor=%d\r\n",timerdev.major, timerdev.minor);}if (ret < 0) {printk("Could not register\r\n");goto fail_devid;}timerdev.cdev.owner = THIS_MODULE;cdev_init(&timerdev.cdev, &timer_fops);ret = cdev_add(&timerdev.cdev,timerdev.devid,TIMER_CNT);if(ret < 0){printk("Could not cdev\r\n");goto fail_cdev;}timerdev.class = class_create(THIS_MODULE,TIMER_NAME);if(IS_ERR(timerdev.class)){ret = PTR_ERR(timerdev.class);goto fail_class;}timerdev.device = device_create(timerdev.class,NULL,timerdev.devid,NULL,TIMER_NAME);if(IS_ERR(timerdev.device)){ret = PTR_ERR(timerdev.device);goto fail_device;}//鍒濆鍖杢imer锛岃缃畾鏃跺櫒澶勭悊鍑芥暟锛岃繕鏈缃懆鏈燂紝鎵€浠ヤ笉浼氭縺娲诲畾鏃跺櫒init_timer(&timerdev.timer);timerdev.timer.function = timer_function;timerdev.timer.data = (unsigned long)&timerdev; //璁剧疆瑕佷紶閫掔粰 timer_function 鍑芥暟鐨勫弬鏁颁负 timerdev 鐨勫湴鍧€return 0;
fail_device:class_destroy(timerdev.class);
fail_class:cdev_del(&timerdev.cdev);
fail_cdev:unregister_chrdev_region(timerdev.devid,TIMER_CNT);
fail_devid:return ret;
}static void __exit timer_exit(void)
{gpio_set_value(timerdev.led_gpio,1);del_timer_sync(&timerdev.timer);printk("timer_exit\r\n");cdev_del(&timerdev.cdev);unregister_chrdev_region(timerdev.devid,TIMER_CNT);device_destroy(timerdev.class,timerdev.devid);class_destroy(timerdev.class);
}module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hbb");
通用定时器特点
内核定时器定时精度不高,不能作为高精度定时器使用。并且内核定时器并不是周期性运行的,超时以后就会自动关闭,因此如果想要实现周期性定时,那么就需要在定时处理函数中重新开启定时器。
高精度定时器
Linux内核提供了高精度定时器,能够实现纳秒(ns)级别的定时精度。这主要得益于内核中的hrtimer框架,它允许开发者创建和运行高精度的定时器。
关于详细的hrtimer结构体的实现可以参考下面这篇文章linux内核定时器
到这里对通用定时器大致说明就结束了,后面有新的相关的重要的内容会继续进行更新。
对代码有兴趣的同学可以查看链接https://github.com/NUAATRY/imx6ull_dev
相关文章:

嵌入式驱动开发详解4(内核定时器)
文章目录 前言通用定时器系统节拍节拍数与时间转换基本框架定时器使用代码展示通用定时器特点 高精度定时器 前言 LInux内核定时器是一种基于未来时间点的计时方式,以当前时刻来启动的时间点,以未来的某一时刻为终止点。比如,现在是10点5分&…...

Linux:信号的预备和产生
引入: 比如当前快递小哥需要通知你下来取快递(产生信号),然后通过电话或短信告知了你(发送信号),但是当前你正在打游戏,所以你并不会马上去处理,但是你会记得这件事&…...

国城杯2024——Curve
相关知识链接:https://tangcuxiaojikuai.xyz/post/187210a7.html #sagemath from Crypto.Util.number import *def add(P, Q):(x1, y1) P(x2, y2) Qx3 (x1*y2 y1*x2) * inverse(1 d*x1*x2*y1*y2, p) % py3 (y1*y2 - a*x1*x2) * inverse(1 - d*x1*x2*y1*y2, p…...

AI生成不了复杂前端页面?也许有解决方案了
在2024年,编程成为了人工智能领域最热门的赛道。AI编程技术正以惊人的速度进步,但在生成前端页面方面,AI的能力还是饱受质疑。自从ScriptEcho平台上线以来,我们收到了不少用户的反馈,他们表示:“生成的页面…...

常见矩阵分析法(BCG、GE、IE、SPACE、TOWS、优先、战略优先级、安索夫、风险矩阵):如何通过系统化方法助力战略决策与数据驱动决策
在快速变化的商业环境中,企业决策者面临着诸多复杂的选择与挑战。矩阵分析法作为战略分析的重要工具,能够系统化地分析企业的内外部环境,帮助管理层做出更加科学、合理的决策。本文将全面解析常见的矩阵分析法,并探讨它们在数据驱…...

JWT 在 SaaS 系统中的作用与分布式 SaaS 系统设计的最佳实践
在现代 SaaS(软件即服务) 系统中,随着服务规模的扩大和用户需求的多样化,如何高效、安全地进行用户身份验证、权限控制以及租户隔离,成为了系统架构中的核心问题之一。**JWT(JSON Web Token)**作…...

基于C#和Sql Server的网上书店管理系统
基于C#和Sql Server的网上书店管理系统 摘要 本系统是建立在 Windows 平台上,基于 B/S 结构的一个网上书店。通过这个网上书店,可以实 现简单的电子商务功能。 整个网站风格一致,较为美观,有完善的导航机制。普通用户从前台首页…...

特高频局放装置在现代配电设施中的应用
引言 随着电力系统的快速发展,尤其是现代配电系统的不断升和智能化,配电网的安全、稳定和运行变得愈发重要。为了确保电力系统能够及时应对各种运行问题,并提高故障诊断和监控的能力,现代配电系统中的监测技术也不断得到创新与提…...

FSC认证是什么?FSC认证费用
FSC认证是指森林管理委员会(Forest Stewardship Council)颁发的一种认证,以下是对FSC认证的详细介绍: 一、FSC认证的定义与目的 FSC认证标志着一件产品来自经过环境友好、社会有益和经济可行的可持续管理的森林。FSC是一个独立的…...

JAVA数据结构
1.数组 (Array): 固定大小的容器,用于存储相同类型的元素,数组在内存中是连续存储的,支持通过索引快 速访问元素。 int[] numbers = new int[10]; numbers[0] = 1;2.Java Collections Framework (JCF) JCF提供了一组接口和类用于管理和操作集合(如列表,集合,…...

mysql8 主从复制一直失败
问题描述: 开启同步后从服务器一直失败,报错如下: Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction ANONYMOUS at source log …...

EDA - Spring Boot构建基于事件驱动的消息系统
文章目录 概述事件驱动架构的基本概念工程结构Code创建事件和事件处理器创建事件总线创建消息通道和发送逻辑创建事件处理器消息持久化创建消息发送事件配置 Spring Boot 启动类测试运行项目 概述 在微服务架构和大规模分布式系统中,事件驱动架构(EDA&a…...

使用vue-seamless-scroll实现echarts图表大屏滚动,出现空白间隔的解决方案
一、背景介绍 最近的业务开发需求,想要实现echarts图表大屏滚动,小编首先采用vue-seamless-scroll进行实现,结果发现第二屏出现空白间隔,尝试了多种解决方案均不生效,最终选择换一个方案。 二、封装的ScrollList组件…...

ios使用UIScrollView和PageControl创建图片轮播
1.创建cocoa touch class 2.同时创建xib页面 3.SceneDelegate设置根视图控制器 // // SceneDelegate.m // iosstudy2024 // // Created by figo on 2024/8/5. //#import "SceneDelegate.h" #import "WidgetViewController.h"interface SceneDelegate …...

3D 生成重建024-LGM第一个开源的3D生成大模型!
3D 生成重建024-LGM第一个开源的3D生成大模型 文章目录 0 论文工作1 论文方法2 实验效果 0 论文工作 这篇论文介绍了一种名为LGM(大型多视角高斯模型)的新方法,用于从单视角图像或文本提示生成高分辨率的三维内容。该方法的核心思想是双重的…...

linux目录权限
一、目录权限的基本概念 Linux中的每个文件和目录都有与之关联的权限,这些权限决定了谁可以读取、写入或执行它们。权限分为三组: 所有者(Owner)权限:目录所有者的权限群组(Group)权限&#x…...

语言模型使用心得
使用像文心一言这样的语言模型,在撰写文章时确实能提供极大的帮助。然而,重要的是我们要明确主次关系:自己的创意和内容应当是文章的核心,而语言模型则扮演着一个辅助角色,帮助我们梳理思路,使文章条理更加…...

ChatGPT客户端安装教程(附下载链接)
用惯了各类AI的我们发现每天打开网页还挺不习惯和麻烦,突然发现客户端上架了,懂摸鱼的人都知道这里面的道行有多深,话不多说,开整! 以下是ChatGPT客户端的详细安装教程,适用于Windows和Mac系统:…...

Electron 基础+传值+引用+安全
文章目录 概要elctron 生命周期及窗口应用主进程与渲染进程交互技术细节electron 中需要注意的安全问题 概要 一、Electron简介 Electron是一个开源框架,它允许开发者使用JavaScript、HTML和CSS构建跨平台的桌面应用程序。它基于Chromium(谷歌浏览器的…...

手机租赁系统全面解析与开发指南
内容概要 手机租赁系统已经成为现代商业中不可或缺的一部分,尤其是在智能手机普及的时代。随着消费者对新机型兴趣的不断增加,大家纷纷走上了“试一试再买”的道路,手机租赁这条路因此越走越宽。这部分的市场需求让创业者们看到了机会。不仅…...

mongoDb的读session和写session权限报错问题
go在使用mongoDb时用到了全局会话,发现在创建的session的逻辑相同,首先会进行数据的查询,此时获取了全局session执行读操作,查询所有文档,则当前会话为读会话,当再去插入时发现会报错,此时sessi…...

Centos在2024年6月30日停止维护后如何换yum源安装组件
现象: 在centos7里使用yum安装报错: Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http://mirrorlist.centos.org/?release7&archx86_64&repoos&infrastock error was 14: curl#6 - “Could not resolve…...

阿里云ACP云计算模拟试题(附答案解析)
1、将基础设施作为服务的云计算服务类型是_____服务。 A.laas B.Paas C.SaaS D.Daas 答案:A 解析:基础设施即服务有时缩写为 IaaS,包含云 IT 的基本构建块,通常提供对联网功能、计算机(虚拟或专用硬件&#x…...

简单的爬虫脚本编写
一、数据来源分析 想爬取一个网站的数据,我们首先要进行数据分析。通过浏览器F12开发者工具栏进行抓包,可以分析我们想要的数据来源。 通过关键字搜索,可以找到相对应的数据包 二、爬虫实现 需要用到的模块为:request…...

[MySQL基础](三)SQL--图形化界面+DML
本专栏内容为:MySQL学习专栏 💓博主csdn个人主页:小小unicorn ⏩专栏分类:MySql 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 目录 图…...

11.23[大数据]
PRO1:LSTM模型预测输出都是同一个值? 画出来的图像就是一条横线 这个搜了搜,原因可能有很多,但感觉最主要的原因极可能是激活函数选择不当,以及层的搭建不合适 原模型是 REF https://zhuanlan.zhihu.com/p/654325094 https:/…...

C++ 游戏开发进阶:打造更精彩的游戏世界
在之前的 C 游戏开发入门教程中,我们已经了解了游戏开发的基本概念和一些简单的实现方法。现在,让我们进一步深入探讨 C 游戏开发中的进阶技术,为玩家打造更精彩、更具沉浸感的游戏体验。 一、游戏物理引擎的集成 物理引擎是现代游戏开发中…...

想在iPad上远程操作安卓手机的APP,怎样实现iPad远程控制安卓?
学生党或互联网行业的打工人,人手连三台电子设备也很常见,手机、平板还有笔记本电脑一大堆,如果出门要全带上,背包压力也变大。 有没有想过用远程控制功能,让iPad远程控制安卓手机?这样做,出门就…...

GPS北斗卫星授时服务器功能是什么?应用是什么?
GPS北斗卫星授时服务器功能是什么?应用是什么? GPS北斗卫星授时服务器功能是什么?应用是什么? 摘 要:首先对计算机网络时间同步相关技术进行了介绍,然后阐述了时间同步技术在现代计算机网络中的应用与发展,最后指出时间同步网络…...

利用Java爬虫获取商品数据的完整指南
在当今数字化时代,数据已成为企业和个人决策的关键资源。特别是在电商领域,获取商品数据对于市场分析、价格监控和竞争对手分析至关重要。Java作为一种强大且广泛使用的编程语言,非常适合开发复杂的爬虫系统。本文将详细介绍如何利用Java编写…...