RTT(RT-Thread)时钟管理

目录

时钟管理

时钟节拍

RTT工程目录结构介绍 

配置文件:rtconfig.h

获取系统节拍

获取系统节拍数函数

实例

定时器

RT_Thread定时器介绍

定时器源码分析(了解即可)

 rt_system_timer_init (硬件定时器初始化)

rt_system_timer_thread_init(软件定时器初始化)

总结

定时器工作机制

定时器相关接口

启动和停止定时器

动态创建定时器

创建定时器

删除定时器

实例

静态创建定时器

初始化定时器

脱离定时器

实例

控制定时器

实例

高精度延时


时钟管理

操作系统需要通过时间来规范其任务,本章主要介绍时钟节拍基于时钟节拍的定时器

时钟节拍

        任何操作系统都需要提供一个时钟节拍,以供系统处理所有和时间有关的事件,如线程的延时、线程的时间片轮转调度以及定时器超时等。

        RT-Thread 中,时钟节拍的长度可以根据 RT_TICK_PER_SECOND 的定义来调整。 rtconfig.h配置文件中定义:

/* *频率是1000HZ 周期是1/1000 s*所以节拍是1ms*/
#define RT_TICK_PER_SECOND 1000

RTT工程目录结构介绍 

配置文件:rtconfig.h

其中包括了内核相关的配置、内部线程通信配置、内存管理、内核设备对象、RTT组件、C++特性、设备驱动和USB配置等等

时钟节拍配置属于内核相关配置,默认配置为1000,表示1000Hz,一次节拍为1ms

系统滴答定时器中断处理函数(每1ms触发一次systick定时器中断):每一次发生中断都会进入中断处理函数

我们可以通过启动文件的中断向量表中进入

void SysTick_Handler(void)
{/* enter interrupt */rt_interrupt_enter();HAL_IncTick();rt_tick_increase();// ++ rt_tick:全局变量自加,//记录的是系统从启动到现在的时间节拍数/* leave interrupt */rt_interrupt_leave();
}

获取系统节拍

获取系统节拍数函数

/*** This function will return current tick fromoperating system startup** @return current tick*/
rt_tick_t rt_tick_get(void)

实例

通过获取系统节拍数来验证时钟节拍1ms一次

... ...
int main(void)
{int i=0;rt_tick_t tick=0;for(i=0;i<10;i++){tick = rt_tick_get();rt_kprintf("tick:%u\n",tick);rt_thread_mdelay(500);}return RT_EOK;
}

运行结果:

通过结果可以验证时钟节拍确实为1ms一次

如果我们将频率改为10000Hz,即100ms一个节拍

修改会导致程序出现警告:division by zero 除数是0

但并不影响运行结果

定时器

        定时器,是指从指定的时刻开始,经过一定的指定时间后触发一个事件,定时器有硬件定时器软件定时器之分:

        硬件定时器: 芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。如果用硬件定时器,触发中断以后进行的处理中断函数属于中断上下文。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。

        软件定时器: 由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受数目限制的定时器服务。软件定时器触发的中断回调函数属于线程上下文。

        RT-Thread操作系统提供软件实现的定时器,以时钟节拍(OS Tick)的时间长度为单位,即定时数值必须是OS Tick的整数倍

RT_Thread定时器介绍

RT-Thread 的定时器提供两类定时器机制:

  • 第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动停止。
  • 第二类是周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动的停止,否则将永远持续执行下去

        根据定时器超时函数执行时所处的上下文环境,RT-Thread的定时器可以分为HARD_TIMER模式和SOFT_TIMER模式。

        HARD_TIMER模式:中断上下文

        定时器超时函数的要求:执行时间应该尽量短(减少对正常执行程序的影响),执行时不应导致当前上下文挂起、等待。例如在中断上下文中执行的超时函数它不应该试图去申请动态内存、释放动态内存等

        SOFT_TIMER模式:线程上下文

        该模式被启用后,系统会在初始化时创建一个 timer 线程,然后 SOFT_TIMER 模式的定时器超时函数在都会在timer线程的上下文环境中执行

定时器源码分析(了解即可)

(1) RT-Thread OS启动阶段,执行rtthread_startup函数,在该函数中调用了定时器初始化函数

/* timer system initialization */
rt_system_timer_init();/* timer thread initialization */
rt_system_timer_thread_init();

 

 

 rt_system_timer_init (硬件定时器初始化)

/*** @ingroup SystemInit** This function will initialize system timer*/
void rt_system_timer_init(void)
{int i;for (i = 0; i < sizeof(rt_timer_list) / sizeof(rt_timer_list[0]); i++){rt_list_init(rt_timer_list + i);}
}

转到rt_list_init()函数定义处,可以发现在RTT中,内核是通过双向列表的方式来管理定时器的

再转到链表定义处,我们可知rt_system_timer_init初始化的是硬件定时器的列表

rt_system_timer_thread_init(软件定时器初始化)

/*** @ingroup SystemInit** This function will initialize system timer thread*/
void rt_system_timer_thread_init(void)
{
#ifdef RT_USING_TIMER_SOFTint i;for (i = 0;i < sizeof(rt_soft_timer_list) / sizeof(rt_soft_timer_list[0]);i++){rt_list_init(rt_soft_timer_list + i);}/* start software timer thread */rt_thread_init(&timer_thread,"timer",rt_thread_timer_entry,RT_NULL,&timer_thread_stack[0],sizeof(timer_thread_stack),RT_TIMER_THREAD_PRIO,10);/* startup */rt_thread_startup(&timer_thread);
#endif
}

从开始的rt_list_init(rt_soft_timer_list + i);中我们可知软件定时器初始化还是先初始化了一个定时器列表,不过传参传的是软件定时器的列表

转到定义处

然后初静态创建定时器并启动

启动完成后会执行线程处理函数rt_thread_timer_entry();

在while(1)中,做了一个超时检测,如果超时则表示软件定时器不存在,则将软件定时器线程挂起,让CPU调度其它线程。否则执行定时器的正常功能。

/* system timer thread entry */
static void rt_thread_timer_entry(void *parameter)
{rt_tick_t next_timeout;while (1){/* get the next timeout tick */next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list);if (next_timeout == RT_TICK_MAX){/* no software timer exist, suspend self. */rt_thread_suspend(rt_thread_self());rt_schedule();}else{rt_tick_t current_tick;/* get current tick */current_tick = rt_tick_get();if ((next_timeout - current_tick) < RT_TICK_MAX / 2){/* get the delta timeout tick */next_timeout = next_timeout - current_tick;rt_thread_delay(next_timeout);}}/* check software timer */rt_soft_timer_check();}
}

总结

内核在管理定时器的时候,将定时器分为了两类,一类是硬件定时器,一类是软件定时器,分别挂在不同的列表上进行管理。

定时器工作机制

        下面以一个例子来说明 RT-Thread 定时器的工作机制。在 RT-Thread 定时器模块中维护着两个重要的全局变量:

  • 当前系统经过的 tick 时间 rt_tick(当硬件定时器中断来临时,它将加 1) ;
  • 定时器链表 rt_timer_list。系统新创建并激活的定时器都会按照以超时时间排序的方式插入到rt_timer_list 链表中。

        如下图所示,系统当前tick值为20,在当前系统中已经创建并启动了三个定时器,分别是定时时间为50个tick的Timer1、100个tick的Timer2和500个tick的Timer3,这三个定时器分别加上系统

        当前时间 rt_tick=20,从小到大排序链接在 rt_timer_list 链表中,形成如图所示的定时器链表结构。

        而 rt_tick 随着硬件定时器的触发一直在增长(每一次硬件定时器中断来临,rt_tick 变量会加 1) ,50个tick以后,rt_tick从20增长到70,与Timer1的timeout值相等,这时会触发与Timer1定时器相关联的超时函数,同时将Timer1从rt_timer_list链表上删除。同理,100个tick和500个tick过去后,与Timer2 和 Timer3 定时器相关联的超时函数会被触发,接着将 Time2 和 Timer3 定时器从 rt_timer_list链表中删除。

        如果系统当前定时器状态在 10 个 tick 以后(rt_tick=30)有一个任务新创建了一个 tick 值为 300 的Timer4定时器,由于Timer4定时器的timeout=rt_tick+300=330,因此它将被插入到Timer2和Timer3定时器中间,形成如下图所示链表结构:

定时器相关接口

启动和停止定时器

/*** This function will start the timer** @param timer the timer to be started** @return the operation status, RT_EOK on OK,-RT_ERROR on error*/rt_err_t rt_timer_start(rt_timer_t timer)

若想使它停止,可以使用下面的函数接口:

/*** This function will stop the timer** @param timer the timer to be stopped** @return the operation status, RT_EOK on OK,-RT_ERROR on error*/rt_err_t rt_timer_stop(rt_timer_t timer)

动态创建定时器

动态创建一个定时器和删除定时器

创建定时器

其中参数2:指向定时超时的回调函数(定时器中断函数),来处理当前的超时事件

参数3:为传递给超时函数的参数

参数4:为定时器时间,单位为节拍数

/*** This function will create a timer** @param name the name of timer* @param timeout the timeout function* @param parameter the parameter of timeoutfunction* @param time the tick of timer* @param flag the flag of timer* #define RT_TIMER_FLAG_ONE_SHOT         0x0             /**< one shot timer */
* #define RT_TIMER_FLAG_PERIODIC           0x2            /**< periodic timer */
* #define RT_TIMER_FLAG_HARD_TIMER      0x0             /**< hard timer,the timer's callbackfunction will be called in tick isr. */
* #define RT_TIMER_FLAG_SOFT_TIMER       0x4           /**< soft timer,the timer's callback function will be called in timerthread. */
* @return the created timer object
*/
rt_timer_t rt_timer_create(const char*name,void (*timeout)(void*parameter),void       *parameter,rt_tick_t   time,rt_uint8_t  flag)

其中flag可以传入以下标志

RT_TIMER_FLAG_ONE_SHOT表示单次触发

RT_TIMER_FLAG_PERIODIC表示周期性的触发

返回值为一个结构体指针

结构体描述当前定时器的信息

删除定时器

传入参数为定时器的结构体指针,返回值为错误码:正确为RT_EOK,错误为负的RT_ERROR

/*** This function will delete a timer andrelease timer memory** @param timer the timer to be deleted** @return the operation status, RT_EOK on OK;-RT_ERROR on error*/
rt_err_t rt_timer_delete(rt_timer_t timer)
实例

首先对动态创建定时器函数进行参数配置,其中标志使用了周期性触发和使用软件定时器。然后定义中断函数,创建一个定时器结构体指针来接收返回值,如果创建失败就返回-没有内存

运行效果

其中timer里面显示了四个定时器,包括了自己创建的tm_demo,处于deactivated未活动的状态,其它三个定时器为系统创建的tshell、tidle0和timer

完善超时处理函数的内容,3s打印一次数据;启动定时器

运行效果

可以发现定时器状态已经开启

静态创建定时器

初始化定时器
/*** This function will initialize a timer,normally this function is used to* initialize a static timer object.** @param timer the static timer object  (typedef struct rt_timer *rt_timer_t;)* @param name the name of timer* @param timeout the timeout function* @param parameter the parameter of timeoutfunction* @param time the tick of timer* @param flag the flag of timer*/
void rt_timer_init(rt_timer_t  timer,const char *name,void (*timeout)(void*parameter),void       *parameter,rt_tick_t   time,rt_uint8_t  flag)
脱离定时器

静态定时器不需要再使用时,可以使用下面的函数接口脱离定时器:

/*** This function will detach a timer from timermanagement.** @param timer the static timer object** @return the operation status, RT_EOK on OK;RT_ERROR on error*/
rt_err_t rt_timer_detach(rt_timer_ttimer)
实例

运行结果

当前时间节拍数

控制定时器
/*** This function will get or set some optionsof the timer** @param timer the timer to be get or set* @param cmd the control command* @param arg the argument* #define RT_TIMER_CTRL_SET_TIME          0x0            /**< set timer control command*/* #define RT_TIMER_CTRL_GET_TIME          0x1            /**< get timer control command*/* #define RT_TIMER_CTRL_SET_ONESHOT       0x2            /**< change timer to one shot */
* #defineRT_TIMER_CTRL_SET_PERIODIC        0x3            /**< change timer to periodic*/
* @return RT_EOK
*/
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
实例

以重新设置定时器时间为例,15s中后修改定时节拍数为1000

 

高精度延时

注意:这个函数只支持低于1个OS Tick(系统节拍)的延时, 否则SysTick会出现溢出而不能够获得指定的延时时间

一般用于IIC、SPI等总线通信

/*** This function will delay for some us.** @param us the delay time of us*/
void rt_hw_us_delay(rt_uint32_t us)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24148.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安全防护,保障企业图文档安全的有效方法

随着企业现在数据量的不断增加和数据泄露事件的频发&#xff0c;图文档的安全性成为了企业必须高度关注的问题。传统的纸质文件存储方式已不适应现代企业的需求&#xff0c;而在线图文档管理成为了更加安全可靠的数字化解决方案。那么在在线图文档管理中&#xff0c;如何采取有…

RW-Everything的RwDrv.sys驱动调用

RW-Everything的RwDrv.sys驱动调用 一、RwDrv.sys二、示例代码三、总结 一、RwDrv.sys RW-Everything是一个硬件底层的工具&#xff0c;可用于物理内存、BIOS、PCI和IO端口的查看和修改&#xff0c;其基于驱动RwDrv.sys来实现&#xff0c;利用这个驱动可以实现系统的侵入。 二…

Windows测试模式打开/关闭 C++ Windows驱动开发

Windows测试模式打开 管理员身份运行CMD 2.输入&#xff1a;bcdedit /set testsigning on 重启计算机 右下角显示&#xff1a; 测试模式成功开启 Windows测试模式关闭 同理&#xff0c;第二步修改为&#xff1a; 重启后右下角&#xff1a; 没有测试模式显示&#xff0c;关闭…

图像处理学习笔记

图像处理的流程&#xff1a;获取图像-分割区域-特征提取。 嵌入式工业读码器 &#xff1a;包括DM码、QR码、vericode码 Blob分析与形态学 1.Blob区域是Blobs这一数据类型在halcon中的一种贴切的表达形式。 采集图像-区域分割&#xff0c;最后通过特征&#xff08;如圆度、面积、…

类与对象【中】

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析2 目录 &#x1f449;&#x1f3fb;类的默认6个成员函数&#x1f449;&#x1f3fb;构造…

代码编辑器实践之vue-codemirror使用

前言 程序员用到IDE次数比较频繁&#xff0c;比如vscode、idea等&#xff0c;这些都是市场上比较流行的代码编辑器&#xff0c;拥有非常全面的功能。但是有时候在项目开发上也会用到代码编辑器&#xff0c;比如复杂的Array<Object>输入&#xff0c;或者需要用到用户交互…

1、Thonny+MicroPython+ESP32开发环境搭建

1. 整体流程说明 1.1 ESP32 大白话来说:ESP32就是一个开发板,上面有芯片以及用到的其它硬件 1.2 ESP32运行程序? 只要是硬件电路(数字电路)那么就可以通过编程的方式对其进行控制 那么这个开发板能认识什么样的程序呢?python?C?C++?Java?。。。。 答:只认识二…

【linux--->数据链路层协议】

文章目录 [TOC](文章目录) 一、数据链路层协议概念二、以太网帧格式1.字段分析 三、局域网通信原理四、ARP协议1.结构2.作用3.ARP通信过程4.ARP协议相关命令 五、局域网内中间人原理六、DNS系统(域名系统)1.域名概念2.DNS系统组成3.DNS协议3.浏览器输入域名后的通信过程4.dig工…

Linux 创建子进程

文章目录 前言一、进程&#xff0c;线程&#xff0c;程序 区分二、创建子进程三、创建多个进程1. 获取进程号2. 循环创建多个进程 四、进程工具。1. ps 查看当前进程.2. kill 进程终止. 总结 前言 在计算机科学中&#xff0c;进程&#xff08;Process&#xff09;、线程&#…

ChatGPT已打破图灵测试,新的测试方法在路上

生信麻瓜的 ChatGPT 4.0 初体验 偷个懒&#xff0c;用ChatGPT 帮我写段生物信息代码 代码看不懂&#xff1f;ChatGPT 帮你解释&#xff0c;详细到爆&#xff01; 如果 ChatGPT 给出的的代码不太完善&#xff0c;如何请他一步步改好&#xff1f; 全球最佳的人工智能系统可以通过…

删除这4个文件夹,流畅使用手机无忧

在现代社会中&#xff0c;手机已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着使用时间的增长&#xff0c;我们可能会遇到手机卡顿和内存不足的问题&#xff0c;让我们感到十分困扰。手机卡顿不仅影响使用体验&#xff0c;还可能导致应用程序运行缓慢&#xff0c;甚…

flex 布局使用 space-between 时将最后一行左对齐

1.使用占位元素 特点&#xff1a;适用于任意列数布局&#xff0c;比较简单&#xff0c;缺点是会产生空标签 方法&#xff1a;使用循环体循环一整行空元素。宽度为单个元素宽度&#xff0c;高度为0 <div class"flex-box"><div class"item-box" v…

HTML <ruby> 标签

实例 一个 ruby 注释&#xff1a; <ruby> 漢 <rt><rp>(</rp>ㄏㄢˋ<rp>)</rp></rt> </ruby>定义和用法 <ruby> 标签定义 ruby 注释&#xff08;中文注音或字符&#xff09;。 在东亚使用&#xff0c;显示的是东亚字…

AutoSAR系列讲解(实践篇)12.2-CanTP

目录 CanTP 一、主要作用 二、诊断传输流程 CanTP CanTP说起来其实重要也不重要,其本身是设计可以用于CAN的很多传输协议,但是目前基本上也就咱们做诊断的时候用用,不过虽然简单,我们也 讲讲 一、主要作用 CanTp是位于PduR和CanIf之间的一个模块,主要提供以下服务:…

论文阅读-Neighbor Contrastive Learning on Learnable Graph Augmentation(AAAI2023)

人为设计的图增强&#xff0c;可能会破坏原始图的拓扑结构&#xff0c;同时相邻节点被视为负节点&#xff0c;因此被推离锚点很远。然而&#xff0c;这与网络的同质性假设是矛盾的&#xff0c;即连接的节点通常属于同一类&#xff0c;并且应该彼此接近。本文提出了一种端到端的…

python绿色版运行程序,python 绿色版免安装

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python绿色版运行程序&#xff0c;python 绿色版免安装&#xff0c;今天让我们一起来看看吧&#xff01; 软件简介 Python3.7.0 是一种被广大从业者广泛使用的通用型设计语言。该软件提供了丰富全面的模块&#xff0c;并…

MFC第二十七天 通过动态链表实现游戏角色动态增加、WM_ERASEBKGND背景刷新的原理、RegisterClass注册窗口与框架程序开发

文章目录 通过动态链表实现游戏角色动态增加CMemoryDC.hCFlashDlg.hCFlashDlg.cpp WM_ERASEBKGND背景刷新的原理RegisterClass注册窗口与框架程序开发CFrameRegister 通过动态链表实现游戏角色动态增加 CMemoryDC.h #pragma once#include "resource.h"/*内存DC类简介…

Grafana-部署

一、部署 1.1 Linux 方式 Centos 系统 yum install https://dl.grafana.com/enterprise/release/grafana-enterprise-10.0.3-1.x86_64.rpm二、配置 Grafana 具有默认和自定义配置文件。您可以通过修改自定义配置文件或使用环境变量来自定义 Grafana 实例。要查看 Grafana 实…

【设计模式|中】结构型模式

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 【设计模式|上】【创建型】 【设计模式 | 中】【结构型】 适配器模式代理模式装饰器模式桥接模式组合模式外观模式享元模式 【设计模式 | 下】【行为型…

6.s081/6.1810(Fall 2022)Lab3: page tables

文章目录 前言其他篇章参考链接0. 前置环境1. Speed up system calls (easy)1.1 简单分析1.2 映射1.3 页分配1.4 页释放1.5 测试 2. Print a page table (easy)2.1 简单分析2.2 实现2.3 测试 3. Detect which pages have been accessed (hard)3.1 简单分析3.2 实现3.2.1 获取参…